CSRF stands for “Cross Site Request Forgery” and is a term that is used to describe a situation in which an attacker tricks a computer user into submitting a web request that they are unaware of performing, that is performed under their identity, and which is typically against their interests. An example might be an instruction to their online bank to transfer money out of their account and into the attacker’s account. Since the action is performed from the victim’s computer, it is indistinguishable from a legitimate and intentional request made by the victim. This obviously sounds fairly alarming! Let’s dig deeper into the mechanisms that make this possible.
When you are browsing a website most of the requests you make will be within the same website context, in that they will request resources and send requested actions to the same “origin” (essentially the same website domain).
However, it is very common for websites to store static content such as images and video on (and therefore fetched from) different sources (different domains) such as a Content Delivery Networks (CDNs). Many websites store scripts, images, and other static resources on CDNs in order to cache them closer to the “network edge” (nearer to the user than the server) and speed up delivery times.
When a website instructs a user’s browser to fetch a resource from a different domain or origin, the browser is making a cross-site request, loading content from one origin or domain (the CDN) within the context of another (the main site).
Cross-Site Requests are very widely used but can represent a security issue if a website instructs a victim’s web browser to perform an HTTP request to another website without the user’s intent, and in such a way that an action is performed that is against their interest. This is possible because in addition to simple “resource fetch” requests (such as loading an image), cross-site requests can also be made which elicit a changed state.
Forcing the victim to retrieve data doesn’t typically benefit an attacker because the attacker doesn’t receive the response, the victim’s browser does. CSRF attacks will therefore typically make HTTP requests that cause a state change on the target server – that is, that will perform a change of some record on the server, rather than simply fetching a resource. Examples will depend on the functionality of the targeted website but could include changing the victim’s registered details (in order to takeover their account), purchasing something using a victim’s details, or transferring money out of their online bank account (and into the attacker’s).
CSRF attacks rely on the fact that targeted web applications are unaware whether the requested action is a valid request made by the user or a malicious action made without them being aware. The latter case may occur when a victim for example clicks on a link in an email.
Cross-site requests are possible because they are sent to the target server from the victim’s computer, hence they inherit the identity and privileges of the victim and are indistinguishable from a legitimate request to the receiving server. This is made possible because a web browser will automatically include any credentials associated with a site, such as the user’s session cookie, in all requests to that site. Therefore, if the user is currently authenticated to a site , the receiving site trusts that the action has been legitimately requested and authorised, and will execute it.
Web applications often use session cookies as a mechanism to identify a user across multiple pages and clicks through a website. Once a user has authenticated with their password, the server wants them to have to avoid reauthenticating by entering their username and password for every single page load – that would get burdensome pretty quickly. Instead, once a user has proven their identity with a single login, the server assignes them a session cookie that is associated with their ID server-side. When a cookie is set for a specific website, the web browser sends this trusted token as part of the metadata of every future HTTP request to that domain, until the user logs out or the cookie expires.
However, this does mean that (because the password doesn’t have to be entered manually on every page load), the receiving site is actually extablishing a trust relationship with the user’s browser rather than with the user themselves. Normally, this is not a problem, however, since the user’s session cookie is sent with every request, attackers can abuse this established trust relationship and launch a cross-site request forgery attack that send requests within this trusted context but without your consent and without you noticing.
Any application that accepts HTTP requests from an authenticated user without having some check in place to verify that the HTTP request is unique and was initiated by the user is vulnerable to CSRF.
HTTP GET requests are used to request data from a web server. For example, when you enter a website URL in your web browser, your browser will send an HTTP GET request to the web server that hosts the website and fetch a resource. However if the server receiving the GET request is using a dynamic language server-side, it can also cause a state-change server-side before returning the requested resource, even though this isn’t perhaps strictly expected under the original specification (RFCs).
In an example CSRF attack using GET method, lets assume that a bank uses GET requests to perform bank transfers. An attacker can take a look at a valid GET request and modify it to one that performs an action instructing the transfer of money to themselves, for example:
http://bank.example/transfer?acct=ATTACKER&amount=10000
All the attacker then needs to do is to use some form of social engineering to get the victim to click on or load this URL. If the targeted user is logged into her online banking when she clicks the link, then the request will execute and the transfer will be performed.
It may seem unlikely that anyone is going to click on such a link. However the URL that the attack has crafted can be disguised as an ordinary link, masking the actual action performed:
<a href=”http://bank.example/transfer?acct=ATTACKER&amount=10000″>Click here to see your e-Birthday Card</a>
Only the link text, and not the URL would be displayed, masking its true nature.
It is not always necessary for the victim even to click on the link directly. Sometimes, GET requests are triggered automatically by certain HTML tags or by JavaScript, without requiring user interaction. For example, the <img> tag will automatically generate a GET request to retrieve the image resource, meaning it is only necessary to include an image tag in an HTML format email to the victim – the attack would be launched without the victim even clicking on a link, as soon as they opened the email and the image loaded.
HTTP POST requests are used to send data to be posted on the web application. For example, when you submit a web form, such as a login or contact form, your browser generates an HTTP POST request. The request contains data submitted through the web form. A web application that uses POST requests for state change actions is just as vulnerable as one that uses GET requests. This is because although the malicious link cannot be embedded in elements such as IMG tags, it can instead be embedded using a FORM tag that is then executed automatically using JavaScript.
As we saw above, our hypothetical attacker was able to launch a CSRF attack against our bank because they were able to form requests consisting of known parameters and value. For example, in our URL from above the parameter “acct” is used for the recipient account ID and the value “ATTACKER” is inserted as the value:
acct=ATTACKER
However, this means that requests can be validated by the receiving application (the online bank in our scenario) to verify that the parameter and values provided in a URL are valid and form a legitimate request. By adding an additional parameter with a value that is unknown to the attacker and which can be validated by the server, potential CSRF attacks can be thwarted.
In order to do this, legitimate requests should contain an identifier that is unique to each request and is not valid if re-used in subsequent requests. This is often done by generating a hidden field on legitimate pages within the application that contain a one-time use token known as a nonce (number-used-once) that protects against replay attacks and parameter value prediction that CSRF relies on. When a form is submitted from a legitimate page within the application, the nonce (token) is appended to the HTTP request on submission. However, an attacker has no way to “read” a legitimate page within the application from the victim’s perspective, meaning that any malicious forms or URLs crafted by an attacker and send to a victim would be rendered harmless since the server would reject it as invalid in not containing a valid nonce.
It is important that nonces are not predictable therefore, which means that they must be both strongly (i.e. cryptographically) random as well as being immune to replay or re-use by being rendered dynamically for every unique link or form on every page for every user. Web frameworks usually either have built in, or recommended extensions which provide, CSRF protection; these should be used in preference to inhouse developed solutions since they are more likely to be robust and secure.
A newer method which can be partnered with tokenised forms strategy outlined above is the use of the SameSite cookie attribute. This attribute helps the browser decide whether to send cookies along with cross-site requests (as it previously would have done always by default). This method takes a different approach to the token approach in that it instead breaks the CSRF pre-condition or reliance on cross-site requests executing within an authorised context (the user being logged in to the target application and hence all actions from them being trusted).
When set to Strict the browser will not send the session cookie to the target site. Any CSRF link clicked on by the user will therefore be executed outside of a user context and hence be ineffective. In our example URL from earlier:
http://bank.example/transfer?acct=ATTACKER&amount=10000
we can see that nowhere is the source of the account transfer detailed (since this is looked up by the target application from the context of the authorised user session) – without this information the malicious request cannot be executed/lacks context, and so the request would be rejected, and the attack fail.
It should be noted that setting the SameSite cookie attribute to Strict can negatively impact the user experience since resources from a third party sites which require authentication cannot be loaded, and even following a link to the third party site would not include the cookie and therefore the user would appear to be logged out.
Another option for the SameSite attribute is to set it to Lax, this is now the default in most browsers. Set to Lax, the browser will send the cookie in requests that originate from another site if it is a GET request and the request was from a top-level user initated navigation. Other requests such as POST, or those initated by scripts will not include the cookie.
The Lax configuration is more user friendly, however still allows the possibility for CSRF attacks, since applications may implement sensitive actions using GET requests or may honour requests that use an unexpected request method (i.e. they were expecting POST but will still process a GET request). Therefore an attacker could include a malicious link to a vulnerable application on their website and entice a user to click it. This is not as subtle as the attack used to be since the user is redirected to the vulnerable application, however by that point it may be too late since the attack has taken place. Therefore SameSite=Lax is only considered a partial mitigation against CSRF attacks.
Note the SameSite attribute can also be set to None which instructs the browser to send the cookie in all contexts (i.e. the behaviour before the SameSite attribute was introduced), this is not recommended.
The SameSite attribute, it is not currently universally supported and exact implementation may differ between browsers ( https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#browser_compatibility).
While SameSite cookies are a valuable tool to be used when defending against CSRF, Anti-CSRF Tokens described above are still the recommended defence.
In addition to the two primary techniques outlines above, several additional techniques outlined below can also be used as part of a defense in depth strategy to help prevent CSRF attacks, even if they should not be relied on exclusively on their own.
An additional defence pattern available to web application developers is having their web applications check the Referrer request header in HTTP requests. Ensuring that the HTTP request has been generated within the context of the original site means that requests that are maliciously formed will not be valid when evaluated by the target server.
A relatively weak defence but which may also help as part of a defense in depth strategy as a backstop if other measures fail is to implement a short or aggressive session inactivity timeout for authorised user sessions, whereby users active sessions are invalidated after say 5 minutes since the last detected action within an authorised session. This has the advantage that it reduces the attack window or length of time that a target application may be targeted by an attacker – if the user becomes logged out due to inactivity, then CSRF attacks against that web application will fail to execute within their context and the attack will fail.
A final pattern that can be used by web application developers is to perform sensitive action reauthentication – that is, upon performing any high-risk or critical transaction (such as a bank transfer), display an additional decision or confirmation to the user. This could be a confirmation dialogue at its most simple, however since that it is subject to bypass via cross site scripting for example, then a stronger requirement would be for the user to enter their password (even though already logged in) in order to verify that they authorise the transaction. A CSRF attacker would not know the password of the user and therefore the transaction could not be performed via a CSRF attack.
Although CSRF is fundamentally a server-side problem that lies in the failure by targeted web applications to adequately validate the source of web requests that perform state change on the server, end users can help to protect themselves by getting into the habit of explicitly logging out of websites when they are finished – particularly where the application is critical, such as online banking.
Lastly – but by no means least! – AppCheck makes it easy to test if your own websites and web applications are vulnerable to CSRF – as well as other vulnerabilities such as the OWASP Top 10. Our AppCheck vulnerability scanner includes a custom CSRF scanner plugin and scans can be launched in seconds using pre-defined scan profiles built by our security experts.
No software to download or install.
Contact us or call us 0113 887 8380
AppCheck is a software security vendor based in the UK, offering a leading security scanning platform that automates the discovery of security flaws within organisations websites, applications, network and cloud infrastructure. AppCheck are authorized by te Common Vulnerabilities and Exposures (CVE) Program aas a CVE Numbering Authority (CNA)