ANTI CSRF FUNCTION
CSRF PROTECTION DONE FOR USER CREATION USER DELETION AND MANUAL PASSWORD RESET FUNCTION
This commit is contained in:
parent
f91e99330a
commit
bfa005b08b
155
Sean/server.js
155
Sean/server.js
@ -243,6 +243,7 @@ async (req, res) => {
|
|||||||
|
|
||||||
// Log anti-CSRF token
|
// Log anti-CSRF token
|
||||||
console.log(`Generated Anti-CSRF Token: ${req.session.csrfToken}`);
|
console.log(`Generated Anti-CSRF Token: ${req.session.csrfToken}`);
|
||||||
|
// Set CSRF token as a cookie
|
||||||
|
|
||||||
// Implement secure session handling:
|
// Implement secure session handling:
|
||||||
// 1. Set secure, HttpOnly, and SameSite flags
|
// 1. Set secure, HttpOnly, and SameSite flags
|
||||||
@ -269,7 +270,12 @@ async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setCSRFToken(req, res, next) {
|
||||||
|
res.locals.csrfToken = req.session.csrfToken;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(setCSRFToken);
|
||||||
|
|
||||||
app.get("/logout", (req, res) => {
|
app.get("/logout", (req, res) => {
|
||||||
try {
|
try {
|
||||||
@ -342,7 +348,7 @@ app.get("/inusers", isAuthenticated, (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render the inusers page with JSON data
|
// Render the inusers page with JSON data
|
||||||
res.render("inusers", { allUsers });
|
res.render("inusers", { allUsers ,csrfToken: req.session.csrfToken });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
function isStrongPassword(password) {
|
function isStrongPassword(password) {
|
||||||
@ -405,10 +411,7 @@ app.post(
|
|||||||
body('username').trim().isLength({ min: 1 }).withMessage('Username must not be empty').escape(),
|
body('username').trim().isLength({ min: 1 }).withMessage('Username must not be empty').escape(),
|
||||||
body('email').isEmail().withMessage('Invalid email address').normalizeEmail(),
|
body('email').isEmail().withMessage('Invalid email address').normalizeEmail(),
|
||||||
body('password').custom((value) => {
|
body('password').custom((value) => {
|
||||||
if (!isStrongPassword(value)) {
|
if (!isStrongPassword(value)) { throw new Error('Password does not meet complexity requirements'); } return true;
|
||||||
throw new Error('Password does not meet complexity requirements');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}),
|
}),
|
||||||
body('jobTitle').trim().isLength({ min: 1 }).withMessage('Job title must not be empty').escape(),
|
body('jobTitle').trim().isLength({ min: 1 }).withMessage('Job title must not be empty').escape(),
|
||||||
],
|
],
|
||||||
@ -420,30 +423,27 @@ app.post(
|
|||||||
return res.status(400).json({ errors: errors.array() });
|
return res.status(400).json({ errors: errors.array() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the anti-CSRF token
|
||||||
|
const submittedCSRFToken = req.body.csrf_token;
|
||||||
|
|
||||||
|
if (!req.session.csrfToken || submittedCSRFToken !== req.session.csrfToken) {
|
||||||
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract user input
|
||||||
const { name, username, email, password, jobTitle } = req.body;
|
const { name, username, email, password, jobTitle } = req.body;
|
||||||
console.log("Sanitized Input:", {
|
|
||||||
name,
|
|
||||||
username,
|
|
||||||
email,
|
|
||||||
password: "*****", // Avoid logging passwords
|
|
||||||
jobTitle,
|
|
||||||
});
|
|
||||||
// Extract the username of the user creating a new user
|
// Extract the username of the user creating a new user
|
||||||
const creatorUsername = req.session.username; // Adjust this based on how you store the creator's username in your session
|
const creatorUsername = req.session.username; // Adjust this based on how you store the creator's username in your session
|
||||||
|
|
||||||
// Validate password complexity (additional check)
|
// Additional password complexity check
|
||||||
if (!isStrongPassword(password)) {
|
if (!isStrongPassword(password)) {
|
||||||
return res
|
return res.status(400).json({ error: "Password does not meet complexity requirements" });
|
||||||
.status(400)
|
|
||||||
.json({ error: "Password does not meet complexity requirements" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the username is already taken
|
// Check if the username is already taken
|
||||||
const checkUsernameQuery = "SELECT * FROM users WHERE username = ?";
|
const checkUsernameQuery = "SELECT * FROM users WHERE username = ?";
|
||||||
connection.query(
|
connection.query(checkUsernameQuery, [username], (usernameQueryErr, usernameResults) => {
|
||||||
checkUsernameQuery,
|
|
||||||
[username],
|
|
||||||
(usernameQueryErr, usernameResults) => {
|
|
||||||
if (usernameQueryErr) {
|
if (usernameQueryErr) {
|
||||||
console.error("Error checking username:", usernameQueryErr);
|
console.error("Error checking username:", usernameQueryErr);
|
||||||
return res.status(500).json({ error: "Internal Server Error" });
|
return res.status(500).json({ error: "Internal Server Error" });
|
||||||
@ -452,20 +452,15 @@ app.post(
|
|||||||
if (usernameResults.length > 0) {
|
if (usernameResults.length > 0) {
|
||||||
// Log unsuccessful user creation due to username taken
|
// Log unsuccessful user creation due to username taken
|
||||||
logUserCreationActivity(creatorUsername, false, "username taken");
|
logUserCreationActivity(creatorUsername, false, "username taken");
|
||||||
return res
|
return res.status(400).json({
|
||||||
.status(400)
|
|
||||||
.json({
|
|
||||||
error: "Username is already taken",
|
error: "Username is already taken",
|
||||||
message: "Username is already taken. Please choose a different username.",
|
message: "Username is already taken. Please choose a different username."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the email is already taken
|
// Check if the email is already taken
|
||||||
const checkEmailQuery = "SELECT * FROM users WHERE email = ?";
|
const checkEmailQuery = "SELECT * FROM users WHERE email = ?";
|
||||||
connection.query(
|
connection.query(checkEmailQuery, [email], (emailQueryErr, emailResults) => {
|
||||||
checkEmailQuery,
|
|
||||||
[email],
|
|
||||||
(emailQueryErr, emailResults) => {
|
|
||||||
if (emailQueryErr) {
|
if (emailQueryErr) {
|
||||||
console.error("Error checking email:", emailQueryErr);
|
console.error("Error checking email:", emailQueryErr);
|
||||||
return res.status(500).json({ error: "Internal Server Error" });
|
return res.status(500).json({ error: "Internal Server Error" });
|
||||||
@ -474,11 +469,9 @@ app.post(
|
|||||||
if (emailResults.length > 0) {
|
if (emailResults.length > 0) {
|
||||||
// Log unsuccessful user creation due to email taken
|
// Log unsuccessful user creation due to email taken
|
||||||
logUserCreationActivity(creatorUsername, false, "email taken");
|
logUserCreationActivity(creatorUsername, false, "email taken");
|
||||||
return res
|
return res.status(400).json({
|
||||||
.status(400)
|
|
||||||
.json({
|
|
||||||
error: "Email is already in use",
|
error: "Email is already in use",
|
||||||
message: "Email is already in use. Please choose another email.",
|
message: "Email is already in use. Please choose another email."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,9 +486,7 @@ app.post(
|
|||||||
connection.beginTransaction((transactionErr) => {
|
connection.beginTransaction((transactionErr) => {
|
||||||
if (transactionErr) {
|
if (transactionErr) {
|
||||||
console.error("Error starting transaction:", transactionErr);
|
console.error("Error starting transaction:", transactionErr);
|
||||||
return res
|
return res.status(500).json({ error: "Internal Server Error" });
|
||||||
.status(500)
|
|
||||||
.json({ error: "Internal Server Error" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the insert query
|
// Define the insert query
|
||||||
@ -504,39 +495,21 @@ app.post(
|
|||||||
|
|
||||||
// Log the query and its parameters
|
// Log the query and its parameters
|
||||||
console.log("Insert Query:", insertUserQuery);
|
console.log("Insert Query:", insertUserQuery);
|
||||||
console.log("Query Parameters:", [
|
console.log("Query Parameters:", [name, username, email, hashedPassword, jobTitle]);
|
||||||
name,
|
|
||||||
username,
|
|
||||||
email,
|
|
||||||
hashedPassword,
|
|
||||||
jobTitle,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Execute the query with user data
|
// Execute the query with user data
|
||||||
connection.query(
|
connection.query(insertUserQuery, [name, username, email, hashedPassword, jobTitle], (queryErr, results) => {
|
||||||
insertUserQuery,
|
|
||||||
[name, username, email, hashedPassword, jobTitle],
|
|
||||||
(queryErr, results) => {
|
|
||||||
if (queryErr) {
|
if (queryErr) {
|
||||||
console.error("Error executing query:", queryErr);
|
console.error("Error executing query:", queryErr);
|
||||||
|
|
||||||
// Rollback the transaction in case of an error
|
// Rollback the transaction in case of an error
|
||||||
connection.rollback((rollbackErr) => {
|
connection.rollback((rollbackErr) => {
|
||||||
if (rollbackErr) {
|
if (rollbackErr) {
|
||||||
console.error(
|
console.error("Error rolling back transaction:", rollbackErr);
|
||||||
"Error rolling back transaction:",
|
|
||||||
rollbackErr
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Log unsuccessful user creation due to an error
|
// Log unsuccessful user creation due to an error
|
||||||
logUserCreationActivity(
|
logUserCreationActivity(creatorUsername, false, "internal error");
|
||||||
creatorUsername,
|
return res.status(500).json({ error: "Internal Server Error" });
|
||||||
false,
|
|
||||||
"internal error"
|
|
||||||
);
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json({ error: "Internal Server Error" });
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -544,44 +517,23 @@ app.post(
|
|||||||
// Commit the transaction
|
// Commit the transaction
|
||||||
connection.commit((commitErr) => {
|
connection.commit((commitErr) => {
|
||||||
if (commitErr) {
|
if (commitErr) {
|
||||||
console.error(
|
console.error("Error committing transaction:", commitErr);
|
||||||
"Error committing transaction:",
|
|
||||||
commitErr
|
|
||||||
);
|
|
||||||
// Log unsuccessful user creation due to an error
|
// Log unsuccessful user creation due to an error
|
||||||
logUserCreationActivity(
|
logUserCreationActivity(creatorUsername, false, "internal error");
|
||||||
creatorUsername,
|
return res.status(500).json({ error: "Internal Server Error" });
|
||||||
false,
|
|
||||||
"internal error"
|
|
||||||
);
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json({ error: "Internal Server Error" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log successful user creation
|
// Log successful user creation
|
||||||
logUserCreationActivity(
|
logUserCreationActivity(creatorUsername, true, "user created successfully");
|
||||||
creatorUsername,
|
|
||||||
true,
|
|
||||||
"user created successfully"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Log the results of the query
|
// Redirect to "/inusers"
|
||||||
console.log("Query Results:", results);
|
res.redirect('/inusers');
|
||||||
|
});
|
||||||
// Respond with a success message
|
});
|
||||||
res
|
});
|
||||||
.status(201)
|
});
|
||||||
.json({ message: "User created successfully" });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error creating user:", error);
|
console.error("Error creating user:", error);
|
||||||
// Log unsuccessful user creation due to an error
|
// Log unsuccessful user creation due to an error
|
||||||
@ -589,11 +541,8 @@ app.post(
|
|||||||
res.status(500).json({ error: "Internal Server Error" });
|
res.status(500).json({ error: "Internal Server Error" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
app.get("/forgot-password", (req, res) => {
|
|
||||||
res.render("forgot-password"); // Assuming you have an EJS template for this
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/forgot-password", (req, res) => {
|
app.get("/forgot-password", (req, res) => {
|
||||||
res.render("forgot-password", { error: null, success: null });
|
res.render("forgot-password", { error: null, success: null });
|
||||||
@ -777,8 +726,14 @@ app.get("/reset-password/:token", (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post("/reset-password", async (req, res) => {
|
app.post("/reset-password", async (req, res) => {
|
||||||
const { username, password, confirmPassword } = req.body;
|
|
||||||
|
const { username, password, confirmPassword, csrf_token } = req.body;
|
||||||
const creatorUsername = req.session.username;
|
const creatorUsername = req.session.username;
|
||||||
|
const submittedCSRFToken = req.body.csrf_token;
|
||||||
|
|
||||||
|
if (!req.session.csrfToken || submittedCSRFToken !== req.session.csrfToken) {
|
||||||
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
|
||||||
// Sanitize the inputs
|
// Sanitize the inputs
|
||||||
const sanitizedUsername = validator.escape(username);
|
const sanitizedUsername = validator.escape(username);
|
||||||
@ -899,13 +854,20 @@ app.get('/api/users', (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route to delete a user by username
|
|
||||||
|
|
||||||
app.delete('/api/deleteUser/:username', async (req, res) => {
|
app.delete('/api/deleteUser/:username', async (req, res) => {
|
||||||
const { username } = req.params;
|
const { username } = req.params;
|
||||||
const query = 'DELETE FROM users WHERE username = ?';
|
const query = 'DELETE FROM users WHERE username = ?';
|
||||||
const creatorUsername = req.session.username;
|
const creatorUsername = req.session.username;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Extract CSRF token from the request body
|
||||||
|
const { csrfToken } = req.body;
|
||||||
|
|
||||||
|
// Compare CSRF token with the one stored in the session
|
||||||
|
if (csrfToken !== req.session.csrfToken) {
|
||||||
|
return res.status(403).json({ success: false, error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
|
||||||
// Log deletion activity to USER_LOGS
|
// Log deletion activity to USER_LOGS
|
||||||
const deletionActivity = `User ${username} has been successfully deleted`;
|
const deletionActivity = `User ${username} has been successfully deleted`;
|
||||||
const logQuery = 'INSERT INTO USER_LOGS (USERNAME, ACTIVITY, TIMESTAMP) VALUES (?, ?, CURRENT_TIMESTAMP)';
|
const logQuery = 'INSERT INTO USER_LOGS (USERNAME, ACTIVITY, TIMESTAMP) VALUES (?, ?, CURRENT_TIMESTAMP)';
|
||||||
@ -925,6 +887,7 @@ app.get('/api/users', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
async function executeQuery(sql, values) {
|
async function executeQuery(sql, values) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.query(sql, values, (err, results) => {
|
connection.query(sql, values, (err, results) => {
|
||||||
|
@ -122,6 +122,7 @@
|
|||||||
<input type="password" name="confirmPassword" id="resetConfirmPassword" placeholder="Confirm new password" required>
|
<input type="password" name="confirmPassword" id="resetConfirmPassword" placeholder="Confirm new password" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
<div class="button">
|
<div class="button">
|
||||||
<input type="submit" value="Reset Password">
|
<input type="submit" value="Reset Password">
|
||||||
</div>
|
</div>
|
||||||
@ -129,6 +130,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div id="deleteUserContainer" style="display: none;">
|
<div id="deleteUserContainer" style="display: none;">
|
||||||
<h3>Delete User</h3>
|
<h3>Delete User</h3>
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
@ -137,7 +139,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="searchResultsContainer" style="display: none;">
|
<div id="searchResultsContainer" style="display: none;">
|
||||||
<h4>Search Results</h4>
|
<h4>Search Results</h4>
|
||||||
<ul id="searchResultsList"></ul>
|
<ul id="searchResultsList">
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#resetPasswordLink').on('click', function () {
|
$('#resetPasswordLink').on('click', function () {
|
||||||
$('#resetPasswordFormContainer').show();
|
$('#resetPasswordFormContainer').show();
|
||||||
@ -177,13 +175,22 @@ function displaySearchResults(users) {
|
|||||||
$('#searchResultsContainer').hide();
|
$('#searchResultsContainer').hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event listener for delete user button in search results
|
// Event listener for delete user button in search results
|
||||||
$('#searchResultsList').on('click', '.deleteUserButton', function () {
|
$('#searchResultsList').on('click', '.deleteUserButton', function () {
|
||||||
const usernameToDelete = $(this).data('username');
|
const usernameToDelete = $(this).data('username');
|
||||||
|
const csrfToken = $('[name="csrf_token"]').val(); // Access the CSRF token by name
|
||||||
|
|
||||||
|
console.log(csrfToken);
|
||||||
console.log('Before fetch for user deletion');
|
console.log('Before fetch for user deletion');
|
||||||
// Make a fetch request to delete the user
|
|
||||||
|
// Make a fetch request to delete the user with CSRF token in headers
|
||||||
fetch(`/api/deleteUser/${usernameToDelete}`, {
|
fetch(`/api/deleteUser/${usernameToDelete}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ csrfToken }), // Include CSRF token in the request body
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
console.log('Inside fetch response handler');
|
console.log('Inside fetch response handler');
|
||||||
@ -277,8 +284,7 @@ function resetFormFields() {
|
|||||||
$('#confirmPassword').val('');
|
$('#confirmPassword').val('');
|
||||||
$('#jobTitle').val('');
|
$('#jobTitle').val('');
|
||||||
}
|
}
|
||||||
|
const csrf_token = $('#userForm input[name="csrf_token"]').val();
|
||||||
|
|
||||||
$('#userForm').on('submit', function (e) {
|
$('#userForm').on('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -303,6 +309,7 @@ function resetFormFields() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: name,
|
name: name,
|
||||||
@ -310,6 +317,7 @@ function resetFormFields() {
|
|||||||
email: email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
jobTitle: jobTitle,
|
jobTitle: jobTitle,
|
||||||
|
csrf_token: csrf_token, // Include the CSRF token in the body
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@ -368,7 +376,7 @@ $('#resetPasswordForm').on('submit', function (e) {
|
|||||||
const username = $('#resetUsername').val();
|
const username = $('#resetUsername').val();
|
||||||
const password = $('#resetPassword').val();
|
const password = $('#resetPassword').val();
|
||||||
const confirmPassword = $('#resetConfirmPassword').val();
|
const confirmPassword = $('#resetConfirmPassword').val();
|
||||||
|
const csrf_token = $('#userForm input[name="csrf_token"]').val();
|
||||||
console.log('Username:', username);
|
console.log('Username:', username);
|
||||||
console.log('New Password:', password);
|
console.log('New Password:', password);
|
||||||
|
|
||||||
@ -384,7 +392,6 @@ $('#resetPasswordForm').on('submit', function (e) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a fetch request
|
|
||||||
fetch('/reset-password', {
|
fetch('/reset-password', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -394,6 +401,7 @@ $('#resetPasswordForm').on('submit', function (e) {
|
|||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
confirmPassword: confirmPassword,
|
confirmPassword: confirmPassword,
|
||||||
|
csrf_token: csrf_token
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@ -431,4 +439,3 @@ $('#resetPasswordForm').on('submit', function (e) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user