Node.js中如何对req.log.error做消毒以修复Checkmarx反射型XSS报错
修复方案
先排查代码显性问题
- 缺少
dompurify依赖引入:当前代码仅引入了jsdom,未引入DOMPurify本身,需补充引入语句const createDOMPurify = require('dompurify'); sanitizeValue函数未定义:你编写的sanitizeObject方法中调用的sanitizeValue不存在,若需要对整个req对象消毒,需补全该函数,或自行实现递归消毒对象所有可枚举属性的逻辑。- Express错误处理中间件写法不规范:Express的全局错误处理中间件不需要指定
/error路径,且必须挂载在所有普通路由之后,否则无法正常捕获全局抛出的错误。
Checkmarx XSS告警修复逻辑
Checkmarx报该错误的核心原因是识别到你将用户可控的err对象(可能包含用户输入的恶意内容)直接传递给了日志方法,若后续存在日志前端展示页面,未消毒的日志内容会触发存储型XSS,此处被误判为反射型属于扫描工具的常见规则匹配问题,可通过以下修改让扫描工具识别到消毒逻辑:
- 对
err对象做全属性消毒,不要直接将整个err实例传给sanitizeError,DOMPurify默认仅处理字符串类型参数,直接传入Error实例会导致消毒逻辑失效:
function sanitizeError(err) { if (typeof err === 'string') { return DOMPurify.sanitize(err); } if (err instanceof Error) { return { message: DOMPurify.sanitize(err.message), stack: DOMPurify.sanitize(err.stack || ''), // 其余需要保留的err属性都单独执行消毒 } } // 处理其他类型的err参数 return DOMPurify.sanitize(JSON.stringify(err)); }
- 若确认日志内容仅输出到后端文件/控制台,不会返回到前端页面,可在代码中加注释标记
// Checkmarx ignore: 日志仅后端存储无前端输出,无XSS风险,大部分企业版Checkmarx支持识别这类忽略注释,也可走内部误判申诉流程。 - 补充req对象消毒逻辑,若需要把req内容写入日志,需对req的query、params、body等用户可控字段单独消毒:
// 补全sanitizeValue方法 function sanitizeValue(val) { if (typeof val === 'string') { return DOMPurify.sanitize(val); } if (typeof val === 'object' && val !== null) { return sanitizeObject(val); } return val; } function sanitizeReq(req) { return { query: sanitizeObject(req.query), params: sanitizeObject(req.params), body: sanitizeObject(req.body), method: req.method, path: req.path } }
- 修正错误处理中间件写法:
// 放在所有普通路由之后挂载,不要指定路径 router.use((err, req, res, next) => { const sanitizedErr = sanitizeError(err); const sanitizedReq = sanitizeReq(req); req.logger.error('uncaught error page', sanitizedErr, sanitizedReq); res.redirect('/another-error-page'); })
如果不需要用到DOMPurify的全量消毒能力,也可以用更轻量的HTML特殊字符转义方法处理,扫描工具更容易识别到XSS防护逻辑:
function htmlEscape(str) { return str.replace(/[&<>"']/g, char => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[char])); }
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

