在本节中,我们将解释什么是跨站点请求伪造,描述一些常见CSRF漏洞的示例,并解释如何防止CSRF攻击。
跨站点请求伪造(也称为CSRF)是一个web安全漏洞,攻击者可以利用该漏洞诱使用户执行他们不打算执行的操作。 它允许攻击者部分规避同一原始策略,该策略旨在防止不同的网站相互干扰。
在成功的CSRF攻击中,攻击者会导致受害者用户无意中执行操作。 例如,这可能是更改其帐户上的电子邮件地址,更改其密码或进行资金转帐。 根据操作的性质,攻击者可能会完全控制用户的帐户。 如果受感染的用户在应用程序中具有特权角色,则攻击者可能能够完全控制所有应用程序的数据和功能。
为了使CSRF攻击成为可能,必须具备三个关键条件:
例如,假设一个应用程序包含一个功能,该功能使用户可以更改其帐户上的电子邮件地址。 用户执行此操作时,将发出如下HTTP请求:
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
email=wiener@normal-user.com
这符合CSRF所需的条件:
在满足这些条件的情况下,攻击者可以构建一个包含以下HTML的网页:
<html>
<body>
<form action="https://vulnerable-website.com/email/change" method="POST">
<input type="hidden" name="email" value="pwned@evil-user.net" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
如果受害用户访问攻击者的网页,则会发生以下情况:
手动创建CSRF攻击所需的HTML可能很麻烦,特别是在所需的请求包含大量参数或请求中存在其他异常的情况下。 构造CSRF漏洞最简单的方法是使用Burp Suite Professional内置的CSRF PoC生成器:
跨站点请求伪造攻击的传递机制与反射的XSS基本上相同。 通常,攻击者会将恶意HTML放到他们控制的网站上,然后诱使受害者访问该网站。 这可以通过电子邮件或社交媒体消息向用户提供指向网站的链接来完成。 或者,如果将攻击置于流行的网站中(例如,在用户评论中),他们可能只是在等待用户访问该网站。
请注意,一些简单的CSRF漏洞利用GET方法,并且可以通过易受攻击的网站上的单个URL完全自包含。 在这种情况下,攻击者可能不需要使用外部站点,并且可以在易受攻击的域上直接向受害者提供恶意URL。 在前面的示例中,如果可以使用GET方法执行更改电子邮件地址的请求,则自包含式攻击将如下所示:
<img src="https://vulnerable-website.com/email/change?email=pwned@evil-user.net">
防御CSRF攻击的最可靠方法是在相关请求中包含CSRF令牌。 令牌应为:
SameSite cookie是对CSRF部分有效的另一种防御措施,可以与CSRF令牌结合使用。
最有趣的CSRF漏洞是由CSRF令牌验证中的错误引起的。
在前面的示例中,假设应用程序现在在更改用户密码的请求中包含CSRF令牌:
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
csrf=WfF1szMUHhiokx9AHFply5L2xAOfjRkE&email=wiener@normal-user.com
这应该防止CSRF攻击,因为它违反了CSRF漏洞的必要条件:应用程序不再仅依赖cookie进行会话处理,并且请求包含一个参数,攻击者无法确定其值。 但是,可以通过多种方式来打破防御,这意味着该应用程序仍然容易受到CSRF的攻击。
当请求使用POST方法时,某些应用程序正确地验证了令牌,但是当使用GET方法时,跳过了验证。
在这种情况下,攻击者可以切换到GET方法来绕过验证并发送CSRF攻击:
GET /email/change?email=pwned@evil-user.net HTTP/1.1
Host: vulnerable-website.com
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
如果令牌存在,某些应用程序会正确验证令牌,但是如果省略令牌,则跳过验证。
在这种情况下,攻击者可以删除包含令牌的整个参数(而不仅仅是令牌的值),以绕过验证并进行CSRF攻击:
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 25
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
email=pwned@evil-user.net
某些应用程序无法验证令牌与发出请求的用户属于同一会话。 而是,应用程序维护已发出的全局令牌池,并接受该池中显示的所有令牌。
在这种情况下,攻击者可以使用自己的帐户登录到应用程序,获取有效令牌,然后在其CSRF攻击中将该令牌提供给受害用户。
在上述漏洞的一种变体中,某些应用程序确实将CSRF令牌绑定到cookie,但没有绑定到用于跟踪会话的cookie。 当应用程序使用两种不同的框架(未集成在一起)时,很容易发生这种情况:一种用于会话处理,另一种用于CSRF保护。
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=pSJYSScWKpmC60LpFOAHKixuFuM4uXWF; csrfKey=rZHCnSzEp8dbI6atzagGoSYyqJqTz5dv
csrf=RhV7yQDO0xcq9gLEah2WVbmuFqyOq7tY&email=wiener@normal-user.com
这种情况很难利用,但仍然很脆弱。 如果该网站包含允许攻击者在受害者的浏览器中设置cookie的任何行为,则可能构成攻击。 攻击者可以使用自己的帐户登录应用程序,获取有效的令牌和关联的cookie,利用cookie的设置行为将其cookie放入受害者的浏览器中,并在CSRF攻击中将其令牌提供给受害者。
在前述漏洞的另一种变体中,某些应用程序不维护任何已发布令牌的服务器端记录,而是复制cookie和request参数中的每个令牌。 当后续请求得到验证时,应用程序仅验证请求参数中提交的令牌是否与cookie中提交的值匹配。 有时将其称为针对CSRF的“双重提交”防御,之所以被提倡,是因为它易于实现并且避免了任何服务器端状态的需要:
POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa
csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa&email=wiener@normal-user.com
在这种情况下,如果网站包含任何cookie设置功能,则攻击者可以再次执行CSRF攻击。 在这里,攻击者无需获取自己的有效令牌。 他们只是发明了一个令牌(如果正在检查,则可能采用所需的格式),利用cookie设置行为将其cookie置于受害者的浏览器中,并在CSRF攻击中将令牌提供给受害者。
除了采用CSRF令牌的防御措施外,某些应用程序还利用HTTP Referer标头尝试防御CSRF攻击,通常是通过验证请求是否来自应用程序自己的域来进行。 这种方法通常效果较差,并且经常会绕过。
HTTP Referer标头(在HTTP规范中无意中拼写错误)是一个可选的请求标头,其中包含链接到所请求资源的网页的URL。 通常,当用户触发HTTP请求时,浏览器会自动添加它,包括单击链接或提交表单。 存在各种方法,允许链接页面保留或修改Referer标头的值。 通常出于隐私原因这样做。
某些应用程序在请求中存在Referer标头时会对其进行验证,但是如果省略标头,则会跳过验证。
在这种情况下,攻击者可以以导致受害者用户的浏览器在结果请求中删除Referer标头的方式设计CSRF利用。 有多种方法可以实现此目的,但最简单的方法是在承载CSRF攻击的HTML页面中使用META标签:
<meta name="referrer" content="never">
一些应用程序以一种可以绕过简单的方式验证Referer标头。 例如,如果应用程序仅验证引荐来源网址包含其自己的域名,则攻击者可以在URL中的其他位置放置所需的值:
http://attacker-website.com/csrf-attack?vulnerable-website.com
如果应用程序验证了Referer中的域以期望值开头,则攻击者可以将其放置为自己域的子域:
http://vulnerable-website.com.attacker-website.com/csrf-attack