前言我写这篇文章是在2026年这个时候编程智能体已经能够完成人类布置的80%以上的编程任务。特别是在很多自媒体的加持下“人人会编程”的理念充斥着社会空间的每一个角落。的确我们能够让CodexClaude CodeQoderCodeWhale这样的编程智能体将我们的需求自然语言翻译成程序代码这些程序代码不仅能跑起来其展示的效果还相当”惊人“。可作为程序员要保持冷静我们的责任远不是辅助编程智能体来生成代码。当大家都在为编程智能体生成代码的“看得见效果”而欢呼的同时我们要比之前任何时候都要了解那些深藏于水底的”看不见“东西。当人人都在用Codex创建web应用时有多少人了解CSRF漏洞今天我要回顾的就是CSRF漏洞。CSRF 简介CSRFCross-Site Request Forgery跨站请求伪造也被称为XSRF或One-Click Attack。它是一种经典且基础的安全漏洞。CSRF 的本质是利用浏览器自动携带 Cookie 的机制冒用用户已登录的身份向目标网站发送伪造请求。 攻击者不需要知道用户的密码也不需要入侵目标服务器只需要诱导用户在已登录的状态下访问恶意页面即可。 目标网站仅凭 Cookie 验证身份无法判断请求是否为用户真实意图从而被欺骗执行了非授权操作。一个经典的教科书级别的CSRF攻击场景你登录了银行网站 A然后在一个论坛里点击了一个看起来无害的链接。这个链接实际上是一个构造了转账请求的img标签。浏览器自动附带了你的 Cookie银行后台看到的是合法用户的请求于是转账执行成功。CSRF 攻击的三个必要条件用户已登录目标网站浏览器中保有有效的身份凭证如 Session Cookie。攻击者能构造出目标网站的有效请求请求参数可预测或可枚举。目标网站没有对请求来源做有效校验如缺少 CSRF Token、SameSite 等防护机制。下面的四种防御思路本质上就是分别破坏上述三个条件中的一条或多条。当其中一条被打破CSRF攻击就无法成立。核心防御思路Anti-CSRF Token每个敏感请求附带一个随机、与用户会话绑定的 Token服务端校验破坏条件2请求不可构造/请求变了。SameSite Cookie设置 Cookie 的SameSite属性为Lax或Strict阻止第三方请求携带 Cookie破坏条件1Cookie不自动携带。双重验证操作前要求输入密码、验证码或二次确认破坏条件3新增校验。Referer / Origin 校验检查请求来源是否为可信站点破坏条件3校验来源。实战以下实战代码来至于我的简历智能体https://www.craftaidhub.com/resume_app/项目。一、核心 CSRF 防御SameSite Cookie文件src/security/cookie.rs 第 64 行Cookie::build(self.cookie_name.clone(), user_id.to_string()) .http_only(true) .secure(false) .same_site(SameSite::Strict) // ← 关键严格同站模式 .max_age(cookie_duration) .finish()SameSite::Strict 是当前最有效的 CSRF 防御手段之一浏览器在来自其他站点的跨站请求包括通过form提交的 POST、通过img发起的 GET中不会附带resume_agent_user_id这个 Cookie。攻击者构造伪造页面 → 用户浏览器自动发起请求 → 因 Cookie 未携带 → 中间件无法解析 user_id → 请求被拦截。效果当用户登录某钓鱼网站该网站通过form actionhttps://your-server/api/v1/startAnalyze methodPOST发起跨站请求时用户的身份 Cookie 不会被带上因此无法冒充用户提交分析请求。二、第二层Cookie 签名防篡改文件src/security/cookie.rs 第 136–184 行fn sign_cookie(self, cookie: mut Cookie_) - Result(), AppError { let mut mac HmacSha256::new_from_slice(self.secret_key)?; mac.update(message.as_bytes()); let signature hex::encode(mac.finalize().into_bytes()); let signed_value format!({}.{}, cookie.value(), signature); cookie.set_value(signed_value); }使用 HMAC-SHA256 对 cookie_namecookie_value 计算签名签名附加在 Cookie 值末尾格式为 user_id.signature验证时使用 恒定时间比较subtle::ConstantTimeEq防止时序攻击CSRF 关联即使攻击者通过某种方式强行设置了 Cookie如 XSS 或其他漏洞写入了 resume_agent_user_id因为无法伪造 HMAC 签名中间件在验证时会拒绝该请求。三、第三层请求身份验证中间件文件src/middleware.rs 第 69–166 行// 在 SecurityMiddleware 中 if path.starts_with(/api/v1/) !path.starts_with(/api/v1/status) !path.starts_with(/api/v1/feedback/question) !path.starts_with(/api/v1/feedback/submit) { match app_state.cookie_security .extract_user_id_from_request(http_req, *app_state.user_repo) .await { Ok(Some(user_id)) { /* 继续 */ }, Ok(None) { /* 新用户或无效用户不设置 user_id */ }, Err(e) { return Err(BadRequest(Invalid user session)); } } }所有受保护的 API 接口/api/v1/startAnalyze、/api/v1/analyze、/api/v1/diagnosis、/api/v1/resume/* 等在进入 handler 之前中间件会解析请求中的 resume_agent_user_id Cookie验证 HMAC 签名查 Redis 确认用户存在验证失败 → 直接返回 400 / 401这意味着跨站请求即使走到了中间件层也会因为签名验证失败或用户不存在而被拒绝。四、辅助防御速率限制文件src/security/rate_limit.rs/// 检查用户是否超过速率限制 pub fn check_user_rate_limit(self, user_id: str) - Resultbool, AppError { ... // 如果超过窗口时间重置计数 if now.duration_since(request_info.last_request) self.window_size { request_info.count 0; request_info.last_request now; } // 检查是否超过限制 if request_info.count self.system_limits.max_requests_per_user { warn!(Rate limit exceeded for user: {}, user_id); return Ok(false); } ... }五、辅助防御输入内容安全验证文件src/security/rate_limit.rs 第 200 行fn contains_suspicious_content(input: str) - bool { // 扫描 script、iframe、onerror、javascript: 等 XSS 特征 }在 startAnalyze、diagnosis 等 POST 接口的 handler 中对 JD 和简历内容进行安全过滤。这防止了攻击者通过 CSRF 漏洞注入恶意脚本执行 XSS。六、辅助防御反馈提交动态密钥文件src/middleware/feedback_validation.rsimplS, B actix_web::dev::ServiceServiceRequest for FeedbackValidationMiddlewareServiceS where S: actix_web::dev::ServiceServiceRequest, Response ServiceResponseB, Error Error static, S::Future: static, B: MessageBody static, { fn call(self, req: ServiceRequest) - Self::Future { let app_state self.app_state.clone(); let service self.service.clone(); Box::pin(async move { // Only validate for feedback submission endpoint if req.path() /api/v1/feedback/submit req.method() POST { // Parse the request body to get dynamic_key match req.json::serde_json::Value().await { Ok(json_body) { if let Some(dynamic_key) json_body.get(dynamic_key).and_then(|k| k.as_str()) { // Validate the dynamic key match app_state.feedback_service.validate_dynamic_key(dynamic_key).await { Ok(true) { ... } Ok(false) { // Key is invalid or expired ... } Err(e) { error!(Failed to validate dynamic key: {}, e); ... } } } else { ... } } Err(e) { ... } } } ... }) } }/api/v1/feedback/submit 接口在 FeedbackValidationMiddleware 中验证 dynamic_key客户端提交反馈时必须先请求 GET /api/v1/feedback/question 获取一个带有 TTL 的动态密钥提交时中间件验证该密钥密钥过期或在别处使用过都会失败这为反馈提交接口提供了一个 CSRF token 的等效实现。后记我写这篇文章的目的主要是为了记录所以结束得比较冲忙在AI编程时代感觉程序员的时间不是变多了反而是变少了。同时参考的链接也记录了下来也是很有价值的。这些链接要是放在10多年前访问量也是相当火爆的。参考阿里云 web渗透-CSRF漏洞YesWeHack 经典示例Portswigger.net CRSF三条件
在AI编程时代,了解CSRF
发布时间:2026/6/6 21:19:30
前言我写这篇文章是在2026年这个时候编程智能体已经能够完成人类布置的80%以上的编程任务。特别是在很多自媒体的加持下“人人会编程”的理念充斥着社会空间的每一个角落。的确我们能够让CodexClaude CodeQoderCodeWhale这样的编程智能体将我们的需求自然语言翻译成程序代码这些程序代码不仅能跑起来其展示的效果还相当”惊人“。可作为程序员要保持冷静我们的责任远不是辅助编程智能体来生成代码。当大家都在为编程智能体生成代码的“看得见效果”而欢呼的同时我们要比之前任何时候都要了解那些深藏于水底的”看不见“东西。当人人都在用Codex创建web应用时有多少人了解CSRF漏洞今天我要回顾的就是CSRF漏洞。CSRF 简介CSRFCross-Site Request Forgery跨站请求伪造也被称为XSRF或One-Click Attack。它是一种经典且基础的安全漏洞。CSRF 的本质是利用浏览器自动携带 Cookie 的机制冒用用户已登录的身份向目标网站发送伪造请求。 攻击者不需要知道用户的密码也不需要入侵目标服务器只需要诱导用户在已登录的状态下访问恶意页面即可。 目标网站仅凭 Cookie 验证身份无法判断请求是否为用户真实意图从而被欺骗执行了非授权操作。一个经典的教科书级别的CSRF攻击场景你登录了银行网站 A然后在一个论坛里点击了一个看起来无害的链接。这个链接实际上是一个构造了转账请求的img标签。浏览器自动附带了你的 Cookie银行后台看到的是合法用户的请求于是转账执行成功。CSRF 攻击的三个必要条件用户已登录目标网站浏览器中保有有效的身份凭证如 Session Cookie。攻击者能构造出目标网站的有效请求请求参数可预测或可枚举。目标网站没有对请求来源做有效校验如缺少 CSRF Token、SameSite 等防护机制。下面的四种防御思路本质上就是分别破坏上述三个条件中的一条或多条。当其中一条被打破CSRF攻击就无法成立。核心防御思路Anti-CSRF Token每个敏感请求附带一个随机、与用户会话绑定的 Token服务端校验破坏条件2请求不可构造/请求变了。SameSite Cookie设置 Cookie 的SameSite属性为Lax或Strict阻止第三方请求携带 Cookie破坏条件1Cookie不自动携带。双重验证操作前要求输入密码、验证码或二次确认破坏条件3新增校验。Referer / Origin 校验检查请求来源是否为可信站点破坏条件3校验来源。实战以下实战代码来至于我的简历智能体https://www.craftaidhub.com/resume_app/项目。一、核心 CSRF 防御SameSite Cookie文件src/security/cookie.rs 第 64 行Cookie::build(self.cookie_name.clone(), user_id.to_string()) .http_only(true) .secure(false) .same_site(SameSite::Strict) // ← 关键严格同站模式 .max_age(cookie_duration) .finish()SameSite::Strict 是当前最有效的 CSRF 防御手段之一浏览器在来自其他站点的跨站请求包括通过form提交的 POST、通过img发起的 GET中不会附带resume_agent_user_id这个 Cookie。攻击者构造伪造页面 → 用户浏览器自动发起请求 → 因 Cookie 未携带 → 中间件无法解析 user_id → 请求被拦截。效果当用户登录某钓鱼网站该网站通过form actionhttps://your-server/api/v1/startAnalyze methodPOST发起跨站请求时用户的身份 Cookie 不会被带上因此无法冒充用户提交分析请求。二、第二层Cookie 签名防篡改文件src/security/cookie.rs 第 136–184 行fn sign_cookie(self, cookie: mut Cookie_) - Result(), AppError { let mut mac HmacSha256::new_from_slice(self.secret_key)?; mac.update(message.as_bytes()); let signature hex::encode(mac.finalize().into_bytes()); let signed_value format!({}.{}, cookie.value(), signature); cookie.set_value(signed_value); }使用 HMAC-SHA256 对 cookie_namecookie_value 计算签名签名附加在 Cookie 值末尾格式为 user_id.signature验证时使用 恒定时间比较subtle::ConstantTimeEq防止时序攻击CSRF 关联即使攻击者通过某种方式强行设置了 Cookie如 XSS 或其他漏洞写入了 resume_agent_user_id因为无法伪造 HMAC 签名中间件在验证时会拒绝该请求。三、第三层请求身份验证中间件文件src/middleware.rs 第 69–166 行// 在 SecurityMiddleware 中 if path.starts_with(/api/v1/) !path.starts_with(/api/v1/status) !path.starts_with(/api/v1/feedback/question) !path.starts_with(/api/v1/feedback/submit) { match app_state.cookie_security .extract_user_id_from_request(http_req, *app_state.user_repo) .await { Ok(Some(user_id)) { /* 继续 */ }, Ok(None) { /* 新用户或无效用户不设置 user_id */ }, Err(e) { return Err(BadRequest(Invalid user session)); } } }所有受保护的 API 接口/api/v1/startAnalyze、/api/v1/analyze、/api/v1/diagnosis、/api/v1/resume/* 等在进入 handler 之前中间件会解析请求中的 resume_agent_user_id Cookie验证 HMAC 签名查 Redis 确认用户存在验证失败 → 直接返回 400 / 401这意味着跨站请求即使走到了中间件层也会因为签名验证失败或用户不存在而被拒绝。四、辅助防御速率限制文件src/security/rate_limit.rs/// 检查用户是否超过速率限制 pub fn check_user_rate_limit(self, user_id: str) - Resultbool, AppError { ... // 如果超过窗口时间重置计数 if now.duration_since(request_info.last_request) self.window_size { request_info.count 0; request_info.last_request now; } // 检查是否超过限制 if request_info.count self.system_limits.max_requests_per_user { warn!(Rate limit exceeded for user: {}, user_id); return Ok(false); } ... }五、辅助防御输入内容安全验证文件src/security/rate_limit.rs 第 200 行fn contains_suspicious_content(input: str) - bool { // 扫描 script、iframe、onerror、javascript: 等 XSS 特征 }在 startAnalyze、diagnosis 等 POST 接口的 handler 中对 JD 和简历内容进行安全过滤。这防止了攻击者通过 CSRF 漏洞注入恶意脚本执行 XSS。六、辅助防御反馈提交动态密钥文件src/middleware/feedback_validation.rsimplS, B actix_web::dev::ServiceServiceRequest for FeedbackValidationMiddlewareServiceS where S: actix_web::dev::ServiceServiceRequest, Response ServiceResponseB, Error Error static, S::Future: static, B: MessageBody static, { fn call(self, req: ServiceRequest) - Self::Future { let app_state self.app_state.clone(); let service self.service.clone(); Box::pin(async move { // Only validate for feedback submission endpoint if req.path() /api/v1/feedback/submit req.method() POST { // Parse the request body to get dynamic_key match req.json::serde_json::Value().await { Ok(json_body) { if let Some(dynamic_key) json_body.get(dynamic_key).and_then(|k| k.as_str()) { // Validate the dynamic key match app_state.feedback_service.validate_dynamic_key(dynamic_key).await { Ok(true) { ... } Ok(false) { // Key is invalid or expired ... } Err(e) { error!(Failed to validate dynamic key: {}, e); ... } } } else { ... } } Err(e) { ... } } } ... }) } }/api/v1/feedback/submit 接口在 FeedbackValidationMiddleware 中验证 dynamic_key客户端提交反馈时必须先请求 GET /api/v1/feedback/question 获取一个带有 TTL 的动态密钥提交时中间件验证该密钥密钥过期或在别处使用过都会失败这为反馈提交接口提供了一个 CSRF token 的等效实现。后记我写这篇文章的目的主要是为了记录所以结束得比较冲忙在AI编程时代感觉程序员的时间不是变多了反而是变少了。同时参考的链接也记录了下来也是很有价值的。这些链接要是放在10多年前访问量也是相当火爆的。参考阿里云 web渗透-CSRF漏洞YesWeHack 经典示例Portswigger.net CRSF三条件