Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How request.getHeader("Origin") prevents from Cross Site Request Forgery attacks?

I am working on Web Application and asked to run the VAPT against it before release.

Then I downloaded Vega and quickly scanned my webapp and came across a VAPT issue, as follows:

Vega has detected that the resource has set an insecure Cross-Origin Resource Sharing (CORS) access control. CORS provides mechanisms that allow a server to restrict resource access for cross-site requests to certain trusted domains. The server in question has allowed resource from any origin by setting the value of the "Access-Control-Allow-Origin" response header to a wildcard value. This presents a security risk because any site can issue requests to access resources, regardless of origin.

Then I started finding a solution to fix it and came across this post and implemented a filter as suggested in the answer as follows:

@Component
public class CORSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods",
                "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(request, response);
    }

    public void destroy() {
    }
}

Now, when again I scanned the Vega against webapp, it doesn't listed the same issue again, which I believe saved my webapp against CSRF attacks.

Now, after reading this post, I am thinking over how request.getHeader("Origin") prevents from Cross Site Request Forgery attacks, as whatever the origin is either https://webapp.com or https://evil.com, request is always valid for the application as I am picking "Access-Control-Allow-Origin" from request header itself.

Can anyone please help me in understanding the concept, how setting the request.getHeader("Origin") saves from CSRF attacks?

Thanks.

Understanding after reading @rism answer and Patrick Grimard post :

When a client application makes an AJAX request, the browser initially sends a preflight OPTIONS request to server to determine what the client is permitted to do, for request other than GET and that's the reason we should set Access-Control-Allow-Origin either to origin or specific domain as part of response header.

Taking the example of POST, when client send request, browser first makes preflight OPTIONS request to the server and the server response to the OPTIONS request contains headers that instruct the browser for which all origin request is permitted. Besides adding response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); site is still vulnerable so we need to explicitly whitelist the IP's either in Apache(for application deployed in cluster) as done here or in Tomcat as described here.

Still I have one doubt, if we are restricting the IP address at server level itself than do we really need to set "Access-Control-Allow-Origin" as part of response header?

like image 452
Arpit Aggarwal Avatar asked Mar 12 '23 06:03

Arpit Aggarwal


1 Answers

It helps to understand the purpose of a CSRF attack. They are NOT about "stealing" your data. They are, as the name suggests, about "making forged requests across sites" aka Cross Site Request Forgery aka CSRF.

The purpose is to alter state on the server with the canonical example involving a bank account. With a CSRF attack we're trying to forge a request (transfer $100) in your name.

So the simple example is the attacker injecting a script or a hidden form etc into a page on any site e.g. www.cutekittens.com and have that script target a specific site e.g. www.mybank.com hence the term Cross Site.

The idea is that you as the victim would be logged into both sites at the same time and the bank site has lax security. While you're looking at cute kittens at www.cutekittens.com, the attacker has injected a cross site attack script into one or many of it's pages. That scripts purpose is to make requests on your behalf to your bank, www.mybank.com, to transfer $100 dollars.

Again note here, the attacker is not stealing your data, they are instead trying to make forged requests in your name to steal your money / whatever. This is not a man in the middle attack (MITM), it is a request forgery attack. In a CSRF, the attacker doesn't see or need to see your data, they just find a way to act as though they were you. The subsequent purpose of this might to get at your data, e.g change your password etc, but the attack itself is about making forged requests, it's not about interception.

So one way the bank can secure itself and its' customers is by specifically stating what sites may and may not make requests to it via CORS headers.

And if they don't specifically include www.cutekittens.com, then even if the attacker manages to inject their malicious script into a page on the www.cutekittens.com site, and even if you happen to be surfing both cutekittens and your bank site at the same, and even if the attack script is executed, the request to www.yourbank.com will be dropped (after preflight for a POST) because the bank has not sent down a header to the browser ACCESS-CONTROL-ALLOW-ORIGIN : www.cutekittens.com to specifically authorise the request.

And so you're right. All you've done by replacing the static * value for this header with the dynamic request.getHeader("Origin") is get Vega off your back. Your site is still potentially vulnerable to this attack if it's been poorly written because it will reflect back www.cutekittens.com which is presumably not what you want.

One reason you'd use the request.getHeader("Origin") instead of * is when you want to send credentials to the server. You can't send credentials e.g. cookies etc on a CORS AJAX request, to a server using only * and so in this case you'd dynamically reflect back the origin to the client.

But then by doing this you really need to make sure you're mitigating risk in other ways. In this case, you'd also typically white list what you will and won't reflect back. e.g. portal.mybank.com might be on the list but www.cutekittens.com would not. So that would be the next step you could implement, if you're going to use dynamic origin reflection.

like image 130
rism Avatar answered Apr 06 '23 12:04

rism