redo ant csrf token
ensure anti csrf token and session is only created after login
This commit is contained in:
@ -19,32 +19,19 @@ const PORT = process.env.PORT || 3000;
|
||||
require("dotenv").config();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(
|
||||
session({
|
||||
secret: process.env.key,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: false, // Make sure to set this to true in a production environment with HTTPS
|
||||
httpOnly: true,
|
||||
maxAge: 24 * 60 * 60 * 1000, // Session duration in milliseconds (here set to 1 day)
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
app.use((req, res, next) => {
|
||||
if (!req.session.csrfToken) {
|
||||
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
|
||||
}
|
||||
|
||||
// Make the CSRF token available in the response context
|
||||
res.locals.csrfToken = req.session.csrfToken;
|
||||
console.log(`Server-side CSRF Token: ${req.session.csrfToken}`);
|
||||
next();
|
||||
});
|
||||
|
||||
app.set("view engine", "ejs");
|
||||
|
||||
app.use(session({
|
||||
secret: process.env.key,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: false, // Make sure to set this to true in a production environment with HTTPS
|
||||
httpOnly: true,
|
||||
maxAge: 24 * 60 * 60 * 1000, // Session duration in milliseconds (here set to 1 day)
|
||||
},
|
||||
}));
|
||||
function isAuthenticated(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return next();
|
||||
@ -144,17 +131,11 @@ const logActivity = async (username, success, message) => {
|
||||
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'),
|
||||
body('csrf_token').escape().trim().isLength({ min: 1 }).withMessage('CSRF token must not be empty'),
|
||||
],
|
||||
async (req, res) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
|
||||
// Validate CSRF token
|
||||
if (req.body.csrf_token !== req.session.csrfToken) {
|
||||
return res.status(403).send("Invalid CSRF token");
|
||||
}
|
||||
|
||||
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.', csrfToken: req.session.csrfToken });
|
||||
@ -222,17 +203,11 @@ async (req, res) => {
|
||||
// OTP verification route
|
||||
app.post("/verify-otp", [
|
||||
body('otp').escape().trim().isLength({ min: 1 }).withMessage('OTP must not be empty'),
|
||||
body('csrf_token').escape().trim().isLength({ min: 1 }).withMessage('CSRF token must not be empty'),
|
||||
],
|
||||
async (req, res) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
|
||||
// Validate CSRF token
|
||||
if (req.body.csrf_token !== req.session.csrfToken) {
|
||||
return res.status(403).send("Invalid CSRF token");
|
||||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
// Handle validation errors, e.g., return an error message to the client
|
||||
return res.render('otp', { error: 'Invalid OTP. Please try again.', username: req.body.username, csrfToken: req.session.csrfToken });
|
||||
@ -240,10 +215,16 @@ async (req, res) => {
|
||||
|
||||
const enteredOTP = req.body.otp;
|
||||
|
||||
if (!req.session) {
|
||||
// If session is not defined, handle accordingly
|
||||
console.error("Session is not defined.");
|
||||
return res.status(500).send("Internal Server Error");
|
||||
}
|
||||
|
||||
if (enteredOTP === req.session.otp) {
|
||||
// Log successful OTP entry and login
|
||||
// Log successful OTP entry
|
||||
if (req.body.username) {
|
||||
await logActivity(req.body.username, true, "OTP entered correctly. Successful login");
|
||||
await logActivity(req.body.username, true, "OTP entered correctly");
|
||||
}
|
||||
|
||||
// Correct OTP, generate a session token
|
||||
@ -253,8 +234,22 @@ async (req, res) => {
|
||||
req.session.authenticated = true;
|
||||
req.session.username = req.body.username;
|
||||
req.session.sessionToken = sessionToken;
|
||||
res.locals.csrfToken = req.session.csrfToken;
|
||||
console.log(`Server-side CSRF Token: ${req.session.csrfToken}`);
|
||||
|
||||
// Generate and store anti-CSRF token in the session
|
||||
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
// Set anti-CSRF token in res.locals
|
||||
res.locals.csrfToken = req.session.csrfToken;
|
||||
|
||||
// Log anti-CSRF token
|
||||
console.log(`Generated Anti-CSRF Token: ${req.session.csrfToken}`);
|
||||
|
||||
// Implement secure session handling:
|
||||
// 1. Set secure, HttpOnly, and SameSite flags
|
||||
// 2. Set an expiration time for the session token
|
||||
// 3. Regenerate the session after authentication
|
||||
res.cookie('sessionToken', sessionToken, { secure: true, httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000) }); // Expires in 1 day
|
||||
|
||||
console.log(`Generated Session Token: ${sessionToken}`);
|
||||
|
||||
// Redirect to home page with session token
|
||||
@ -273,7 +268,9 @@ async (req, res) => {
|
||||
res.status(500).send("Internal Server Error");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
app.get("/logout", (req, res) => {
|
||||
try {
|
||||
const username = req.session.username || "Unknown User";
|
||||
|
Reference in New Issue
Block a user