Understanding and Preventing CSRF Attacks

While there are many prevailing Cross-site scripting attacks on the internet today, CSRF attacks remain one of the highest according to the OWASP Foundation.

A Cross-Site Request Forgery occurs when an attacker carries out a transaction using a malicious website, email, blog, instant message, or program causing a user’s web browser without their knowledge to perform an unwanted action on a trusted site for which the user is currently authenticated. A malicious HTTP request is slipped into the user's web browser by the attacker so that when it is called, the web application takes the action desired by the attacker.

The impact of a successful CSRF attack is limited to the loopholes exposed by the vulnerable application. For example, this attack could result in the unauthorized transfer of funds, change of password, or purchase in the user’s context.

The security problem is caused by the statelessness of the HTTP protocol, since after a one-time authentication the browser implicitly sends its session data to the server every time. If the CSRF attack goes undetected, the web application becomes vulnerable.

CSRF has the following characteristics:

  • Involves websites or web apps that rely on a user’s identity.
  • Exploits the site’s trust using that identity and tricks the user’s browser into sending HTTP requests to a target site.
  • Involves HTTP requests that have harmful side effects.

While CSRF refers to any form of data change via HTTP request, session riding refers to data manipulation through a valid user session. Session riding is a special case of CSRF where the session identifier is transported using basic/digest authentication or a cookie.

In a nutshell, a typical CSRF attack happens as follows:

  • The attacker leads the user to perform an action like visiting a web page or clicking a link. This action sends an HTTP request to a website on the user's behalf.
  • The request is processed as a legitimate request from the user if an authenticated session is active on the trusted website.

How are CSRF Attacks Executed?

In the OIDC flow, CSRF attacks can occur against client callback URL where an attacker injects their own authorization code or access token that can induce the client to use an access token associated with the attacker’s protected resources rather than the user’s.

CSRF vulnerability is based on the user's active session which is authenticated using session management.

Typically, Session Management on a web application is based on cookies. With each request to the server, the browser sends the related cookie that identifies the current user's session and the specific actions the user can perform on the website. Any request sent with these HTTP credentials or cookies will be considered legitimate even though the user would be sending the request on the attacker’s command from a different website.

An attacker could authorize an authorization code to their own protected resources on an authorization server. They can then abort the redirect flow back to the client device and trick the user into executing the redirect back to the client. The client receives the redirect, fetches the token(s) from the authorization server, and associates the user’s client session with the resources accessible with the token.

Impact

The user accesses resources on behalf of the attacker while the resulting impact depends on the type of resource accessed. For example, the user may upload private items to an attacker’s resources. Or, when using OAuth in third-party login scenarios, the user may associate his client account with the attacker’s identity at the external Identity Provider. In this way, the attacker could easily access the user’s data at the client by logging in from another device with his credentials from the external Identity Provider.

CSRF using GET and POST Requests

Clients MAY use the HTTP GET or HTTP POST methods to send the Authorization Request to the Authorization Server.

The GET method should not be used to perform state changes and should never cause any data changes.

However, some web apps still use GET instead of POST to perform state changes for operations such as changing a password or adding a user.

When the users click the link provided by the attacker using social engineering, they are directed to the attacker’s malicious site. This website executes a script that triggers the user’s web browser to send an unsolicited request without the user being aware. However, on the server side it appears as if the user sent the request because it includes cookies used to verify that the user's identity.

Most state-changing requests are done using HTTP POST requests. This means that web apps are more likely to accept POST instead of GET when a state change is involved. In the case of POST, the user’s browser sends parameters and values in the request body and not the URL as in the case of a GET request. The attacker can design a malicious website to include JavaScript in the request body that causes the user’s browser to send an unsolicited POST request, as soon as, the page loads.

Preventing CSRF Attacks using OIDC

In OIDC, the ‘state’ parameter is used to mitigate CSRF attacks. In order to prevent CSRF attacks on callback, the client needs to implement CSRF protection by checking that the state parameter exists in the user’s session when an authorization code response arrives in exchange for the access token to the client callback URL.

Important OIDC Standard Considerations

In the OIDC flow, the CSRF attackers initiate the attack during the Authentication Request. Thus, here are some important definitions to know.

Authentication Request

An Authentication Request is an OAuth 2.0 Authorization Request that requests the end-user to be authenticated by the Authorization Server.

OpenID Connect uses the following OAuth 2.0 request parameters with the Authorization Code Flow:

Parameter Type Mandate Description
scope String Required OpenID Connect requests MUST contain the openid scope value. If the openid scope value is not present, the behavior is entirely unspecified. Other scope values MAY be present. Scope values used that are not understood by an implementation SHOULD be ignored.
response_type String Required OAuth 2.0 Response Type value that determines the authorization processing flow to be used, including what parameters are returned from the endpoints used. When using the Authorization Code Flow, this value is code.
client_id String Required OAuth 2.0 Client Identifier valid at the Authorization Server.
redirect_uri String/url Required Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider. The Redirection URI MAY use an alternate scheme, such as one that is intended to identify a callback into a native application.
state String Optional but Recommended Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.

In the case where the OIDC flow is initiated by an IdP, the CSRF attack cannot be prevented by them because the state parameter needs to be generated and managed by the client in order to correlate the state with the application user’s session.

One possible solution which can be performed by the client to mitigate CSRF attacks in IdP initiated OIDC requests, is by verifying the ‘Referer’ headers of the incoming HTTP requests.

Custom Request Headers

One of the common ways to protect against CSRF according is to include anti-CSRF tokens on state-modifying requests. For a more robust layer of defense, you can add custom headers as defined by OWASP which is particularly well suited for AJAX or API endpoints. This defense relies on the same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin.

Custom HTTP headers such as X-Requested-With can be used to prevent CSRF attacks, because this header cannot be added to the request cross domain without the consent of the server via Cross-Origin Resource Sharing (CORS). By default, browsers prevent sites from sending custom HTTP headers to another site using JavaScript but allow sites to send custom HTTP headers to themselves using XMLHttpRequest. If a request comes into a REST endpoint without the custom header, then the request will be dropped.

To use custom headers as a CSRF defense, a site must issue all state-modifying requests using XMLHttpRequest, attach the custom header (e.g. X-Requested-with), and reject all state-modifying requests that are not accompanied by the header. For example, the prototype.js JavaScript library uses this approach and attaches the X-Requested-By header with the value XMLHttpRequest. Google Web Toolkit also recommends that web developers defend against CSRF attacks by attaching a X-XSRF-Cookie header to XMLHttpRequest that contains a cookie value. The cookie value is not actually required to prevent CSRF attacks since the mere presence of the header is sufficient. For example, to defend against login CSRF, the site must send the user’s authentication credentials to the server via XMLHttpRequest.

This works because XMLHttpRequest does not allow an attacker to make a request to a third-party domain by default. Thus, it is not possible for an attacker to forge a request with a spoofed X-Requested-With header. You can simply verify the presence of this header and value on all your server-side AJAX endpoints in order to defend CSRF attacks. This approach does not require UI changes or server-side state changes which is particularly useful for REST services.

Important Note: This method also prevents any direct access from a web browser to that REST endpoint. Web applications using this approach will need to interface with their REST endpoints via XMLHttpRequest or similar technology.

A request with custom headers causes the browser to automatically send a request to the endpoint using the OPTIONS verb. If the server-side application recognises the OPTIONS request, it will reply with a header showing which headers will be allowed from the calling domain.

The attempt to send X-Requested-With in a cross-domain POST results in an OPTIONS request requesting this header be allowed.

If the server-side is not explicitly configured to allow this (i.e. no Access-Control-Allow-Origin to allow the domain and no Access-Control-Allow-Headers to allow the custom header), The header is not allowed because the domain is not configured for CORS.Therefore if CORS is not allowing the attacker’s domain to send extra headers, it mitigates CSRF.

Here are the steps to follow:

1. Set the custom header in every AJAX request that changes the server-side state of the application. Example: X-Requested-With: XmlHttpRequest.

2. In each server-side method handler, ensure a CSRF check function is called.

3. The CSRF function examines the HTTP request and checks that X-Requested-With: XmlHttpRequest is present as a header. If it is present, it is allowed. If it isn’t, an HTTP 403 response is sent and logged in the server-side.


We've come to the end of our discussion on Preventing CSRF Attacks. If you have any questions or need to know more, please contact our support team for further assistance.

We'll be happy to help. Thank you!



results matching ""

    No results matching ""