Node Express中API端点CSRF错误规避问题:next()无法正常绕过
问题描述
我编写了一个中间件,原本用于在CSRF令牌无效时渲染404页面,同时想让REST_ENDPOINTS数组中的API端点绕过CSRF错误处理。但实际运行中,这些API端点仍持续弹出CSRF错误;若直接用next()跳过错误处理,仅对同域客户端请求有效,跨域API端点仍存在问题。我需要针对这些API端点禁用CSRF错误提示,但当前实现未达到预期效果。
相关代码
中间件代码
/* * Middleware for rendering 404 page on invalid csrf token */ this.app.use((err: any, req: Request, res: Response, next: NextFunction) => { if (err.code === this.constants.CSRF.errCode) { let bypass = false; if (req.headers.referer || req.originalUrl || req.url) { let is_referer_url = ''; let is_originalUrl_url = ''; let is_url = ''; // @ts-ignore is_referer_url = req.headers.referer; is_url = req.url; is_originalUrl_url = req.originalUrl; return REST_ENDPOINTS.forEach((endpoint) => { if (is_referer_url == endpoint || is_originalUrl_url == endpoint || is_url == endpoint) { bypass = true; return this.redirect(res, endpoint); } }); } if (!bypass) { this.invalidCsrfResponse(req, res); } // this.invalidCsrfResponse(req, res); next() } if (err.code !== this.constants.CSRF.errCode) { next(err); } })
REST_ENDPOINTS数组
export const REST_ENDPOINTS = [ "/get_example/", "/patch_example/", "/delete_example/" ]
简化后的绕过代码
this.app.use((err: any, req: Request, res: Response, next: NextFunction) => { if (err.code === this.constants.CSRF.errCode) { // this.invalidCsrfResponse(req, res); next() } if (err.code !== this.constants.CSRF.errCode) { next(err); } })
问题分析
- 原中间件逻辑错误:
- 使用
forEach遍历端点时,内部的return无法终止遍历,且会直接结束整个中间件函数,导致后续next()和bypass判断逻辑失效。 - 错误地用
referer(请求来源地址)匹配API端点,跨域请求的referer可能为空或不属于当前域名,根本无法匹配到目标端点;同时严格相等==匹配URL容易忽略路径参数、尾部斜杠等细节问题。
- 使用
- 跨域处理不当:直接用
next()跳过错误处理时,CSRF保护中间件可能仍在拦截跨域请求,且未针对API端点提前禁用CSRF验证。
解决方案
1. 提前对API端点禁用CSRF保护
在CSRF中间件生效前,先判断请求路径,对指定API端点跳过CSRF验证(以csurf中间件为例):
// 假设csrfMiddleware是你初始化的CSRF保护中间件 this.app.use((req, res, next) => { // 检查请求路径是否属于API端点列表 const isApiRoute = REST_ENDPOINTS.some(endpoint => req.path === endpoint); if (isApiRoute) { return next(); // 跳过CSRF验证 } // 非API路由应用CSRF保护 csrfMiddleware(req, res, next); });
2. 修正错误处理中间件逻辑
移除无效的referer判断,改用请求路径匹配,同时优化逻辑流程:
this.app.use((err: any, req: Request, res: Response, next: NextFunction) => { if (err.code === this.constants.CSRF.errCode) { // 验证当前请求是否为API端点 const isApiEndpoint = REST_ENDPOINTS.some(endpoint => req.path === endpoint); if (isApiEndpoint) { return next(); // 跳过错误处理,继续执行后续逻辑 } // 非API端点返回404页面 this.invalidCsrfResponse(req, res); return; // 终止后续逻辑,避免重复调用next() } // 其他错误传递给下一个错误处理中间件 next(err); });
3. 配置正确的跨域规则
确保CORS配置允许目标跨域域名访问API端点,同时因为API端点无需CSRF保护,不需要传递CSRF令牌:
const corsOptions = { origin: "https://your-frontend-domain.com", // 替换为你的前端域名 credentials: true, // 若需要携带Cookie则开启 }; // 注意:CORS中间件要放在CSRF和路由中间件之前 this.app.use(cors(corsOptions));
内容的提问来源于stack exchange,提问作者someCoder
相关产品推荐
相关产品推荐

