From de7b3a66f9c69daa4ddde366b55d8150e0d8d336 Mon Sep 17 00:00:00 2001 From: BIG2EYEZ Date: Wed, 3 Jan 2024 16:33:31 +0800 Subject: [PATCH] protect with xss for login --- Sean/server.js | 112 ++++++++++++++++++++++++------------------- Sean/views/login.ejs | 6 --- package-lock.json | 26 +++++----- package.json | 1 + 4 files changed, 77 insertions(+), 68 deletions(-) diff --git a/Sean/server.js b/Sean/server.js index 83bda9f..a0ca3c4 100644 --- a/Sean/server.js +++ b/Sean/server.js @@ -6,7 +6,7 @@ const bcrypt = require("bcrypt"); const crypto = require("crypto"); const nodemailer = require("nodemailer"); const otpGenerator = require('otp-generator'); - +const { body, validationResult } = require('express-validator'); const { transporter } = require("./modules/nodeMailer"); const { connection } = require("./modules/mysql"); @@ -20,7 +20,7 @@ require("dotenv").config(); app.use(bodyParser.urlencoded({ extended: true })); app.use( session({ - secret: "your_session_secret", + secret: process.env.key, resave: false, saveUninitialized: true, }) @@ -100,67 +100,79 @@ const logActivity = async (username, success, message) => { // Login route - app.post("/login", async (req, res) => { - try { - let { username, password } = req.body; - username = username.trim(); + app.post('/login',[ + body('username').escape().trim().isLength({ min: 1 }).withMessage('Username must not be empty'), + body('password').escape().trim().isLength({ min: 1 }).withMessage('Password must not be empty'), + ], + async (req, res) => { + try { + const errors = validationResult(req); - const loginSql = "SELECT * FROM users WHERE username = ?"; - const updateLastLoginSql = "UPDATE users SET lastLogin = CURRENT_TIMESTAMP WHERE username = ?"; - - connection.query(loginSql, [username], async (error, results) => { - if (error) { - console.error("Error executing login query:", error); - res.status(500).send("Internal Server Error"); - return; + if (!errors.isEmpty()) { + // Handle validation errors, e.g., return an error message to the client + return res.render('login', { error: 'Invalid input. Please check your credentials.' }); } - if (results.length > 0) { - const isLoginSuccessful = await bcrypt.compare(password, results[0].password); + let { username, password } = req.body; + username = username.trim(); - if (isLoginSuccessful) { - // Log successful login attempt - await logActivity(username, true, "Credentials entered correctly"); + const loginSql = "SELECT * FROM users WHERE username = ?"; + const updateLastLoginSql = "UPDATE users SET lastLogin = CURRENT_TIMESTAMP WHERE username = ?"; - const user = results[0]; - const { otp, expirationTime } = generateOTP(); + connection.query(loginSql, [username], async (error, results) => { + if (error) { + console.error("Error executing login query:", error); + res.status(500).send("Internal Server Error"); + return; + } - // Store the OTP and expiration time in the session for verification - req.session.otp = otp; - req.session.otpExpiration = expirationTime; - req.session.save(); + if (results.length > 0) { + const isLoginSuccessful = await bcrypt.compare(password, results[0].password); - // Send OTP via email - try { - await sendOTPByEmail(user.email, otp); - // Log successful OTP sending - await logActivity(username, true, "OTP successfully sent to user"); - } catch (sendOTPError) { - // Log unsuccessful OTP sending - await logActivity(username, false, "OTP failed to send to user"); - console.error("Error sending OTP:", sendOTPError); - res.status(500).send("Internal Server Error"); - return; + if (isLoginSuccessful) { + // Log successful login attempt + await logActivity(username, true, "Credentials entered correctly"); + + const user = results[0]; + const { otp, expirationTime } = generateOTP(); + + // Store the OTP and expiration time in the session for verification + req.session.otp = otp; + req.session.otpExpiration = expirationTime; + req.session.save(); + + // Send OTP via email + try { + await sendOTPByEmail(user.email, otp); + // Log successful OTP sending + await logActivity(username, true, "OTP successfully sent to user"); + } catch (sendOTPError) { + // Log unsuccessful OTP sending + await logActivity(username, false, "OTP failed to send to user"); + console.error("Error sending OTP:", sendOTPError); + res.status(500).send("Internal Server Error"); + return; + } + + // Render OTP input page + res.render("otp", { error: null, username: user.username }); + } else { + // Log unsuccessful login attempt + await logActivity(username, false, "Incorrect password"); + res.render("login", { error: "Invalid username or password" }); } - - // Render OTP input page - res.render("otp", { error: null, username: user.username }); } else { // Log unsuccessful login attempt - await logActivity(username, false, "Incorrect password"); + await logActivity(username, false, "User not found"); res.render("login", { error: "Invalid username or password" }); } - } else { - // Log unsuccessful login attempt - await logActivity(username, false, "User not found"); - res.render("login", { error: "Invalid username or password" }); - } - }); - } catch (error) { - console.error("Error in login route:", error); - res.status(500).send("Internal Server Error"); + }); + } catch (error) { + console.error("Error in login route:", error); + res.status(500).send("Internal Server Error"); + } } - }); + ); app.post("/verify-otp", async (req, res) => { try { const enteredOTP = req.body.otp; diff --git a/Sean/views/login.ejs b/Sean/views/login.ejs index f901937..0d90b6a 100644 --- a/Sean/views/login.ejs +++ b/Sean/views/login.ejs @@ -94,11 +94,5 @@ button:hover {

If you have forgotten your password, please reset here.

- diff --git a/package-lock.json b/package-lock.json index 0a88b9c..859192e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -293,13 +293,6 @@ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } } }, "content-type": { @@ -498,11 +491,6 @@ "iconv-lite": "0.4.24", "unpipe": "1.0.0" } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -546,6 +534,15 @@ } } }, + "express-validator": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz", + "integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.9.0" + } + }, "filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -1207,6 +1204,11 @@ "glob": "^7.1.3" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", diff --git a/package.json b/package.json index a0204fb..f59d111 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "ejs": "^3.1.9", "express": "^4.18.2", "express-session": "^1.17.3", + "express-validator": "^7.0.1", "helmet": "^7.1.0", "mqtt": "^5.3.3", "mysql2": "^3.6.5",