4.3 跨边界请求:CSRF、CORS 与 SSRF
CSRF 与 SSRF 都让一个有权限的组件替攻击者发送请求,但代理不同:CSRF 借用用户浏览器自动携带的凭据,SSRF 借用服务器的网络位置和服务身份。CORS 则主要控制浏览器脚本能否读取跨源响应。
CSRF 不因 SameSite 出现而消失
若应用用 Cookie 认证,浏览器可能在跨站触发的请求中自动携带它。防护应组合:
- 状态变更使用 POST/PUT/PATCH/DELETE 等语义上不安全的方法,不放在 GET/HEAD 中;这里“不安全”是 HTTP 的状态变更分类,使用 POST 本身不防 CSRF;
- SameSite=Lax/Strict 按产品流程设置;
- 使用绑定会话的 synchronizer token,或以 HMAC 绑定会话的 signed double-submit token;仅比对两个相等但可被攻击者种入的值不够;
- 校验 Origin,必要时把 Referer 作为兼容信号;
- 高风险操作重新认证并显示交易内容;
- 不信任同站不可信子域。
SameSite=None 场景必须配合 Secure,且需要完整 token/Origin 防护。登录 CSRF、OAuth 回调和跨站嵌入流程尤其要单独建模,不能为了让一个集成工作就全局关闭防御。
CORS 是响应读取策略
服务端通过 CORS 响应头告诉浏览器哪些 origin 的脚本可以读取响应:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin对 credentials mode 为 include 的请求,Access-Control-Allow-Origin: * 不能授权浏览器读取响应;这不意味着请求或 Cookie 一定没有发出去。动态反射 Origin 前必须与规范化后的精确 allowlist 匹配,不能用 endsWith("example.com") 接受 attackerexample.com。
例如恶意站点发起普通跨站表单 POST 时,浏览器可能直接发请求;若 Cookie 的 SameSite 条件允许,服务端仍可能收到登录凭据。响应因 CORS 不可读,也撤不回已经完成的转账。
Preflight 不是认证机制,非浏览器客户端可直接发送请求。API 必须照常验证身份、授权、内容类型和 CSRF 条件。CORS 配错通常泄露浏览器可读数据;它并不替网络 ACL 限制谁能连接服务。
SSRF 让服务器成为网络代理
典型入口包括 URL 预览、Webhook 测试、头像抓取、PDF 渲染、云导入和“从 URL 安装插件”。攻击者可能访问:
- loopback、私网、link-local 和云 metadata;
- 只对内开放的管理面与数据库代理;
- Unix socket 或非 HTTP scheme;
- 通过重定向、DNS rebinding、IPv6/混合编码绕过的目标。
最佳防御是不要接受任意 URL:让用户选择服务端登记的 integration/object ID。若业务确实需要出站抓取,应建立专用 egress fetcher:
- 只允许
https等必要 scheme; - 严格解析 hostname、port、userinfo 和 IP literal;
- 检查全部 A/AAAA 结果,拒绝 loopback、private、link-local、multicast 及其他不允许的特殊地址,并统一处理 IPv4-mapped IPv6;不能只检查第一条结果;
- 建立连接时使用已验证 IP,避免连接库再次解析到另一地址;TLS 仍验证原始 hostname 并发送正确 SNI,每次重定向都重新检查目标;
- 用网络策略阻断 metadata、管理网和不必要内网;
- 限制响应大小、类型、时间、重定向数与并发;
- fetcher 不携带调用方 Cookie、云凭据和内部认证头;
- 记录最终 IP、域名、响应大小和拒绝原因。
域名 allowlist 比任意 URL 好,但仍要处理被接管子域、DNS 变化和供应商 redirect。只用正则拒绝 127.0.0.1 会漏掉 IPv6、整数 IP 和解析后的私网地址。
Webhook 需要反向的边界控制
发送 webhook 时,目标 URL 带来 SSRF 风险;接收 webhook 时,伪造与重放成为主要风险。接收端应按发送方协议验证原始 body 字节上的 HMAC/签名,以及受签名保护的时间戳和 event ID。只有协议明确规定 canonicalization 时才使用该规则;“规范化原始 body”不能由接收端自行发明。
不要先 JSON parse 再重新序列化验签,不同空白、字段顺序和数值表示会改变字节。HMAC 使用恒定时间比较,并限制重放窗口。验证成功后,在同一事务中插入带唯一约束的 event ID 和待处理工作(或 outbox 记录),再确认接收;先记幂等键、后入队而没有原子性,可能在崩溃后永远丢掉事件。消费者仍须把业务副作用做成可幂等重试,重复投递不能变成重复扣款。错误响应不泄露签名比较细节。
安全响应头缩小浏览器攻击面
根据产品使用:
Content-Type: application/json
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: frame-ancestors 'none'HSTS 只有在确认整个域及所选子域长期支持 HTTPS、具备证书应急能力后才逐步启用;错误的长周期 includeSubDomains 会造成持久可用性事故。
边界测试矩阵
CSRF:跨站表单、fetch、同站恶意子域、无/错 token、异常 Origin
CORS:允许/拒绝 origin、null origin、credentials、缓存 Vary
SSRF:IPv4/IPv6 私网、redirect、DNS 变化、metadata、超大响应
Webhook:签名篡改、过期时间、重复 event、body 编码差异下一章假设攻击者已通过应用漏洞拿到进程执行权,检查操作系统还能施加哪些限制。
参考资料
- OWASP, CSRF Prevention Cheat Sheet
- Fetch Standard, CORS protocol
- OWASP, SSRF Prevention Cheat Sheet
- OWASP, HTTP Headers Cheat Sheet