关于javascript:Web-安全-之-CSRF

8次阅读

共计 8362 个字符,预计需要花费 21 分钟才能阅读完成。

Cross-site request forgery (CSRF)

在本节中,咱们将解释什么是跨站申请伪造,并形容一些常见的 CSRF 破绽示例,同时阐明如何进攻 CSRF 攻打。

什么是 CSRF

跨站申请伪造(CSRF)是一种 web 安全漏洞,它容许攻击者诱使用户执行他们不想执行的操作。攻击者进行 CSRF 可能局部躲避同源策略。

CSRF 攻打能造成什么影响

在胜利的 CSRF 攻打中,攻击者会使受益用户无心中执行某个操作。例如,这可能是更改他们帐户上的电子邮件地址、更改明码或进行资金转账。依据操作的性质,攻击者可能可能齐全管制用户的帐户。如果受益用户在应用程序中具备特权角色,则攻击者可能可能齐全控制应用程序的所有数据和性能。

CSRF 是如何工作的

要使 CSRF 攻打成为可能,必须具备三个要害条件:

  • 相干的动作。攻击者有理由诱使应用程序中产生某种动作。这可能是特权操作(例如批改其余用户的权限),也可能是针对用户特定数据的任何操作(例如更改用户本人的明码)。
  • 基于 Cookie 的会话解决。执行该操作波及收回一个或多个 HTTP 申请,应用程序仅依赖会话 cookie 来标识发出请求的用户。没有其余机制用于跟踪会话或验证用户申请。
  • 没有不可预测的申请参数。执行该操作的申请不蕴含攻击者无奈确定或猜想其值的任何参数。例如,当导致用户更改明码时,如果攻击者须要晓得现有明码的值,则该性能不会受到攻打。

假如应用程序蕴含一个容许用户更改其邮箱地址的性能。当用户执行此操作时,会收回如下 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 要求的条件:

  • 更改用户帐户上的邮箱地址的操作会引起攻击者的趣味。执行此操作后,攻击者通常可能触发明码重置并齐全管制用户的帐户。
  • 应用程序应用会话 cookie 来标识发出请求的用户。没有其余标记或机制来跟踪用户会话。
  • 攻击者能够轻松确定执行操作所需的申请参数的值。

具备这些条件后,攻击者能够构建蕴含以下 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>

如果受益用户拜访了攻击者的网页,将产生以下状况:

  • 攻击者的页面将触发对易受攻击的网站的 HTTP 申请。
  • 如果用户登录到易受攻击的网站,其浏览器将主动在申请中蕴含其会话 cookie(假如 SameSite cookies 未被应用)。
  • 易受攻击的网站将以失常形式解决申请,将其视为受害者用户收回的申请,并更改其电子邮件地址。

留神:尽管 CSRF 通常是依据基于 cookie 的会话解决来形容的,但它也呈现在应用程序主动向申请增加一些用户凭据的上下文中,例如 HTTP Basic authentication 根本验证和 certificate-based authentication 基于证书的身份验证。

如何结构 CSRF 攻打

手动创立 CSRF 攻打所需的 HTML 可能很麻烦,尤其是在所需申请蕴含大量参数的状况下,或者在申请中存在其余异常情况时。结构 CSRF 攻打的最简略办法是应用 Burp Suite Professional(付费软件)中的 CSRF PoC generator

如何传递 CSRF

跨站申请伪造攻打的传递机制与反射型 XSS 的传递机制基本相同。通常,攻击者会将歹意 HTML 放到他们管制的网站上,而后诱使受害者拜访该网站。这能够通过电子邮件或社交媒体音讯向用户提供指向网站的链接来实现。或者,如果攻打被搁置在一个风行的网站(例如,在用户评论中),则只需期待用户上钩即可。

请留神,一些简略的 CSRF 攻打应用 GET 办法,并且能够通过易受攻击网站上的单个 URL 齐全自蕴含。在这种状况下,攻击者可能不须要应用内部站点,并且能够间接向受害者提供易受攻击域上的歹意 URL。在后面的示例中,如果能够应用 GET 办法执行更改电子邮件地址的申请,则自蕴含的攻打如下所示:

![](https://vulnerable-website.com/email/change?email=pwned@evil-user.net)

进攻 CSRF 攻打

进攻 CSRF 攻打最无效的办法就是在相干申请中应用 CSRF token,此 token 应该是:

  • 不可预测的,具备高熵的
  • 绑定到用户的会话中
  • 在相干操作执行前,严格验证每种状况

可与 CSRF token 一起应用的附加进攻措施是 SameSite cookies

常见的 CSRF 破绽

最乏味的 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 的攻打。

CSRF token 的验证依赖于申请办法

某些应用程序在申请应用 POST 办法时正确验证 token,但在应用 GET 办法时跳过了验证。

在这种状况下,攻击者能够切换到 GET 办法来绕过验证并发动 CSRF 攻打:

GET /email/change?email=pwned@evil-user.net HTTP/1.1
Host: vulnerable-website.com
Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm

CSRF token 的验证依赖于 token 是否存在

某些应用程序在 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

CSRF token 未绑定到用户会话

有些应用程序不验证 token 是否与发出请求的用户属于同一会话。相同,应用程序保护一个已收回的 token 的全局池,并承受该池中呈现的任何 token。

在这种状况下,攻击者能够应用本人的帐户登录到应用程序,获取无效 token,而后在 CSRF 攻打中应用本人的 token。

CSRF token 被绑定到非会话 cookie

在上述破绽的变体中,有些应用程序的确将 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。

CSRF token 仅要求与 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。

基于 Referer 的 CSRF 进攻

除了应用 CSRF token 进行进攻之外,有些应用程序应用 HTTP Referer 头去进攻 CSRF 攻打,通常是验证申请来自应用程序本人的域名。这种办法通常不太无效,而且常常会被绕过。

留神:HTTP Referer 头是一个可选的申请头,它蕴含链接到所申请资源的网页的 URL。通常,当用户触发 HTTP 申请时,比方单击链接或提交表单,浏览器会主动增加它。然而存在各种办法,容许链接页面保留或批改 Referer 头的值。这通常是出于隐衷思考。

Referer 的验证依赖于其是否存在

某些应用程序当申请中有 Referer 头时会验证它,然而如果没有的话,则跳过验证。

在这种状况下,攻击者能够精心设计其 CSRF 攻打,使受益用户的浏览器在申请中抛弃 Referer 头。实现这一点有多种办法,但最简略的是在托管 CSRF 攻打的 HTML 页面中应用 META 标记:

<meta name="referrer" content="never">

Referer 的验证能够被躲避

某些应用程序以一种能够被绕过的形式验证 Referer 头。例如,如果应用程序只是验证 Referer 是否蕴含本人的域名,那么攻击者能够将所需的值放在 URL 的其余地位:

http://attacker-website.com/csrf-attack?vulnerable-website.com

如果利用程序验证 Referer 中的域以预期值结尾,那么攻击者能够将其作为本人域的子域:

http://vulnerable-website.com.attacker-website.com/csrf-attack

CSRF tokens

在本节中,咱们将解释什么是 CSRF token,它们是如何进攻的 CSRF 攻打,以及如何生成和验证 CSRF token。

什么是 CSRF token

CSRF token 是一个惟一的、机密的、不可预测的值,它由服务端应用程序生成,并以这种形式传输到客户端,使得它蕴含在客户端收回的后续 HTTP 申请中。当收回后续申请时,服务端应用程序将验证申请是否蕴含预期的 token,并在 token 失落或有效时回绝该申请。

因为攻击者无奈确定或预测用户的 CSRF token 的值,因而他们无奈结构出一个利用程序验证所需全副参数的申请。所以 CSRF token 能够避免 CSRF 攻打。

CSRF token 应该如何生成

CSRF token 应该蕴含显著的熵,并且具备很强的不可预测性,其通常与会话令牌具备雷同的个性。

您应该应用加密强度伪随机数生成器(PRNG),该生成器附带创立时的工夫戳以及动态明码。

如果您须要 PRNG 强度之外的进一步保障,能够通过将其输入与某些特定于用户的熵连贯来生成独自的令牌,并对整个构造进行强哈希。这给试图剖析令牌的攻击者带来了额定的阻碍。

如何传输 CSRF token

CSRF token 应被视为秘密,并在其整个生命周期中以平安的形式进行解决。一种通常无效的办法是将令牌传输到应用 POST 办法提交的 HTML 表单的暗藏字段中的客户端。提交表单时,令牌将作为申请参数蕴含:

<input type="hidden" name="csrf-token" value="CIwNZNlR4XbisJF39I8yWnWX9wX4WFoz" />

为了平安起见,蕴含 CSRF token 的字段应该尽早搁置在 HTML 文档中,最好是在任何非暗藏的输出字段之前,以及在 HTML 中嵌入用户可控制数据的任何地位之前。这能够反抗攻击者应用精心编制的数据操纵 HTML 文档并捕捉其局部内容的各种技术。

另一种办法是将令牌放入 URL query 字符串中,这种办法的安全性稍差,因为 query 字符串:

  • 记录在客户端和服务器端的各个地位;
  • 容易在 HTTP Referer 头中传输给第三方;
  • 能够在用户的浏览器中显示在屏幕上。

某些应用程序在自定义申请头中传输 CSRF token。这进一步避免了攻击者预测或捕捉另一个用户的令牌,因为浏览器通常不容许跨域发送自定义头。然而,这种办法将应用程序限度为应用 XHR 收回受 CSRF 爱护的申请(与 HTML 表单相同),并且在许多状况下可能被认为过于简单。

CSRF token 不应在 cookie 中传输。

如何验证 CSRF token

当生成 CSRF token 时,它应该存储在服务器端的用户会话数据中。当接管到须要验证的后续申请时,服务器端应用程序应验证该申请是否蕴含与存储在用户会话中的值相匹配的令牌。无论申请的 HTTP 办法或内容类型如何,都必须执行此验证。如果申请基本不蕴含任何令牌,则应以与存在有效令牌时雷同的形式拒绝请求。


XSS vs CSRF

在本节中,咱们将解释 XSSCSRF 之间的区别,并探讨 CSRF token 是否有助于进攻 XSS 攻打。

XSS 和 CSRF 之间有啥区别

跨站脚本攻打 XSS 容许攻击者在受害者用户的浏览器中执行任意 JavaScript。

跨站申请伪造 CSRF 容许攻击者伪造受益用户执行他们不打算执行的操作。

XSS 破绽的结果通常比 CSRF 破绽更重大:

  • CSRF 通常只实用于用户可能执行的操作的子集。通常,许多应用程序都实现 CSRF 进攻,然而疏忽了裸露的一两个操作。相同,胜利的 XSS 攻打通常能够执行用户可能执行的任何操作,而不论该破绽是在什么性能中产生的。
  • CSRF 能够被形容为一个“单向”破绽,因为只管攻击者能够诱导受害者收回 HTTP 申请,但他们无奈从该申请中检索响应。相同,XSS 是“双向”的,因为攻击者注入的脚本能够收回任意申请、读取响应并将数据传输到攻击者抉择的内部域。

CSRF token 是否进攻 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

某些网站应用 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,但前提是满足以下两个条件:

  • 申请应用 GET 办法。应用其余办法(如 POST)的申请将不会包含 cookie。
  • 申请是由用户的顶级导航(如单击链接)产生的。其余申请(如由脚本启动的申请)将不会包含 cookie。

应用 SameSiteLax 模式的确对 CSRF 攻打提供了局部进攻,因为 CSRF 攻打的指标用户操作通常应用 POST 办法实现。这里有两个重要的注意事项:

  • 有些应用程序的确应用 GET 申请实现敏感操作。
  • 许多应用程序和框架可能容忍不同的 HTTP 办法。在这种状况下,即便应用程序自身设计应用的是 POST 办法,但它实际上也会承受被切换为应用 GET 办法的申请。

出于上述起因,不倡议仅依赖 SameSite Cookie 来抵挡 CSRF 攻打。当其与 CSRF token 联合应用时,SameSite cookies 能够提供额定的进攻层,并加重基于令牌的进攻中的任何缺点。

正文完
 0