Imagine you are a common user performing some tasks in a commercial application. An attacker evaluates the application and obtains all possible requests that the frontend sends to the server. She determines that some requests can be executed if a valid user is authenticated, so she develops a web application that includes her malicious requests. Next she publishes the application online and uses social engineering to deceive users into entering her application.
If the user from earlier in this scenario has a valid session running on that commercial application at the same time, the malicious requests can be executed without notifying the user. These requests could run any operation the web application accepts, from getting information to making modifications. This is the idea behind CSRF (CROSS-SITE REQUEST FORGERY).
CSRF attacks work by sending an HTTP request from an authenticated user’s browser to the application, which then commits an action without the target user providing authorization.
Here is a simple example of how a basic CSRF attack occurs:
An attacker discovers that when a client of Loremar Bank performs a transfer transaction, the bank’s application sends this request using GET method to the web server:
/transfer&amount=1000&user=123
The parameter user corresponds to the client ID.
So the attacker creates a malicious link and distributes it via a website.
/transfer&amount=1000&user=889
In this case, the attacker changes the ID.
A client user who was recently authenticated to the Loremar Bank site clicks the attacker’s link.
An HTTP Get request is made using his opened session. A cookie session is sent with the request (this is made by the user browser).
The web server (the bank) processes the HTTP Get request with the client’s authentication cookie.
The account is changed!
There are many techniques you can use to defend against CSRF. Let’s examine several of them and see the important role Zero Trust can play.
The first go-to solution to prevent a CSRF vulnerability is the use of a unique ID in the HTTP Request, also known as a CSRF header:
The application creates a valid list of unique IDs (created randomly).
A unique ID is appended to each link on the requested page prior to being displayed to the user.
The application checks the unique ID passed with the HTTP request.
If the unique ID is not present or is not valid, the request is rejected.
The use of CSRF per-request tokens is very helpful in preventing attacks. Let’s look at an example:
A client makes a request for a web page.
The server returns the web page along with CSRF token. For instance:
<input type="hidden" name="_csrf" value="bhxG6W57-x2GoA-mfq-ndIfDtDsEcstMGuDk">
The client requests an HTTP resource on a server, and attaches the CSRF token:
_csrf=bhxG6W57-x2GoA-mfq-ndIfDtDsEcstMGuDk
The CSRF token is validated by server, and the response is sent to the client.
When an attacker wants to conduct a CSRF attack he can send the HTTP request, but this request does not contain a valid CSRF token because the request did not initiate from the user. Thus, the request is blocked by the server and the attack attempt fails.
Using HTTP Headers is another method to prevent CSRF attacks, as a means for authenticating the requests. Let’s review some of the headers you can use:
Origin and Referer Header
Any application can send an HTTP request that includes an Origin or Referer header. That header indicates the URL domain that the requests originate from. With this information, the server can distinguish if the request was made from the original domain. If the domains are not the same, the request is blocked.
The origin header is only sent on HTTP POST requests. This is in contrast to a Referer header, which is also present on both HTTPS and HTTP requests.
Example:
Origin: https:// www.loremar.com:80
The referer header is set on all requests. The only time this header is not present is when the referring link has the attribute rel=noreferer set.
Example:
Referer: https:// www.loremar.com:80
There may be browsers or proxies that don't send a referrer header, so you must be cautious with this tactic. Whenever it is possible, you should check both headers. If neither header is present, it is safe to assume that the request is not valid and should be rejected.
Custom Request Headers
Custom Request Headers can be used in AJAX or API endpoints (API REST for example) and are another option to protect against CSRF attacks.
In this method, a custom header is added in the HTTP request and the server checks if the header is included. If the header is not included the server does not process the request. The value of the headers is not relevant.
Here is an example of a HTTP custom header:
X-MY-XSRF-HEADER: a867d-e2fcfafd-c600-4156-88ae-ca56babd24e1
When a browser generates a request to your website, it will attach the last known cookies the site sent to the request. This means that malicious cross-site requests could arrive at your web server with any security cookies you previously set.
The SameSite attribute is defined in rfc6265bis and tries to establish methods of defense against CSRF attacks by defining whether a cookie can be sent in cross-site requests.
Because modern browsers are improving their functions continuously, this attribute cookie is now completely supported in all the latest browser versions.
SameSite = Strict
Setting the "SameSite" attribute in "Strict" mode provides robust defense in depth against CSRF attacks. This setting blocks a cookie that is sent from anotherdomain.com to mydomain.com. Also, when clicking on a top-level link in a third-party domain which redirects to your site, the browser will block this cookie. This can force the user to log in again in your site. This setting can be a good option for applications that require a high level of security (for example a bank).
Example:
Set-Cookie: session_id=23093242342307235435; SameSite=Strict;
SameSite = Lax
In this setting, cookies are only sent in requests that occur within the same site. Unlike the “Strict” setting, “Lax”allows access to top-level requests via HTTP such as GET. In cross-domain POST requests or when loading a cross-domain site, the cookie will not be sent. This implies that it must be sent when navigating to the site through a top-level link.
Other cookies attributes also help with Cross Site attacks include:
Secure Attribute: This ensures the cookie will be sent only when using a secure channel such as HTTPS, which protects it from being passed in unencrypted requests.
HttpOnly Attribute: This attribute restricts the attack vendors by not allowing the cookie to be accessed via a client-side script such as JavaScript.
The simplest explanation of "Zero Trust" is that no user or device is granted inherent trust. Traditional IT network security is based on the perimeter concept, which places a wall between trusted and untrusted resources. Once an attacker gains access to a trusted resource like a local network, it is easier for him to access other resources in this trusted area. Zero trust security is a newer IT security model that requires any enterprise resource or user/device access to be strictly authorized. The access privileges should be as granular as possible to assure the principle of least privilege.
ZTNA (Zero Trust Network Access) is a set of cloud native technologies that operate on an adaptive trust model, where access is granted on a “need-to-know,” least-privileged basis defined by granular policies. ZTNA is a software-defined perimeter (SDP) implementation.
How It Works:
A user sends a request to the controller.
The controller determines a list of accepting hosts to which the user host is authorized to communicate.
The controller instructs to accept communication from the user host and any policy required.
The controller gives the list of authorized hosts and policies required.
The user communicates with the accepting hosts through the TLS connection.
SDP, software defined perimeter, is the architecture on which zero trust is instated. In February 2014, the CSA (Cloud Security Alliance) sponsored the Software Defined Perimeter Hackathon, an event challenging hackers to attack a server defended by a software defined perimeter (SDP). No attacks were reported.
In a ZTNA architecture, all requests are authenticated and verified before they are forwarded (proxied) to the backend application. This allows the adding of the controls we previously discussed without needing to change the application, i.e without having to modify the code. In other words, ZTNA helps protect from CSRF attacks before they reach the application - unlike the other security measures in this list.
CSRF is still a common vulnerability. Although there are some defenses, many applications lack the correct implementation.
It is important not to underestimate this type of vulnerability in application design, coding, and testing.
Implement all the possible CSRF mitigations you can apply to your software development.
Consider a Zero Trust architecture for your company. Although it is a continuously evolving framework, ZTNA can already help you prevent and defend against many application attacks.
To get started with zero trust, reach out to the team at Cyolo to learn more about the industry's most secure zero trust solution.
Author
Eran Shmuely is the Chief Architect and Co-Founder of Cyolo. Prior to Cyolo, Eran was the Senior Security Engineer at Salesforce and the Open-Source Security Research Leader at GE Digital.