Authorized Cross-Site Request Forgery (CSRF)

Severity: Medium
Test name: Cross-Site Request Forgery (CSRF)
Summary

Authorized Cross-Site Request Forgery (CSRF) occurs when a malicious resource forces a user's web browser to perform an unwanted action on a trusted website when the user is authenticated. The attack works because the browser requests automatically include all cookies, including session cookies. If the user is authenticated to the site, the site cannot distinguish between legitimate requests and forged requests.

An attacker may deliver a dangerous URL to a user in different ways, for example:

  • Send an email with a link to a malicious request.
  • Send an email with a 0x0 fake image. The source of the image is a malicious request.
  • Develop a fake web application with a prepared form. The form can send a malicious request automatically (<body onload="document.forms[0].submit()">) or by clicking a submit button.
  • Develop a fake web application with a prepared JavaScript code that will send "XMLHttpRequest".
Impact

The CSRF attack may be executed for the following purposes:

  • Send money from one account to another
  • Change a user's password or a secret question
  • Gain administrative privileges
  • Make a purchase with the user's credentials
Example
  1. The user is using a bank website (https://{your-bank}.com) and has an active session in his browser (for example, this website is opened in one of the browser tabs).
  2. An attacker creates a special link to transfer money between two accounts:
https://{your-bank}.com/transfer?from=account1&to=account2&amount=1000
  1. The attacker sends this link to the user in any possible way. For example, the attacker can use an email to send the link that will be shown for the user as a “broken" picture. The body of the email should contain:
<img src="https://{your-bank}.com/transfer?from=account1&to=account2&amount=1000/>
  1. As soon as the user clicks this image, the corresponding URL opens in a new browser tab. As the user still has an active session (see point 1), the money from "account1" will be transferred to "account2". An unwanted action is performed on a trusted site when the user is authenticated.
Location
  • The issue can be found in the source code on the server side.
  • The issue can be found in the server configuration.
Remedy suggestions
  • Check if your framework has built-in CSRF protection and use it.
  • Always use the "SameSite" Cookie Attribute for session cookies. Based on your application use cases, "Lax" or "Strict" value should be used.
Set-Cookie: JSESSIONID=xxxxx; SameSite=Strict
Set-Cookie: JSESSIONID=xxxxx; SameSite=Lax
  • Do not use the GET method for state-changing requests. The GET request should be used only for retrieving the information.

  • Try to avoid cross-site requests if possible. Modern web browsers support same-origin policy restriction, so do not configure CORS headers on your server.

  • If your application supports cross-site requests, then carefully configure CORS headers. Configure allowed domain names in "Access-Control-Allow-Origin" header.

    • Nginx:
    if ($http_origin ~* (whitelist\.address\.one|whitelist\.address\.two)$) {
    add_header Access-Control-Allow-Origin "$http_origin";
    }
    
    • Apache:
    <IfModule mod_headers.c>
        SetEnvIfNoCase Origin "https://(whitelist\.address\.one|whitelist\.address\.two)$" 
    AccessControlAllowOrigin=$0
        Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e 
    env=AccessControlAllowOrigin
    </IfModule>
    
    • IIS 7.5+:
    <system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
            <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
        </customHeaders>
    </httpProtocol>
            <rewrite>            
                <outboundRules>
                    <clear />                
                    <rule name="AddCrossDomainHeader">
                        <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                        <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                            <add input="{HTTP_ORIGIN}" pattern="(https://(whitelist\.address\.one|whitelist\.address\.two))" />
                        </conditions>
                        <action type="Rewrite" value="{C:0}" />
                    </rule>           
                </outboundRules>
            </rewrite>
    </system.webServer>
    
    • If the cookie is used for storing session information then the cookie have to be "HTTP-only" and "Secured" one:
    Set-Cookie: sessionId=some_session_hash; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly
    
Classifications
  • CWE-352
  • CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
References