BreadcrumbHomeResourcesBlog What Is CSRF & How To Load Test CSRF-Protected Websites January 3, 2023 What is CSRF & How to Load Test CSRF-Protected WebsitesPerformance TestingBy Dmitri TikhanskiMore and more sites, applications, and application frameworks are expected to start implementing protection from Cross-Site Request Forgery (CSRF) in the very near future. While this is an exciting development in terms of application security, it does present challenges when it comes to automated load testing. This post will take a closer look at what CSRF is and show you how to bypass CSRF protection in your JMeter test. Table of Contents:What is CSRF?CSRF & JMeterExtracting the CSRF Token With JMeter Post-ProcessorsWhat is CSRF?Cross-Site Request Forgery is an attack that forces the user to execute unwanted actions on a site where he is authenticated. Thanks to social engineering (malicious links sent via chat or email) or XSS vulnerabilities, the user ends up making requests he never intended to make. Here are a few ways that CSRF can impact end users: Logging the user out.Changing their password.Gaining access to a restricted resource.Escalating the attacker’s privileges for a certain web application.CSRF attacks are made through the user’s identities, such as headers, cookies, credentials, and privileges. In short, anything associated with the target user’s session - starting from IP addresses and ending with Windows Domain credentials - can be used against them. These dangers from CSRF are why different content management systems and frameworks like Drupal, .NET Framework, and Django have built-in protection from CSRF requests. This means that developers do not usually need to worry about implementing CSRF protection themselves. CSRF & JMeterFrom the end user’s point of view, CSRF protection is transparent. On the protocol level, CSRF protection is an additional mandatory dynamic parameter, such as:CookiesHeadersRequest ParametersWhen a real-life user surfs a CSRF-protected website with a web browser, the browser’s CSRF security token can be set (for example this can be set with a JavaScript function). Now, here’s where JMeter’s “not being a browser” issue really becomes a limitation. As it’s not a browser, it can’t execute a client-side JavaScript and therefore can’t generate and record a proper CSRF token. To resolve the challenges raised by CSRF sites, you will need to use a JMeter Correlation. Here, I’m referring to the software testing definition of “correlation”: the process of handling dynamic parameters by extracting them from a previous response, storing them as variables, and adding them to the next request as a parameter. Extracting the CSRF Token With JMeter Post-ProcessorsLet us inspect two recorded requests to a Django website to see how they are different. If you’re not comfortable recording JMeter tests, it is worth checking out one of the following guides:JMeter's Superpower: The HTTP Proxy ServerRecording HTTPS Traffic with JMeter's Proxy ServerBlazemeter Extension for Google ChromeI would recommend using the BlazeMeter Chrome Plugin since you will not need to worry about proxies, SSL certificates, excluding common unwanted assets, etc. Attempt One:Attempt Two:As you can see, we need to correlate something called “csrfmiddlewaretoken”. In order to do this, we need to inspect the previous response details. The View Results Tree listener offers the easiest way to see details of requests, responses and debugging tests. Run the Recorded Load Test ScenarioLet us add the View Results Tree listener to our recorded test plan and see the response details of the request before login.Select the request before the actual login attempt (the failed one) in the View Results Tree listenerSwitch to the “Response Data” tab - as this holds the actual server responseType “csrf” into the “Search” input and click the “Find” buttonVoila! We have a hidden input named “csrfmiddlewaretoken” and it looks like its value attribute is holding the dynamic CSRF token needed for a successful login. <input type='hidden' name='csrfmiddlewaretoken' value='sTrKh7qgnuKtuNTkbwlyCv45W2sqOaiY'/>Based on the response nature, you can use the following Post-Processor options: Regular Expression Extractor XPath ExtractorCSS/JQuery ExtractorJSON Path Extractor Please note that in all cases, the ‘Reference Name’ is the name of the JMeter Variable where the extractor result will be stored. This name can be anything as long as it is meaningful. For example: if you set ‘TOKEN’ as the Reference Name, you will be able to access this variable as ${TOKEN} later on in the script. Regular Expression Extractor:Apply to and Field to check: depends on where you expect the value to appear. In my case it’s “Main Sample Only” and “Body”Reference Name: REGEX_TOKENRegular Expression: <input type='hidden' name='csrfmiddlewaretoken' value='(.+?)'/>Template: $1$XPath ExtractorIf your response is not XML/XHTML compliant, check Use Tidy boxReference Name: XPATH_TOKENXPath Query: //input[@name='csrfmiddlewaretoken']/@valueCSS/JQuery ExtractorReference Name: CSS_TOKENCSS/JQuery Expression: input[name=csrfmiddlewaretoken]Attribute: valueTechnically, you can use any of the above approaches.We typically recommend using the Regular Expression Extractor whenever possible because it’s the fastest and least memory-consuming way to correlation. On the other hand, if there’s a complex markup, it might be easier to use the XPath or CSS/JQuery as Regular Expressions are fragile and sensitive to any changes (such as extra spaces, line breaks, attributes location etc.). If you are sure that the entity you are trying to extract is more or less “static,” your best bet is to use the Regular Expressions. But there could be an easier way as CSRF Tokens can be found in other response parts. So let’s go back to our View Results Tree listener and take a look at the “Response Headers” section on the “Samper Result” tab for the same request.Construct CSRF Middleware Token Request ParameterIn the following image, you will see that the “csrftoken” cookie value is exactly the same as “csrfmiddlewaretoken”. Therefore, it can be used to construct the relevant “csrfmiddlewaretoken” request parameter.Set-Cookie:csrftoken=sTrKh7qgnuKtuNTkbwlyCv45W2sqOaiY; expires=Sun, 20-Dec-2015 11:34:43 GMT; Max-Age=31449600; Path=/To extract this parameter from the Set-Cookie header, add a Regular Expression Extractor Post-Processor as a child of the request penultimate to the login request. Now configure it as follows:Apply to: Main sample onlyField to check: Response HeadersReference Name: CSRF_TOKENRegular Expression: Set-Cookie: csrftoken=(.+?);Template: $1$Get Response Cookie via the Regular Expression ExtractorNow is a good time to replace a hard-coded recorded “csrfmiddlewaretoken” request parameter value with the one we extracted from the “csrftoken” cookie. To do this, just use the “Reference Name” you defined in the extractor postprocessor as follows:${CSRF_TOKEN}${__V(CSRF_TOKEN)}Both approaches will work fine. However, the second one uses the __V function, which allows the evaluation of nested variables. So feel free to replace the recorded value with one of the JMeter Variable references shown in the following image.Pass a JMeter Variable as a Request ParameterNow we are ready to re-run a recorded script with the correlation enabled. Again, the View Results Tree listener is the best way to see the requests/responses details. Proof of Login SuccessLet us take a closer look at this ‘Proof of Login Success’ picture:The second request, which failed during the first recorded scenario, now passes.The “Logout” and “Profile” links also confirm that the user is authenticated.The penultimate request reports an error (shown by the red font and exclamation mark) as it hasn’t been correlated and the CSRF token doesn’t match the server’s expectations. If you are sure that your request is correct and the token is good, but you are still unable to login, double-check other request parameters, such as the: Origin header.Referer header.Host header.Any cookies other than “csrf” ones.The reason to check these parameters is because it is possible that the recorded headers will work in a test environment but fail in staging or production due to an origin mismatch. Bottom LineThis blog post showed how you can deal with CSRF protection in your Apache JMeter test script. The same approach can also be taken for any other scenario which assumes correlation. Just a few final things: Remember that the CSRF token won’t necessarily have “csrf” in its name. Also, a developer can implement his own approach and the application under test might expect something different ( i.e. a specific HTTP Request Header rather than a parameter). Being attentive to anything that changes from request to request and keeping your eyes open is the key to a robust and reliable JMeter test. Learn how you can scale your JMeter testing with BlazeMeter. Try BlazeMeter for free today. Start Testing Now
Dmitri Tikhanski Contributing Writer Dmitri Tikhanski is a Contributing Writer to the BlazeMeter blog.