fix(security): stop reflecting submitted values in validation errors everywhere, cap credential lengths, close the login timing oracle
safeValidationErrors moves to utils/routeHelpers and replaces every
res.status(400).json({ errors: errors.array() }) in the routes, so no 400
body carries the submitted value any more (setup, customer auth and
customer change-password were still echoing rejected passwords).
Admin login, gallery verify, customer login/register/reset, customer
change-password and setup now cap username/slug at 255 and passwords at
MAX_PASSWORD_LENGTH at the validator, so an oversized value never reaches
the lockout lookup, bcrypt or the failed-attempt log.
Admin and customer login run one bcrypt compare on every path; the unknown
account branch used to return in microseconds against ~100ms for a wrong
password, which enumerated usernames despite the generic message.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
const { body, param, validationResult } = require('express-validator');
|
||||
const { safeValidationErrors } = require('./routeHelpers');
|
||||
const validator = require('validator');
|
||||
const { IDENTITY_PRESERVING_NORMALIZE_EMAIL } = require('./emailNormalization');
|
||||
const { REACTION_EMOJIS } = require('../constants/reactions');
|
||||
@@ -254,7 +255,7 @@ const checkValidation = (req, res, next) => {
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation failed',
|
||||
errors: errors.array()
|
||||
errors: safeValidationErrors(errors)
|
||||
});
|
||||
}
|
||||
next();
|
||||
|
||||
@@ -42,6 +42,15 @@ const handleAsync = (fn) => {
|
||||
* // ... rest of handler
|
||||
* }));
|
||||
*/
|
||||
|
||||
/**
|
||||
* express-validator's errors.array() carries `value` -- the submitted input.
|
||||
* Returning it verbatim reflects whatever the caller sent (a rejected
|
||||
* password, a 2mb string) back in the 400 body. Everything except `value` is
|
||||
* kept, so consumers that read `msg` / `path` see no change.
|
||||
*/
|
||||
const safeValidationErrors = (errors) => errors.array().map(({ value, ...rest }) => rest);
|
||||
|
||||
const validateRequest = (req) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
@@ -174,6 +183,7 @@ const paginatedResponse = (data, total, page, limit) => {
|
||||
module.exports = {
|
||||
handleAsync,
|
||||
validateRequest,
|
||||
safeValidationErrors,
|
||||
successResponse,
|
||||
errorResponse,
|
||||
withValidation,
|
||||
|
||||
Reference in New Issue
Block a user