CSRF Token与Session Cookie的区别及访问权限疑问解析
核心区别
存储与传递逻辑不同
Session Cookie由浏览器管理,存在专门的Cookie存储区域,只要请求的目标域名匹配Cookie的设置,浏览器就会自动把Cookie附加到请求头里发给服务器,无需开发者额外处理;而CSRF Token是由服务器生成后嵌入到页面内容里(比如表单的隐藏<input>、页面的JS变量或者自定义请求头),必须由开发者手动在请求中携带(比如表单提交时随字段发送,AJAX请求时放到X-CSRF-Token头里)。同源策略下的访问权限不同
Session Cookie的读取被同源策略限制——第三方网站的脚本无法读取其他域名的Cookie,但浏览器会在跨域请求时自动携带符合条件的Cookie;而CSRF Token完全依赖同源策略保护:它属于目标网站页面的一部分,第三方网站的脚本因为跨域,既不能直接访问目标页面的DOM获取Token,也不能通过跨域请求获取包含Token的页面内容(浏览器会拦截跨域请求的响应读取)。
为什么Session Cookie会被自动携带,而CSRF Token无法被攻击者获取?
关于Session Cookie的自动携带
这是浏览器的默认行为:当用户登录目标网站后,浏览器会保存该域名的Session Cookie。之后不管是用户主动访问目标网站,还是被诱使从恶意网站发起对目标网站的请求(比如自动提交的表单、加载一张指向目标接口的图片),只要Cookie的Domain、Path、SameSite等属性允许跨域携带,浏览器就会自动把Cookie加到请求里。这个过程不需要用户或脚本干预,是浏览器的内置机制。
关于CSRF Token无法被获取的原因
核心就是浏览器的同源策略:攻击者的恶意网站和目标网站属于不同源(域名、协议、端口任意一个不同就算跨域),浏览器会严格限制跨域脚本的权限:
- 恶意脚本不能访问用户当前打开的目标网站页面的DOM——比如不能通过
document.getElementById去读取目标页面里隐藏的Token输入框; - 恶意脚本不能通过AJAX/fetch请求目标网站的页面来获取Token——就算发起了跨域请求,浏览器也会拦截响应内容,不让恶意脚本读取,除非目标网站设置了非常宽松的CORS规则(正常网站绝不会这么做)。
你可能会疑惑:操作是在用户浏览器里进行的,Token就在浏览器里,为什么攻击者拿不到?其实用户浏览器里的目标网站页面和恶意网站页面是完全隔离的两个上下文,恶意脚本只能操作自己页面的内容,碰不到其他域名页面里的任何数据,这就是同源策略的核心作用。
内容的提问来源于stack exchange,提问作者kayrhan

