How to protect your website and web applications with anti-CSRF tokens

        The most common way to prevent cross-site request forgery attacks (CSRF/XSRF) is to use an anti-CSRF token, which is simply a unique set of values ​​that is then required by the web application. CSRF is a client-side attack that can be used to redirect users to malicious websites, steal sensitive information, or perform other actions within a user's session. Fortunately, it is relatively easy to use CSRF tokens to protect users from CSRF attacks and their consequences.

CSRF principle

Let’s look at the details of the attack in detail

Look at the pictures and talk, the general process

  • User accesses and browses normal websites
  • The normal website server responds and returns a cookie that identifies the user.
  • The user accesses a malicious website without logging out of the normal website.
  • A malicious website visits a normal website and carries a cookie that identifies the user.
  • Normal website server accepts requests from malicious websites

        When you visit a normal website again, the browser will automatically send a request with a cookie that identifies the user, so the normal website server will accept the request from the malicious website, thereby completing the attack.

        When I visit and log in to a normal website, after successful access, the server will generate a cookie that identifies the user and save it in the user's browser. If I visit a malicious website while the identifying cookie still exists, the attacker will make you unknowingly access the website. Visit the previous normal website and perform some operations. Since the cookie that identifies the user's identity still exists, the user's browser thinks it is the user's intended operation and executes the request, thus the attack is successful.

        There are many access methods for these deceptions, such as "clicking on small ads, retrieving passwords", etc. to induce users to click.

CSRF attack types

        If a web application cannot distinguish between illegal and valid requests, it is vulnerable to cross-site request forgery. The attack will only succeed when the authenticated user has an active session with the web application.

Login CSRF attack

        Using a special form of CSRF attack called a Login CSRF attack, an attacker can gain access to a victim user's confidential and sensitive data. This attack forces unsuspecting users to log into accounts controlled by hackers. Victims are then tricked into adding personally identifiable and sensitive information, such as email addresses and credit card information, to their accounts.

Storage CSRF attack

        CSRF attack kits can also be stored on vulnerable websites. An adversary can achieve stored CSRF attacks by performing advanced XSS attacks or storing IFRAME or IMG tags in fields that accept HTML. Storing the attack on the site amplifies the severity and likelihood of the attack because the victim user will now certainly view the CSRF-loaded page and will naturally authenticate to that page as well

Some ways to prevent CSRF attacks include

  1. Using the synchronizer token pattern
  2. Use double submission cookies
  3. Use standard HTTP headers to verify the origin of the request
  4. UI-based authentication, such as CAPTCHA-based authorization and MFA
  5. Use SameSite Cookie for request source management
  6. Use of CSRF tokens

Here are some ways to defend against CSRF attacks:

  • Use POST request

            Since it is relatively easy to forge a GET request (just open a URL or request a resource), try to use POST requests for interfaces involving critical business operations. This is because POST requests typically require more conditions and data, making it more difficult for an attacker to forge a valid request.

  • Add verification code  

           Verification codes are considered the most concise and effective defense method against CSRF attacks.

           As can be seen from the above examples, CSRF attacks often construct network requests without the user's knowledge. The verification code forces the user to interact with the application to complete the final request. Because usually, verification codes can effectively contain CSRF attacks.

           However, verification codes are not omnipotent, because for user considerations, verification codes cannot be added to all operations on the website. Therefore, the verification code can only be used as an auxiliary means to defend against CSRF, but not as the main solution.

           By adding verification methods such as verification codes, only requests that pass verification are considered legitimate requests. This method ensures the authenticity of the request to prevent maliciously forged requests from successfully executing.

  • Set SameSite properties

            One of the characteristics of CSRF attacks is that the domain name of the forged request is usually not the attacked website. By setting the SameSite attribute of Cookies to Strict, only the same-origin website is allowed to send requests with Cookies. This prevents cross-origin attackers from executing forged requests in the user's browser. Note that this method may be limited by some incompatible browser versions.

  • VerifyReferer

            Since forged requests usually do not contain correct Referer information, you can identify whether the source of the request is trustworthy based on the Referer field in the request header. By validating the Referer, you can prevent untrusted requests from being forged. However, an attacker may be able to bypass this defense by setting the request to not carry a Referer, so this should only be used as a secondary defense method.

           According to the HTTP protocol, there is a field called Referer in the HTTP header, which records the source address of the HTTP request. Referer Check allows you to check whether the request comes from a legitimate "source".

           For example, if a user wants to delete his own post, he must first log in to www.c.com, then find the corresponding page and initiate a request to delete the post. At this time, the value of Referer is http://www.c.com; when the request is initiated from www.a.com, the value of Referer is http://www.a.com. Therefore, to defend against CSRF attacks, you only need to verify the Referer value of each post deletion request. If it is a domain name starting with www.c.com, it means that the request comes from the website itself and is legal. If the Referer is another website, it may be a CSRF attack and the request can be rejected.

    For the above example, you can add the following code on the server side:

    1

    2

    3

    4

    if (req.headers.referer !== 'http://www.c.com:8002/') {

      res.write('csrf 攻击');

      return;

    }

            Referer Check can not only prevent CSRF attacks, but another application scenario is "preventing image hotlinking". The disadvantage of this Referer method is that an attacker may tamper with the contents of the Referer field to deceive the server.

  • Verify CSRF token

            This is a widely used and effective defense method. The server generates a random CSRF token in each session and saves it in the session and in the client's .Cookies or .form fields. When sending a request, the client sends the token either as a header in the HTTP request or as a parameter to the server. After the server receives the request, it verifies that the token in the request matches the token in the session. A request is considered legitimate only if the tokens match. This approach generally works for both non-detached and detached projects. For non-detached projects, the token can be written directly into a hidden form field in the template, so no additional action is required when sending the request. For separate projects, the token can be written to Cookies when logging in. When sending a request, JavaScript reads the token from Cookies and sets it as the header of the HTTP request.

  • Change the login state solution

            Since CSRF attacks essentially exploit the victim's authenticated session in the browser, if the session verification mechanism is replaced, such as using JSON Web Token (JWT), whose token information is usually stored in the HTTP header, CSRF attacks can be effectively prevented. .

    The following are some key advantages of JWT-based defense against CSRF attacks:

    (1) CSRF Token is no longer necessary: ​​Traditional Session-based solutions usually require the use of CSRF Token for verification in forms or requests to prevent CSRF attacks. In JWT-based solutions, JWT itself contains verification information and does not require additional CSRF Token, thus simplifying the complexity of implementation and management.

    (2) Prevent cross-domain requests: JWT-based solutions usually store JWT in the header of the request, such as Authorization Header, but cross-domain requests usually cannot carry custom headers. In this way, attackers cannot send valid JWTs in cross-origin requests, effectively preventing CSRF attacks.

    (3) Verify token integrity: In traditional Session-based solutions, the server needs to obtain the Session ID associated with the request from the session storage and verify it. In the JWT-based solution, the server only needs to verify the signature and validity period of the JWT to ensure the integrity and legality of the JWT.

    It should be noted that although JWT-based solutions provide some advantages to defend against CSRF attacks, this article only explains the advantages of JWT based on defending against CSRF attacks. However, the final choice of the appropriate login state solution is based on application needs, security requirements and technology. Determined by the architecture. Regardless of whether you choose a Session-based or JWT-based solution, you need to follow relevant security best practices to ensure the security of the login state and the overall security of the application.

Anti-CSRF Token Basics

        The idea behind anti-CSRF tokens (also called synchronizer token patterns or simply CSRF tokens) is to provide the user's browser with a piece of information (the token) that the browser must then send back. The token must be unique and cannot be guessed by a third party, and the application must verify the token before processing the HTTP request. This ensures that only the original user can send requests within an authenticated session.

        For a basic example without CSRF protection, assume you are running a web application on www.example.com . To post a message on their profile in the app, users need to fill out an HTML form and click the "Submit" button:

<form action="/action.php" method="post">
  Subject: <input type="text" name="subject"/><br/>
  Content: <input type="text" name="content"/><br/>
  <input type="submit" value="Submit"/>
</form>

        The submit operation causes the web browser to send a POST request to the server, sending any data entered by the user as parameters:

POST /post.php HTTP/1.1
Host: example.com

subject=I am feeling well&content=I just ate a cookie and it was delicious

        If the user is logged in and the attacker knows the request syntax, it is possible to use a CSRF attack to post ads on that user's profile:

<form action="/action.php" method="post">
  Subject: <input type="text" name="subject" value="Buy my product!"/>
  Content: <input type="text" name="content" value="To buy my product, visit this site: example.biz."/>
  <input type="submit" value="Submit"/>
</form>
<script>
  document.forms[0].submit();
</script>

      As a result, the web browser sends the following POST request:

POST /post.php HTTP/1.1
Host: example.com

subject=Buy my product!&content=To buy my product, visit this site: example.biz.

        On unprotected pages, CSRF may be achieved if the server treats the forged request as coming from an authenticated user.

        But now imagine that your site uses simple token-based CSRF mitigation, and your web server sets the token in a session cookie that is sent to the browser immediately after login. All form submissions then include a hidden field containing the token. Assuming proper token validation, this completely eliminates the CSRF vulnerability:

<form>
  Subject: <input type="text" name="subject"/><br/>
  Content: <input type="text" name="content"/><br/>
  <input type="submit" value="Submit"/>
  <input type="hidden" name="token" value="R6B7hoBQd0wfG5Y6qOXHPNm4b9WKsTq6Vy6Jssxb"/>
</form>

        The server should then only accept POST requests from the same user containing this exact token value, for example:

POST /post.php HTTP/1.1
Host: example.com

subject=I am feeling well&content=I just ate a cookie and it was delicious.&token=R6B7hoBQd0wfG5Y6qOXHPNm4b9WKsTq6Vy6Jssxb

        With this protection in place, an attacker trying to perform CSRF using a malicious site would not be able to forge an HTTP request without knowing the current token set in a valid user cookie. Since your server rejects all requests without this token, any attack attempts will fail.

How to generate and verify CSRF tokens

        Regardless of the specific method you use to generate and verify anti-CSRF tokens, be sure to follow these top security rules to prevent attackers from forging tokens in their malicious requests:

  • Use a reputable and unpredictable random number generator with sufficient entropy.
  • Tokens expire after a short period of time to prevent reuse.
  • When checking whether the received token is the same as the one set, use a secure comparison method (such as comparing cryptographic hashes).
  • Never send CSRF tokens in HTTP GET requests to ensure that they are never displayed in the URL and are not Refererleaked in the header along with other referrer information.

For example, in PHP you can generate a basic token like this:

$_SESSION['token'] = bin2hex(random_bytes(24));

When you receive an incoming token, you can securely verify it by comparing the hashes:

if (hash_equals($_SESSION['token'], $_POST['token'])) {
  // Action if token is valid
} else {
  // Action if token is invalid
}

CSRF protection for every form

        Using the basic anti-CSRF token above, you can set the token in the user's session cookie when logging in, and then validate the same token for every form. In most cases, this protection is sufficient, but some sites may require a more secure approach. To balance security and usability, you can generate separate tokens for each form you use.

        To do this, generate a token but do not expose it directly to the user's browser. Instead, hash the token combined with the form's filename, for example:

hash_hmac('sha256', 'post.php', $_SESSION['internal_token'])

        To verify, compare the two hashes generated in this way. If the token is valid and uses the same form, the hashes will match.

CSRF protection on every request

        When a very high level of protection is required (perhaps in a banking application) you can use separate tokens for each request and simply invalidate each token after validation.

        This approach has several usability flaws that should be carefully considered before implementing a per-request token.

  1. 1. Most notably, it makes it impossible to use the app in multiple tabs.
  2. 2. You also cannot use the browser's back button and can only use the application's internal navigation function.
  3. 3. Since each request requires a new random token, protection of each request needs to consider server performance and use a less resource-intensive random number generator.

Using non-persistent CSRF tokens

        If your web page or application is very busy and your server has limited storage space, you may want to avoid persisting tokens on the server side altogether. In these specific cases, you can generate and handle tokens cryptographically without storing them in the server session:

  1. With symmetric encryption, the key is known only to the server and is never shared with the client.
  2. Generate a token by combining the current timestamp, username, and form name (if needed), then encrypt the entire string using the server key.
  3. When you receive the token from the web browser, use the same key to decrypt it.
  4. Check the timestamp of the decrypted token (to eliminate old tokens) and compare the decrypted user and form names with the expected current values.

        While this approach does not require server-side storage, it may incur some performance overhead because cryptographic functions are more resource intensive than simple random number generation.

        Another option for implementing non-persistent tokens is to double-submit cookies. For this technique, the server sets a random value in the cookie even before the user authenticates. The server then expects this value to be sent with every request (e.g. using a hidden form field).

CSRF protection for asynchronous (Ajax) requests

        Anti-CSRF tokens should also be used for Ajax requests. To implement them safely, first ensure that your web server does not allow cross-domain asynchronous requests (by checking the Cross-Origin Resource Sharing header).

        When implementing CSRF protection for Ajax requests, you can include the token in a hidden text field as usual, or put it directly into JavaScript. You can then send the token with every asynchronous request and verify its existence and value on the server side.

Anti-CSRF token for login form

        It is generally accepted that anti-CSRF tokens are only needed when a user is logged in, so the login form does not need CSRF protection. While it is true that there is no way to impersonate a user before they log in, the lack of CSRF protection in the login form could allow an attack to expose sensitive information after tricking the user into logging in as the attacker . The attack can be performed as follows:

  1. An attacker creates an account in your web application.
  2. An attacker tricks a victim into logging into your application using the attacker's credentials, which may be achieved through some social engineering if there is no CSRF protection on the login form.
  3. The victim uses your application normally and may not know they are logged in as someone else.
  4. The attacker might then use the history feature to track the victim or otherwise profit from the victim's interaction with your application.

        To minimize the risk of these and related attacks, a best practice is to include anti-CSRF tokens on all login pages.

        As with login forms, you may also see online resources that advise against using anti-CSRF tokens for REST API endpoints, claiming that they are unnecessary. While this may be technically true in many cases, it's often difficult to predict all the ways an API can be accessed (and how it might be modified in the future), so providing CSRF protection for a REST API may be considered an additional layer of security.

Beyond Tokens: Other CSRF Prevention Methods

        For in-depth protection against CSRF, you can combine CSRF tokens with other technologies. For example, to validate Ajax requests, you can add and then inspect any custom headers. This works because the Same Origin Policy states that request headers can only be added using JavaScript from the same origin, but be aware that you should not rely on this behavior as your only line of defense. For a detailed discussion of this and other CSRF prevention methods, see the OWASP Cross-Site Request Forgery Prevention Cheat Sheet .

        Anti-CSRF tokens are one of the most secure ways to defend against CSRF attacks, but other vulnerabilities in applications may allow attackers to bypass CSRF protection. For example, if your web application has a cross-site scripting vulnerability (XSS) , an attacker could use XSS to execute a script that silently fetches a new version of the form using the current (valid) CSRF token. To prevent this from happening and maintain solid web application security, make sure to regularly scan your web applications for all types of vulnerabilities, not just CSRF.

CSRF considerations

        There are some special considerations to consider when implementing protection against CSRF attacks.

Log in

        To prevent  forged login requests , the HTTP request for login should be protected from CSRF attacks. Preventing forged login requests is necessary so that malicious users cannot read the victim's sensitive information. The attack works as follows.

  1. The malicious user uses the "malicious user's credentials" to perform CSRF login. The victim is now authenticated as a malicious user.

  2. The malicious user then tricks the victim into visiting the compromised website and entering sensitive information.

  3. This information is associated with the malicious user's account, so the malicious user can log in with their own credentials and view the victim's sensitive information.

        One possible complication in ensuring that logged-in HTTP requests are protected from CSRF attacks is that the user may experience a session timeout, causing the request to be rejected. Session timeouts are surprising for users who don't expect to need a session to log in. For more information, see CSRF and Session Timeout .

sign out

        To prevent forged logout requests, logout HTTP requests should be protected against CSRF attacks. Preventing forged logout requests is necessary so that malicious users cannot read the victim's sensitive information. For details on the attack, see  this blog post .

        A possible complication in ensuring that the logout HTTP request is protected from CSRF attacks is that the user may encounter a session timeout, causing the request to be rejected. Session timeouts are surprising for users who don't expect to have a session to log out. For more information, see  CSRF and Session Timeout .

CSRF and session timeout

        More often than not, the expected CSRF token is stored in the session. This means that once the session expires, the server cannot find the expected CSRF token and rejects the HTTP request. There are many options (each with a swap condition) to solve the timeout problem.

  • The best way to mitigate timeouts is to use JavaScript to request a CSRF token on form submission. Then update the form with the CSRF token and submit.

  • Another option is to have some JavaScript that lets the user know that their session is about to expire. Users can click a button to continue and refresh the session.

  • Finally, the expected CSRF token can be stored in a cookie. This can invalidate the expected CSRF token within the session.

    One may ask why the expected CSRF token is not stored in the cookie by default. This is because there are known vulnerabilities where header information (for example, used to specify cookies) can be set by another domain. This is the same reason why Ruby on Rails  no longer skips CSRF checks when the X-Requested-With header is present . Details on how to execute this vulnerability can be found in  this webappsec.org article . Another drawback is that by removing state (i.e. timeout), you lose the ability to forcefully invalidate the token if it is compromised.

Multipart (file upload)

        Protecting Multipart requests (file uploads) from CSRF attacks creates a  chicken or egg  problem. To prevent CSRF attacks from occurring, the body of the HTTP request must be read to obtain the actual CSRF token. However, reading the body means the file was uploaded, which means an external website can upload the file.

There are two ways to use CSRF protection  multipart/form-data.

Each choice has its pros and cons.

Before you integrate Spring Security's CSRF protection with multipart file uploads, you should first ensure that you can upload without CSRF protection. For more information on using multipart forms in Spring, see the  1.1.11. Multipart Resolver  section of the Spring documentation and  the MultipartFilter Javadoc .

Put CSRF token in request body

        The first option is to include the actual CSRF token in the body of the request. By placing the CSRF token in the request body, the request body is read before authorization occurs. This means that anyone can place temporary files on your server. However, only authorized users can submit a file for processing by your application. Generally speaking, this is the recommended approach, as the impact of temporary file uploads on most servers should be negligible.

Put CSRF token in URL

        If having unauthorized users upload temporary files is unacceptable, an alternative is to include the expected CSRF token as a query parameter in the form's action attribute. The disadvantage of this approach is that query parameters can be leaked. More commonly, it is best practice to put sensitive data in the body or header to ensure it is not leaked. You can   find more information in RFC 2616 Section 15.1.3 , Encoding Sensitive Information in URIs.

HiddenHttpMethodFilter

        Some applications can use form parameters to override HTTP methods. For example, the form below can treat HTTP methods  delete as not  post.

CSRF Hidden HTTP Method Form

<form action="/process"
	method="post">
	<!-- ... -->
	<input type="hidden"
		name="_method"
		value="delete"/>
</form>

        Overriding HTTP methods occurs within a filter. This filter must be placed before Spring Security support. Note that the rewrite only happens on  post , so this is actually unlikely to cause any real problems. However, the best practice is to make sure it is placed before Spring Security's filters.

Defense example

Nginx defense example

https://github.com/gartnera/nginx_csrf_prevent/blob/master/ngx_http_csrf_prevent_filter_module.c

Nginx+lua defense example

https://gist.github.com/loveshell/7480950

reference:

How to protect your websites and web apps with anti-CSRF tokens | Invicti

XSS and CSRF attacks - what is the difference? - Zhihu

Cross Site Request Forgery (CSRF) :: Spring Security Reference

Recognize and defend against XSS and CSRF attacks | Youth Academy-Nuggets

Guess you like

Origin blog.csdn.net/yangyangye/article/details/132895518