One way that your web-site might be vulnerable to an attack is via Cross Site Request Forgery (CSRF or XSRF).
If you’ve ever been logged into a web-site - say Twitter for example - and you open a separate tab, then type in a twitter account, for example: https://www.twitter.com/paul_michaels, you’ll notice that when the site opens, it opens already logged in for you - which is very helpful. Imagine having to re-log-in every single time you wanted to view a tweet or a profile.
Okay, now imagine that, instead of typing that into the browser, you click the link above - try it! What - it didn’t take you to Twitter, but it took you to the home page of this blog? In fact, that’s exactly how a CSRF attack would work in practice. If you were already logged into that site, the link could have executed a CSRF attack.
Cross Site Request Forgery works on the premise that the victim of the attack is actually logged into a given website with valid credentials, and the attacker knows the exact format of a valid request. So, for example, I can take you to my Twitter profile, because the format of that is well known. Nobody, least of all Twitter themselves, want you to have to mess around logging in again.
But what about if you want to actually post a Tweet? Here’s the Url that gets called:
It’s a little difficult to demonstrate, because Twitter operates over HTTPS, so the traffic is encrypted, but the gist is that, even if I managed to create a site that copied this message exactly, the Tweet would not get created. Let’s have a look at replicating such an attack.
To Reproduce
Your first step is to create a really bog standard web site - the default MVC template will do. It might also help to demonstrate if you don’t use HTTPS.
Launch the web-site with F12 tools and make a given request. For example, click the “Contact” link on the default site. Make a note of the URL and the form data for the request:
Leave the app running and logged in.
Now Attack
Create a new web app with the following code:
[code language=“html”]
Run CSRF Attack on MyApp
Obviously, don't use that code - otherwise you'll cause over a thousand pounds to be transferred from my account to yours! Replace the URL with whatever the URL from the above site was, and the values with whatever values were behind your grey box above. You can use POST or GET or whatever else you like. What you'll notice is that clicking your button interacts with the site you created in the same way as it would if you were on your site. The "SendLoadsOfMoney" is obviously an example that takes it to the extremes, but the principle is correct.
# Fix
To fix this in MVC is very easy.
Add:
``` csharp
[ValidateAntiForgeryToken]
If you add this to the controller method, you should start seeing this error:
The required anti-forgery cookie “__RequestVerificationToken” is not present.
Your calling code might look like this:
[code lang=“html”] <form action=“Test” method=“post”> <input type=“submit” value=“Test3”>
The next step is to add a call into the client; for example:
[code lang="html"]
<form action="Test" method="post">
@Html.AntiForgeryToken()
<input type="submit" value="Test3">
</form>
So far, so good. This works for Asp.Net Mvc Core and Framework, but not for ApiControllers! The decorator [ValidateAntiForgeryToken] has no effect on an ApiController out of the box (and worse, you’ll never know it without launching a specific attack on your ApiController). So what can you do?
One option is to implement a custom token as described here. I would treat this as a specific case for ApiControllers only, though.
References
https://github.com/zaproxy/zaproxy/wiki/Downloads
https://www.owasp.org/index.php/OWASP_Testing_Project
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1