那个的真实意义是什么?你能给我一个现实生活中的例子吗?
攻击示例 1:使用 HTML 表单的跨站请求伪造 (CSRF)
在evil.com
攻击者的页面上放了:
<form method="post" action="http://bank.com/trasfer">
<input type="hidden" name="to" value="ciro">
<input type="hidden" name="ammount" value="100000000">
<input type="submit" value="CLICK TO CLAIM YOUR PRIZE!!!">
</form>
没有进一步的安全措施:
- 请求确实被发送。SOP 不禁止发送此请求。
- 它包括您从中登录的身份验证 cookie
bank.com
。如“是否禁止所有跨域请求?”中所述。例如,跨域发送 cookie 允许您单击<a
链接bank.com
并转到已登录的网站,这是用户通常想要的。
它是同步器令牌模式,单独,即使没有 SOP,也阻止了它的工作。
同步器令牌模式
对于 上的每一个表单bank.com
,开发者都会生成一个一次性随机序列作为隐藏参数,并且只有在服务器获取到参数时才接受请求。
例如,Rails 的 HTML 助手会自动向 HTML 添加一个authenticity_token
参数,因此合法的表单如下所示:
<form action="http://bank.com/transfer" method="post">
<p><input type="hidden" name="authenticity_token"
value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
<p><input type="hidden" name="to" value="ciro"></p>
<p><input type="hidden" name="ammount" value="100000000"></p>
<p><button type="submit">Send 100000000$ to Ciro.</button></p>
</form>
如所述:https : //stackoverflow.com/questions/941594/understanding-the-rails-authenticity-token/26895980#26895980
因此,如果evil.com
发出一个单一的请求,他们永远不会猜到那个令牌,服务器会拒绝交易!
另请参阅:OWASP 的同步器令牌模式。
攻击示例 2:使用 JavaScript AJAX 的跨站请求伪造 (CSRF)
但是,是什么阻止了evil.com
使用 JavaScript 发出 2 个请求,就像合法浏览器会做的那样:
- 令牌的 XHR GET
- 包含好令牌的 XHR POST
所以evil.com
会尝试这样的事情(jQuery 因为懒惰):
$.ajax({
url: 'http://bank.com/transfer',
type: "GET",
xhrFields: {withCredentials: true},
});
// Parse HTML reply and extract token.
$.ajax({
url: 'http://bank.com/transfer',
type: "POST",
data: {
to: 'ciro',
ammount: '100000000',
authenticity_token: extracted_token
},
xhrFields: {withCredentials: true},
});
攻击者在这里使用withCredentials: true
,因为没有它 XHR 不会发送交叉请求 cookie,另请参阅:为什么 cookie 与 HTML 页面的跨域请求一起发送,但不与 JS 的 XHR 一起发送?
这就是 SOP 发挥作用的地方。尽管GET 和 POST 实际上确实像 HTML 表单一样发送经过身份验证的请求,但发送者的浏览器阻止 JavaScript 代码读取 HTML 回复,因为请求被发送到单独的域!
Chromium 开发者控制台显示一个错误类型:
从源“http://evil.com”访问“http://bank.com”中的 XMLHttpRequest 已被 CORS 策略阻止:请求的资源上不存在“Access-Control-Allow-Origin”标头。
已在以下位置询问:https ://stackoverflow.com/questions/20035101/why-does-my-javascript-code-get-a-no-access-control-allow-origin-header-is-pr
为什么不直接发送交叉请求 cookie 呢?
如果实现有这样的规则:“允许任何请求,但只在当前域 XHR 上发送 cookie”怎么办?那不是更简单吗?
但这仍然允许另一种类型的攻击:当身份验证不是基于 cookie,而是基于请求的源 (IP) 时!
例如,您在公司的 Intranet 中,您可以从那里访问内部服务器,该服务器从外部不可见并提供秘密数据。
是否禁止所有跨域请求?
即使忘记 CORS,不,我们每天都在做!
唯一不能允许的就是在 JavaScript 中读回此类请求的结果,因为这会击败同步器令牌模式。
来自MDN:
通常允许跨域写入:链接、重定向和表单提交。
[我的评论]:例如,当您单击链接时,您通常希望登录到该网站,这需要发出经过身份验证的 GET 请求以返回新页面。
通常允许跨域嵌入:图像、外部 CSS 和 Javascript、iframe。
通常不允许跨域读取:XHR(上面的示例),iframe
读取。
但是,读取访问权限通常会因嵌入而泄露。例如,您可以读取嵌入图像的宽度和高度、嵌入脚本的操作或嵌入资源的可用性(因此可能会在用户登录或未登录给定域的情况下)
其他预防方法
- 检查是否存在某些标题,例如
X-Requested-With
:
- 检查
Origin
标头的值:为什么同步器令牌模式优先于源标头检查以防止 CSRF
- 重新认证:再次询问用户密码。对于每个关键操作(银行登录和汇款、大多数网站的密码更改)都应该这样做,以防您的网站被 XSSed。缺点是用户必须多次输入密码,这很烦人,并且增加了键盘记录/肩冲浪的机会。
其他预防方法:智威汤逊
JSON Web Token是 2020 年左右 cookie + 同步器令牌模式的相当流行的替代方案。
这个方法的作用是:
- 将签名令牌存储在
window.localStorage
- 每当您想向服务器发出经过身份验证的请求时,请发送一个 header
Authentication: <token>
。请注意,这只能通过 JavaScript 完成。
此方法之所以有效,是因为与 cookie 不同,localStorage
它仅在您从网站本身(通过 JavaScript)发出请求时可用,从而分配同步器令牌。
然后,当用户第一次访问该网站时,他们最初会被注销,并显示一个虚拟加载页面。
然后浏览器运行刚刚从服务器接收到的 JavaScript,读取localStorage
(现在我们已经在正确的域中)并向 API 路径发送经过身份验证的 GET 请求,以仅获取没有 HTML 的数据,通常为 JSON。
最后,JavaScript 在浏览器上呈现该数据。
由于单页应用程序的流行,这种方法变得特别流行,其中最简单的实现方法是这个两步获取虚拟页面,然后用 API 数据填充它。
所以这基本上进行了权衡:
- 好处:
- 更容易实现,因为每个表单上都没有同步器
- 通常的 SPA 优势:在初始请求后您只获得数据,而不是 HTML 标记
- 缺点:
- 通常的SPA缺点:
- 在第一次加载期间,用户可能会看到令人讨厌的加载虚拟页面元素
- 没有 JavaScript 网站是不可见的
也可以看看