在本节中,咱们将解释什么是跨站请求伪造,并描述一些常见的 CSRF
漏洞示例,同时说明如何防护 CSRF
攻击。html
跨站请求伪造(CSRF
)是一种 web 安全漏洞,它容许攻击者诱使用户执行他们不想执行的操做。攻击者进行 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 的网页:cookie
<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>
若是受害用户访问了攻击者的网页,将发生如下状况:session
注意:虽然 CSRF
一般是根据基于 cookie 的会话处理来描述的,但它也出如今应用程序自动向请求添加一些用户凭据的上下文中,例如 HTTP Basic authentication 基本验证和 certificate-based authentication 基于证书的身份验证。并发
手动建立 CSRF
攻击所需的 HTML 可能很麻烦,尤为是在所需请求包含大量参数的状况下,或者在请求中存在其余异常状况时。构造 CSRF
攻击的最简单方法是使用 Burp Suite Professional
(付费软件) 中的 CSRF PoC generator
。app
跨站请求伪造攻击的传递机制与反射型 XSS 的传递机制基本相同。一般,攻击者会将恶意 HTML 放到他们控制的网站上,而后诱使受害者访问该网站。这能够经过电子邮件或社交媒体消息向用户提供指向网站的连接来实现。或者,若是攻击被放置在一个流行的网站(例如,在用户评论中),则只需等待用户上钩便可。
请注意,一些简单的 CSRF
攻击使用 GET 方法,而且能够经过易受攻击网站上的单个 URL 彻底自包含。在这种状况下,攻击者可能不须要使用外部站点,而且能够直接向受害者提供易受攻击域上的恶意 URL 。在前面的示例中,若是可使用 GET 方法执行更改电子邮件地址的请求,则自包含的攻击以下所示:

防护 CSRF
攻击最有效的方法就是在相关请求中使用 CSRF token
,此 token
应该是:
可与 CSRF token
一块儿使用的附加防护措施是 SameSite cookies
。
最有趣的 CSRF
漏洞产生是由于对 CSRF token
的验证有问题。
在前面的示例中,假设应用程序在更改用户密码的请求中须要包含一个 CSRF token
:
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 方法时正确验证 token ,但在使用 GET 方法时跳过了验证。
在这种状况下,攻击者能够切换到 GET 方法来绕过验证并发起 CSRF
攻击:
GET /email/change?email=pwned@evil-user.net HTTP/1.1 Host: vulnerable-website.com Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
某些应用程序在 token 存在时正确地验证它,可是若是 token 不存在,则跳过验证。
在这种状况下,攻击者能够删除包含 token 的整个参数,从而绕过验证并发起 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
有些应用程序不验证 token 是否与发出请求的用户属于同一会话。相反,应用程序维护一个已发出的 token 的全局池,并接受该池中出现的任何 token 。
在这种状况下,攻击者可使用本身的账户登陆到应用程序,获取有效 token ,而后在 CSRF
攻击中使用本身的 token 。
在上述漏洞的变体中,有些应用程序确实将 CSRF token
绑定到了 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 的行为,则可能发生攻击。攻击者可使用本身的账户登陆到应用程序,获取有效的 token 和关联的 cookie ,利用 cookie 设置行为将其 cookie 放入受害者的浏览器中,并在 CSRF
攻击中向受害者提供 token 。
注意:cookie 设置行为甚至没必要与 CSRF
漏洞存在于同一 Web 应用程序中。若是所控制的 cookie 具备适当的范围,则能够利用同一整体 DNS 域中的任何其余应用程序在目标应用程序中设置 cookie 。例如,staging.demo.normal-website.com
域上的 cookie 设置函数能够放置提交到 secure.normal-website.com
上的 cookie 。
在上述漏洞的进一步变体中,一些应用程序不维护已发出 token 的任何服务端记录,而是在 cookie 和请求参数中复制每一个 token 。在验证后续请求时,应用程序只需验证在请求参数中提交的 token 是否与在 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
攻击。在这里,攻击者不须要得到本身的有效 token 。他们只需发明一个 token ,利用 cookie 设置行为将 cookie 放入受害者的浏览器中,并在 CSRF
攻击中向受害者提供此 token 。
除了使用 CSRF token
进行防护以外,有些应用程序使用 HTTP Referer
头去防护 CSRF
攻击,一般是验证请求来自应用程序本身的域名。这种方法一般不太有效,并且常常会被绕过。
注意:HTTP Referer
头是一个可选的请求头,它包含连接到所请求资源的网页的 URL 。一般,当用户触发 HTTP 请求时,好比单击连接或提交表单,浏览器会自动添加它。然而存在各类方法,容许连接页面保留或修改 Referer
头的值。这一般是出于隐私考虑。
某些应用程序当请求中有 Referer
头时会验证它,可是若是没有的话,则跳过验证。
在这种状况下,攻击者能够精心设计其 CSRF
攻击,使受害用户的浏览器在请求中丢弃 Referer
头。实现这一点有多种方法,但最简单的是在托管 CSRF
攻击的 HTML 页面中使用 META 标记:
<meta name="referrer" content="never">
某些应用程序以一种能够被绕过的方式验证 Referer
头。例如,若是应用程序只是验证 Referer
是否包含本身的域名,那么攻击者能够将所需的值放在 URL 的其余位置:
http://attacker-website.com/csrf-attack?vulnerable-website.com
若是应用程序验证 Referer
中的域以预期值开头,那么攻击者能够将其做为本身域的子域:
http://vulnerable-website.com.attacker-website.com/csrf-attack
在本节中,咱们将解释什么是 CSRF token,它们是如何防护的 CSRF 攻击,以及如何生成和验证CSRF token 。
CSRF token 是一个惟一的、秘密的、不可预测的值,它由服务端应用程序生成,并以这种方式传输到客户端,使得它包含在客户端发出的后续 HTTP 请求中。当发出后续请求时,服务端应用程序将验证请求是否包含预期的 token ,并在 token 丢失或无效时拒绝该请求。
因为攻击者没法肯定或预测用户的 CSRF token 的值,所以他们没法构造出一个应用程序验证所需所有参数的请求。因此 CSRF token 能够防止 CSRF 攻击。
CSRF token 应该包含显著的熵,而且具备很强的不可预测性,其一般与会话令牌具备相同的特性。
您应该使用加密强度伪随机数生成器(PRNG),该生成器附带建立时的时间戳以及静态密码。
若是您须要 PRNG 强度以外的进一步保证,能够经过将其输出与某些特定于用户的熵链接来生成单独的令牌,并对整个结构进行强哈希。这给试图分析令牌的攻击者带来了额外的障碍。
CSRF token 应被视为机密,并在其整个生命周期中以安全的方式进行处理。一种一般有效的方法是将令牌传输到使用 POST 方法提交的 HTML 表单的隐藏字段中的客户端。提交表单时,令牌将做为请求参数包含:
<input type="hidden" name="csrf-token" value="CIwNZNlR4XbisJF39I8yWnWX9wX4WFoz" />
为了安全起见,包含 CSRF token 的字段应该尽早放置在 HTML 文档中,最好是在任何非隐藏的输入字段以前,以及在 HTML 中嵌入用户可控制数据的任何位置以前。这能够对抗攻击者使用精心编制的数据操纵 HTML 文档并捕获其部份内容的各类技术。
另外一种方法是将令牌放入 URL query 字符串中,这种方法的安全性稍差,由于 query 字符串:
某些应用程序在自定义请求头中传输 CSRF token 。这进一步防止了攻击者预测或捕获另外一个用户的令牌,由于浏览器一般不容许跨域发送自定义头。然而,这种方法将应用程序限制为使用 XHR 发出受 CSRF 保护的请求(与 HTML 表单相反),而且在许多状况下可能被认为过于复杂。
CSRF token 不该在 cookie 中传输。
当生成 CSRF token 时,它应该存储在服务器端的用户会话数据中。当接收到须要验证的后续请求时,服务器端应用程序应验证该请求是否包含与存储在用户会话中的值相匹配的令牌。不管请求的HTTP 方法或内容类型如何,都必须执行此验证。若是请求根本不包含任何令牌,则应以与存在无效令牌时相同的方式拒绝请求。
在本节中,咱们将解释 XSS
和 CSRF
之间的区别,并讨论 CSRF token
是否有助于防护 XSS
攻击。
跨站脚本攻击 XSS
容许攻击者在受害者用户的浏览器中执行任意 JavaScript 。
跨站请求伪造 CSRF
容许攻击者伪造受害用户执行他们不打算执行的操做。
XSS
漏洞的后果一般比 CSRF
漏洞更严重:
CSRF
一般只适用于用户可以执行的操做的子集。一般,许多应用程序都实现 CSRF
防护,可是忽略了暴露的一两个操做。相反,成功的 XSS
攻击一般能够执行用户可以执行的任何操做,而无论该漏洞是在什么功能中产生的。CSRF
能够被描述为一个“单向”漏洞,由于尽管攻击者能够诱导受害者发出 HTTP 请求,但他们没法从该请求中检索响应。相反,XSS
是“双向”的,由于攻击者注入的脚本能够发出任意请求、读取响应并将数据传输到攻击者选择的外部域。一些 XSS
攻击确实能够经过有效使用 CSRF token
来进行防护。假设有一个简单的反射型 XSS
漏洞,其能够被利用以下:
https://insecure-website.com/status?message=<script>/*+Bad+stuff+here...+*/</script>
如今,假设漏洞函数包含一个 CSRF token
:
https://insecure-website.com/status?csrf-token=CIwNZNlR4XbisJF39I8yWnWX9wX4WFoz&message=<script>/*+Bad+stuff+here...+*/</script>
若是服务器正确地验证了 CSRF token
,并拒绝了没有有效令牌的请求,那么该令牌确实能够防止此 XSS 漏洞的利用。这里的关键点是“跨站脚本”的攻击中涉及到了跨站请求,所以经过防止攻击者伪造跨站请求,该应用程序可防止对 XSS
漏洞的轻度攻击。
这里有一些重要的注意事项:
XSS
漏洞存在于站点上任何其余不受 CSRF token
保护的函数内,则能够以常规方式利用该 XSS
漏洞。XSS
漏洞,则能够利用该漏洞使受害用户执行操做,即便这些操做自己受到 CSRF token
的保护。在这种状况下,攻击者的脚本能够请求相关页面获取有效的 CSRF token
,而后使用该令牌执行受保护的操做。CSRF token
不保护存储型 XSS
漏洞。若是受 CSRF token
保护的页面也是存储型 XSS
漏洞的输出点,则能够以一般的方式利用该 XSS
漏洞,而且当用户访问该页面时,将执行 XSS
有效负载。某些网站使用 SameSite cookies 防护 CSRF
攻击。
这个 SameSite
属性可用于控制是否以及如何在跨站请求中提交 cookie 。经过设置会话 cookie 的属性,应用程序能够防止浏览器默认自动向请求添加 cookie 的行为,而无论cookie 来自何处。
这个 SameSite
属性在服务器的 Set-Cookie
响应头中设置,该属性能够设为 Strict
严格或者 Lax
松懈。例如:
SetCookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Strict; SetCookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Lax;
若是 SameSite
属性设置为 Strict
,则浏览器将不会在来自其余站点的任何请求中包含cookie。这是最具防护性的选择,但它可能会损害用户体验,由于若是登陆的用户经过第三方连接访问某个站点,那么他们将不会登陆,而且须要从新登陆,而后才能以正常方式与站点交互。
若是 SameSite
属性设置为 Lax
,则浏览器将在来自另外一个站点的请求中包含cookie,但前提是知足如下两个条件:
使用 SameSite
的 Lax
模式确实对 CSRF
攻击提供了部分防护,由于 CSRF
攻击的目标用户操做一般使用 POST 方法实现。这里有两个重要的注意事项:
出于上述缘由,不建议仅依赖 SameSite
Cookie 来抵御 CSRF
攻击。当其与 CSRF token
结合使用时,SameSite
cookies 能够提供额外的防护层,并减轻基于令牌的防护中的任何缺陷。