CSRF(跨站请求伪造)攻击
CSRF 英文全称是 Cross-site request forgery,所以又称为“跨站请求伪造”,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。
CSRF 攻击需要具备三个条件:
- 目标站点存在漏洞;
- 用户要登录过目标站点;
- 黑客需要通过第三方站点发起攻击。
实施 CSRF 攻击的三种方式:
1.自动发起 Get 请求
<!DOCTYPE html>
<html>
<body>
<h1>黑客的站点:CSRF攻击演示</h1>
<img src="https://xxx.xxx.xxx/sendcoin?user=hacker&number=100">
</body>
</html>
黑客将转账的请求接口隐藏在 img 标签内,当该页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,进行转账。
2.自动发起 POST 请求
<!DOCTYPE html>
<html>
<body>
<h1>黑客的站点:CSRF攻击演示</h1>
<form id='hacker-form' action="https://xxx.xxx.xxx/sendcoin" method=POST>
<input type="hidden" name="user" value="hacker" />
<input type="hidden" name="number" value="100" />
</form>
<script> document.getElementById('hacker-form').submit(); </script>
</body>
</html>
使用构建自动提交表单这种方式,也可以自动实现跨站点 POST 数据提交。
3.引诱用户点击链接
用户点击恶意链接,也会实现跨站点请求。
和 XSS 不同的是,CSRF 攻击不需要将恶意代码注入用户的页面,仅仅是利用服务器的漏洞和用户的登录状态来实施攻击。这里说的利用用户登录状态指的是恶意站点其实获取不到源站点的cookie信息,只是冒用。
举例说明:
1.用户A登录某网站B.com的账号,网站B.com返回了该用户的cookie信息。
2.用户A在未退出B.com登录的情况下,不小心进入恶意网站C.com。
3.恶意网站C.com向B.com网站发起转账请求。默认情况下,用户A未退出B.com登录,浏览器中存储B.com站点的cookie,那么浏览器会自动在请求转账中将cookie带上。
4.B.com收到请求之后通过验证发现cookie合法,就会进行转账的操作。
怎么避免CSRF攻击?
1.充分利用好 Cookie 的 SameSite 属性
通常 CSRF 攻击都是从第三方站点发起的,要防止 CSRF 攻击,我们最好能实现从第三方站点发送请求时禁止 Cookie 的发送。因此在浏览器通过不同来源发送 HTTP 请求时,有如下区别:
- 如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键 Cookie 数据到服务器;
- 如果是同一个站点发起的请求,那么就需要保证 Cookie 数据正常发送。
Cookie 中的 SameSite 属性正是解决了这个问题。我们在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项。
SameSite 选项通常有 Strict、Lax 和 None 三个值。
Strict : Strict 最为严格。如果 SameSite 的值是 Strict,那么浏览器会完全禁止第三方Cookie。从上面的例子来说,从C.com发送请求时,那么B.com用户A的cookie是不会发到B.com的服务器上面的。只能从B.com网页发送到B.com的服务器上。
Lax:从第三方站点的链接打开和从第三方站点提交Get 方式的表单会携带 Cookie。但Post请求、通过 img、iframe 等标签加载的 URL,这些场景都不会携带 Cookie。
None: 在任何情况下都会发送 Cookie 数据。
2.验证请求的来源站点
由于 CSRF 攻击大多来自于第三方站点,因此服务器可以禁止来自第三方站点的请求。通过 HTTP 请求头中的 Referer 和 Origin 属性,可以判断请求是否来自第三方站点。
Referer属性: 是 HTTP 请求头中的一个字段,记录了该 HTTP 请求的来源地址。虽然可以通过 Referer 告诉服务器 HTTP 请求的来源,但是有一些场景是不适合将来源URL 暴露给服务器的,因此浏览器提供给开发者一个选项,可以不用上传 Referer 值。
但在服务器端验证请求头中的 Referer 并不是太可靠,因此标准委员会又制定了Origin 属性。
Origin 属性: 通过 XMLHttpRequest、Fecth 发起跨站请求或者通过 Post方法发送请求时,都会带上 Origin 属性。
Origin 属性只包含了域名信息,并没有包含具体的 URL 路径,这是Origin 和 Referer 的一个主要区别。在这里需要补充一点,Origin 的值之所以不包含详细路径信息,是有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器。 因此,服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。
3.CSRF Token
CSRF Token 流程大致分为两步:
- 1.第一步,在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。
- 第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。如果是从第三方站点发出的请求,那么将无法获取到CSRF Token 的值(同源策略的限制),所以即使发出了请求,服务器也会因为 CSRF Token 不正确而拒绝请求。
同源策略可以查看我的:# 浏览器安全之Web页面安全(一)同源策略(Same-origin policy);
XSS攻击可以查看我的:# 浏览器安全之Web页面安全(二)XSS (跨站脚本)攻击
有问题欢迎在评论区指出!相互交流才能一起进步!