Cross-site Request Forgery (CSRF) is a malicious attack that exploits the permission of a trusted user on a website to execute an unauthorized command. Exploiting sites that trust trusted users by masquerading their requests is not very popular, but it is difficult to prevent and no less dangerous than other security vulnerabilities.

This article will briefly introduce the causes of CSRF and the ways to use it, and then provide some schemes for reference on how to avoid this kind of attack, hoping that the vast number of programmers can understand this kind of attack, so as to avoid their applications being used by others.

CSRF, also known as one-click Attack or Session riding, is sometimes abbreviated using XSRF.

[TOC]

This article will continue to be revised and updated, please refer to my GITHUB program ape growth plan project for the latest content, welcome Star, more exciting content please follow me.

What is CSRF?

Simply put, a CSRF attack is when an attacker uses the identity of the victim to send malicious requests in the name of the victim. Different from XSS (Cross-site Scripting), XSS is designed to obtain user identities, while attackers steal user identities (session/cookie), whereas CSRF uses users’ current identities to perform unauthorized operations.

CSRF attacks was discovered in 2001 at the earliest, as a result of its request from the user’s IP address, so in the web log server may not be able to detect whether the CSRF attacks, it is because of this kind of its concealment, for a long time has not been publicly reported, it was not until 2007 that the real attention by people.

Generation principle and use way

To complete a CSRF attack, the following conditions must be met:

  • The victim has logged into the target site (your site) and has not logged out
  • Victims intentionally or unintentionally visit pages or links posted by attackers

(The picture is from the Internet, the source is unknown, Baidu to)

The whole process looks something like this:

  1. User Xiaoming logs in to your website A, and A returns A session ID (stored using cookies).
  2. Xiaoming’s browser keeps the login state of website A. In fact, almost all websites do so. Generally, at least before the user closes the browser, the user’s session will not end
  3. The attacker xiaoqiang sends Ming a link to the address, which Ming opens to view the content of the web page
  4. When Xiao Ming opened this address, the page had automatically sent A request to website A. At this time, as website A did not quit, as long as the requested address is A, it will carry the cookie information of A, that is, the session between A and Xiao Ming will be used
  5. At this time, A website must not know that this request is actually sent on the forged web page of Xiaoqiang, but mistakenly thought that Xiaoming is to operate in this way, so that Xiaoqiang can arbitrarily change xiaoming’s information on A, to operate in the identity of Xiaoming on A website

Using the way

CSRF attack mainly includes two ways: one is based on GET request and the other is based on POST request.

POST request utilization

Compared with GET, POST is more complex and difficult. An attacker needs to forge a form that can be submitted automatically to send a POST request.

<script>
$(function() {
    $('#CSRF_forCSRFm').trigger('submit');
});
</script>
<form action="http://a.com/user/grant_super_user" id="CSRF_form" method="post">
    <input name="uid" value="121" type="hidden">
</form>
Copy the code

Just find a way to automatically submit the form when the user accesses it.

Prevent principle

To prevent CSRF attacks, in fact, the essence of the website is to be able to identify which requests are initiated by abnormal users. This requests us in the request to embed additional authorization data, make the web server can distinguish between these unauthorized requests, such as a field is added in the request parameters, the value of this field from the logged in user’s cookies or page in (the field value must be for each user is random, there can be no rules to follow). The attacker can avoid this attack by forging a request without being able to retrieve a random value on the page associated with the logged-in user or the contents of the user’s current cookie.

Synchronizer token pattern

The Synchronizer Token Pattern (STP) is the technique of embedding a token in all forms on a page requested by a user and validating that token on the server side. The token can be anything, but it must be impossible for an attacker to guess or query. An attacker cannot use the correct token in a request, and therefore can identify an unauthorized request.

Verification code

Using a captcha can prevent CSRF attacks, but this method requires each request to enter a captcha. Obviously, no site wants to use this crude method, and the user experience will be poor, and users will go crazy.

Analyze verifyCS SRfToken middleware in Laravel framework

In Laravel framework, VerifyCSRFToken middleware is used to defend against CSRF attack.

Use {{CSRF_field()}} to generate tokens in the form of the page. This function adds a hidden field named _token to the form. The value of the hidden field is the token generated by Laravel, who uses randomly generated 40 characters as tokens to defend against CSRF attacks.

$this->put('_token', Str::random(40));
Copy the code

If the request is ajax asynchronous, you can add a token to the meta tag

<meta name="CSRF-token" content="{{ CSRF_token() }}">
Copy the code

When using jquery as a front-end framework, you can add this value to all asynchronous request headers using the following configuration

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="CSRF-token"]').attr('content')
    }
});
Copy the code

When a session is enabled, Laravel generates a value named _token and stores it in the session. The token added to the page using the previous two methods uses this value. When a user request arrives, the VerifyCSRFToken middleware performs CSRF checks on eligible requests

if (
  $this->isReading($request) ||
  $this->runningUnitTests() ||
  $this->shouldPassThrough($request) ||
  $this->tokensMatch($request)
) {
  return $this->addCookieToResponse($request, $next($request));
}

throw new TokenMismatchException;
Copy the code

There are four conditions in the if statement. If any of the conditions result in true, then any request is valid. Otherwise, a TokenMismatchException is thrown, telling the user that the request is invalid and there is a CSRF attack.

$this->isReading($request)

protected function isReading($request)
{
    return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
}
Copy the code

The request mode is determined. If the request mode is HEAD, GET, and OPTIONS, the request is directly allowed. You may be wondering why GET requests should also be allowed. This is because Laravel believes that all three requests are requests for query data, and if a request uses GET, no matter how many times the request is made, no matter what the request parameters are, the data should not be modified.

$this->tokensMatch($REQUEST) : $this->tokensMatch($request) : $this->tokensMatch($request)

$sessionToken = $request->session()->token(); $token = $request->input('_token') ? : $request->header('X-CSRF-TOKEN'); if (! $token && $header = $request->header('X-XSRF-TOKEN')) { $token = $this->encrypter->decrypt($header); } if (! is_string($sessionToken) || ! is_string($token)) { return false; } return hash_equals($sessionToken, $token);Copy the code

Laravel reads the value of the _token parameter from the request, which is generated by the CSRF_field() function added in the previous form. If the request is asynchronous, the X-CSRF-Token request header is read and the TOKEN value is read from the request header.

Finally, the hash_equals function is used to verify that the token values provided in the request parameters are consistent with the token values stored in the session. If they are, the request is valid.

You may have noticed that this check also reads a request header named X-XSRF-Token. This value is used to support javascript frameworks (such as Angular) that automatically add this header to asynchronous requests. This value is read from the XSRF-token in the Cookie, so at the end of each request, Laravel sends the client a Cookie value named xSRF-Token

$response->headers->setCookie(
    new Cookie(
        'XSRF-TOKEN', $request->session()->token(), time() + 60 * $config['lifetime'],
        $config['path'], $config['domain'], $config['secure'], false
    )
);
Copy the code

reference