For other translations of this series, see [JS Working Mechanism – Xiaobai’s 1991 column – Nuggets (juejin. Cn)] (juejin.cn/column/6988… Reading Index :5 This article is not very informative and easy to understand. It is highly recommended

An overview of the

Cross-site Request Forgery (CSRF), also known as one-click attack or Session Riding. It is also a malicious attack on web sites or applications. This attack means that the attacker performs malicious requests on behalf of the victim. Malicious applications can deliver these requests in many ways, such as specially processed image tags, hidden forms, AJAX requests, and so on, all without the user knowing or suspecting them. XSS attacks take advantage of users’ trust in some websites, while CSRF attacks take advantage of users’ trust in some browsers.

CSRF attack mechanism

While performing a CSRF attack, the victim submits a malicious request. This request can cause the Web application to perform risky behavior, such as leaking client and server data, modifying session state, or manipulating users’ accounts.

A CSRF attack is an example of a confused proxy attack on browsing. The browser was tricked by the attacker into sending a bogus request.

CSRF generally has the following characteristics:

  • Design websites and applications that rely on user authentication
  • Take advantage of the site’s trust in this certification
  • Tricking the user’s browser into sending an HTTP request to the target web site
  • This HTTP request has side effects

To summarize the steps of a CSRF attack:

  • The victim performed some suspicious behavior, such as visiting the attacker’s controlled web pages, links, etc.
  • The effect of this action is to send a request to the attacker’s website on behalf of the victim
  • If the site has the victim’s authentication information at this point, the request is considered a legitimate request sent by the victim.

Note that the CSRF leverages the authentication information activated by the victim.

In most cases, CSRF attacks do not steal private information, but rather trigger actions related to users’ accounts, such as changing their authentication information or making a purchase. Forcing the user to fetch data from the server does not benefit the attacker because the response to the request is unacceptable to the attacker. Therefore, they execute requests to change data.

Session management in Web applications is based on cookies. Each time a request is sent to the server, the browser will attach the relevant cookie to indicate the identity of the current user. This is often done even under different domains. The attacker took advantage of this vulnerability. Although CRFS is often referred to as session related, it can be used in other situations as well – as long as the application automatically adds user authentication information to the request

Example

Let’s look at the following example which 上 升 a simple “Profile page” on a Social Network Web app:

<! DOCTYPE HTML > < HTML > < head > < script SRC = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" > < / script > <script> $.get('htps://example.com/api/profile', function(data) { $('#username').val(data.name); $('#useremail').val(data.email); }); </script> </head> <body> <form method='post' action='htps://example.com/api/profile'> <fieldset> <legend>Your Profile:</legend> <label for='username'> Name:</label> <input name='username' id='username' type='text'> <br><br> <label  for='email' > Email:</label> <input name='email' id='useremail' type='email'> <br><br> <button type='submit'> Update </button> </fieldset> </form> </body> </html>Copy the code

This page simply loads the user’s account data and populates it in a form. If the form is edited, the data is submitted and updated. The server accepts the submitted data as long as the user is currently authenticated. Now take a look at the malicious page with CSRF executed. This page was created by the attacker and hosted under a different domain name. The goal of this page is to send a request to the social network:

<! DOCTYPE HTML> <html> <head></head> <body> <form method='post' action='htps://example.com/api/profile'> <input type='hidden' name='username' value="The Attacker"> <input type='hidden' name='email' value="[email protected]"> </form> <script> document.forms[0].submit(); </script> </body> </html>Copy the code

This page contains a form with hidden fields, and the action of the form points to the same Profile page.

Once a user opens a malicious site, the form automatically submits data to the server.

At this point, if the user has not authenticated an account, then this expression is less harmful because the server will refuse to modify the user’s data. But if the user is logged in and authenticated, the request is a valid one, and the server modifies the data.

The attacker mainly forged the request and did not directly read and steal the user’s cookie. This example is simple. Real attacks would be more sophisticated and covert. For example, a CSRF attack can be embedded in an IFrame where the victim is completely imperceptibly

There are many ways to reduce the risk of CSRF attacks:

Token-based prevention

This defense is one of the most popular and recommended methods to mitigate CSRF attacks. It can be achieved with two General Approaches: This is the most popular and recommended approach to reduce CSRF attacks. It achieves its effect in two main ways:

  • Stateful – Synchronization token mode
  • Stateless – Encrypted or hashed based on token mode

There are many libraries that provide out-of-the-box implementations of these technologies

Built-in CSRF implementation

Before trying to build an application, it’s best if you use a framework that supports CSRF protection by default. But even so, we are still responsible for the correct configuration, such as key management and token management

If you are using a framework that does not have CSRF protection built in, you will need to implement it yourself.

Let’s take a look at how the Express framework implements built-in CSRF protection. Express provides cSURF middleware, which does just that: CSRF protection.

Of course we won’t discuss the details, just the key points

We’ll start with index.js:

const express = require('express');
const bodyParser = require('body-parser');
const csrf = require('csurf')
const cookieParser = require('cookie-parser')
const app = express();
const csrfProtection = csrf({ cookie: true });

app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs');

app.get('/', csrfProtection, (req, res) => {
  res.render('index', { csrfToken: req.csrfToken() });
});

app.post('/profile', csrfProtection, (req, res, next) => {
  res.send(req.body.name);
});

app.listen(3000);
Copy the code

Then in the views folder, we add index.ejs:

<form action='/profile' method='POST'>
  <input type='hidden' name='_csrf' value='<%= csrfToken  %>'>  
  <label for='name'> Name:</label> 
  <input type='text' name='name'>
  <button type='submit'> Update </button>
</form>
Copy the code

Ejs template will be rendered and the csrfToken variable in the template will be assigned a CSRF token.

In index.ejs, the csrfToken is assigned to a hidden field. When the form is submitted, a request is sent to the protected /profile route.

If no CSRF token is found, an invalid CSRF token is thrown.

Synchronizing Token Mode

The synchronous Token mode allows servers to validate requests to ensure that their source is legitimate. The server generates a tokern for each user seesion and each request

When a request is sent from a client, the server compares the request with the token in the user session to verify that the request carries the token and is valid

In most applications, the server uses HTTPsession to indicate the user’s login status. In this example, the server generates the session and sends the session ID to the client. This ID is stored in the client cookie most of the time

If the Cookie that holds the session ID is not properly protected (httpOnly, co-site, security, etc.), it may be accessed by other pages opened in the browser.

It is safer to generate each request once because attackers have less time to take advantage of tokens. But it can also make the user experience worse. Because it is likely that the user clicked a back button, but the page contained an invalid token, the server could not validate the token and the request would not be accepted.

A CSRF token needs to have the following characteristics:

  • Each session is unique
  • Hard to predict – a safe random number

Without tokens, an attacker cannot create a valid request, thus reducing CSRF attacks.

CSRF tokens also cannot be sent using cookies because they can be intercepted or accessed by an attacker.

CSRF tokens cannot also be passed using “GET” requests, as there are many ways to leak them. Such as browser history, log files, recommendation headers, etc.

CSRF Tokens can be transmitted in these ways:

  • Used in the Hidden Fields form
  • Used when Headers AJAX calls are made

For example, in the form:

<form action= '/ API /payment' method= 'post' > <input type= 'hidden" name=' CSRFToken ' Value = "WfF1szMUHhiokx9AHFply5L2xAOfjRkE" > < / form >Copy the code

As in the example above, the token value is generated on the server side.

Token Encryption Mode

For the Web application pattern, the encryption mode obviously fits better and the server does not have to maintain any state.

The server generates the token, which consists of the user’s sessionID and timestamp. This pair is the secret key used for encryption. Once the token is generated, it is returned to the client. Like synchronous tokens, encrypted tokens need to be in a hidden field or in the request header of an Ajax request.

Once the server receives the request, it attempts to decrypt the token

If decryption fails, it means that the request has been compromised in some way and the request is invalidated.

If decryption succeeds, the sessionID and timestamp are extracted. The sessionID is compared with the current authentication user, and the timestamp is compared with the current server to check whether the predefined expiration time is exceeded. If the session ID matches and the timestamp does not expire, then the request is safe to be processed.

SameSite Cookies

Supplement of SameSite [to see] this article ([Cookie SameSite analysis – zhihu (zhihu.com)] > (zhuanlan.zhihu.com/p/266282015))

SameSite is a cookie property that is also used to protect against CSRF attacks. This property allows the browser to decide whether or not to include cookies for cross-site requests, and the values of this property have these values

  • Strict– Cookies are sent only in the current context. Requests from third-party websites are not sent. If you click on a link to a GitHub repository on a page, for example, cookies won’t be included in the request when you jump
  • LaxCookies do not appear in request methods that are vulnerable to CRSF attacks, such asPOST. Cookies are allowed when the user navigates to the source site, which is the default cookie value if the browser does not explicitly set SameSite. Also, if you want to access a private GitHub repository at this point, you will be carrying your cookies
  • None– Cookies are carried by all requests, both the current source and cross-source requests. But you need oneSecureThe tag.

Desktop browsers and most mobile browsers support the SameSite property. Note that this attribute does not replace tokens, they are both co-existing, giving the user double insurance.

Homologous verification

This approach requires two steps to validate the HTTP request header

  • Verify the source from which the request originatedOrigin 和 RefererThe head can be seen
  • Verify the target source

The server needs to verify that the request source and target source match. If there is no match, the request is considered cross-source and is rejected. This validation is very reliable because the header information is forbidden to be modified and only the browser can manipulate it.

Double Submit Cookie

This is an alternative to the token scheme and is a stateless scheme.

When the user accesses the Web application, a pseudo-random number of high security level is generated and set in the cookies. This value is independent of the session ID.

Each request the server accepts carries this random number (by hiding the form or request parameters). If the two values are matched on the server side, the request is considered valid, otherwise it is rejected.

Custom request headers

This approach is best suited to the application, handled primarily in AJAX requests and also dependent on API endpoints.

The first is to use the same origin policy, which is limited to its source and can only add custom headers using JS. By default, browsers do not allow JS to make cross-source requests with custom headers.

This requires a stable [CORS] configuration scheme because requests from other sources trigger preventive checks for CORS.

Allows you to add a custom header and verify its existence and correctness on the server. This is recommended when using AJAX, and

elements should use tokens.

Interaction-Based Defense

User behavior is the most effective mechanism against CSRF attacks. There are two common ways:

  • Preauthentication – Forcing user authentication before the request is initiated
  • CAPTCHA

These are powerful ways to counter CSRF, but they also have a negative impact on the user experience. Therefore, they should be mainly applied to some key behaviors, such as transferring money, placing orders, etc.

Preauthentication defense

CSRF attacks can also occur on some pages, such as the login page, when the user is not authenticated. This attack affects pre-authenticated pages differently than authenticated pages

Let’s say there’s an e-commerce site, and the victim authenticates herself. In this case, the attacker can use CSRF attacks to replace the victim’s account with his own. When the victim enters their information card information, the attacker can use the victim’s credit card to make purchases.

To avoid this attack, you can create a pre-authentication when the user is not authenticated. The login form must contain a CSRF token, as we mentioned earlier

Once the user is authenticated, the pre-session programs the actual session.