CORS 和 CSRF 分别解决什么问题

遇到“跨域报错”时,容易把 CORS、登录状态和 CSRF 当成同一个问题。实际上,它们位于不同层次。弄清浏览器做了什么、服务器收到了什么,通常比先修改一组响应头更有效。

本篇目标: 区分跨源读取策略与跨站请求伪造防护,避免错误地把一种机制当成另一种保护。

两个机制,观察的不是同一个问题
两个机制,观察的不是同一个问题放大图解 ↗

CORS 主要影响脚本能否读取

CORS 是浏览器实施的跨源资源共享机制。服务器通过响应头表达允许哪些源以及相关条件,浏览器据此决定是否把响应交给脚本。某些请求会先进行预检,另一些请求则可能直接发出。MDN:CORS

因此,脚本无法读取响应,不代表服务器没有收到请求。也不能指望 CORS 阻止独立 HTTP 客户端调用接口;业务身份与权限仍需要服务器自己检查。

CSRF 关注带身份的非预期操作

如果浏览器会自动附带身份凭据,攻击页面可能尝试诱导它发出用户没有主动确认的操作。防护需要结合认证方式和请求路径设计,例如校验专用令牌、核对来源信息,以及合理设置 Cookie 属性。

这些措施需要在服务器端执行,不能只靠前端页面隐藏按钮。只读动作和写动作也应保持清楚语义,避免一个看似浏览链接的请求产生重要修改。

排错时分开检查

先观察请求是否到达服务器,是否发生 OPTIONS 预检,再看身份凭据是否按预期发送,最后检查服务端具体拒绝原因。不要为了消除控制台错误,直接允许任意源携带凭据访问。

请求是否发出?
服务器如何认证和授权?
服务器如何验证操作来源?
浏览器是否允许脚本读取响应?

这四个问题可以分别成立,不能用一个 200 状态码或者一条跨域报错代替全部判断。

做一个可重复的小实验

在两个不同源的测试页面间发出只读和写入请求,分别观察网络面板、服务端记录与脚本可见结果。使用完全虚构的测试账号和数据,记录每种凭据策略下的行为。

当观察顺序足够清楚,就能判断该调整共享策略、修正认证配置,还是补上请求伪造防护,而不是在响应头中不断添加字段碰运气。

见字如晤

图解