Infrastructure at your Service

Pascal Brand

Apache JMeter and Cross-Site Request Forgery (CSRF) token management

Introduction

In Nowadays web technologies a common defensive mechanism against Cross-Site Request Forgery (CSRF) attacks is to use a synchronizer token. This token might be unique for each request and thus it blocks us from using the recorded JMeter test session off the shelf.

This blog will describe how this CSRF feature can be handled in JMeter.

How to implement this feature

The solution is to identify and extract the CSRF token from the response data or header depending how is it has been set.
The site I was doing the Load test using JMeter is using a cookie to set the CSRF Token and adds a X-CSRFToken header to the following HTTP requests.

The HTTP Response header contains something like:

Set-Cookie: csrftoken=sTrKh7qgnuKtuNTkbwlyCv45W2sqOaiY; expires=Sun, 21-Jan-2017 11:34:43 GMT; Max-Age=31449600; Path=/

To extract the CSRF token value from the HTTP Response header, add a Regular Expression Extractor Post Processor globally.
This way if the token value is reset to a new value somehow, it will be dynamically updated in the following response.

Now configure it as follows:

Apply to: Main sample only
Field to check: Response Headers
Reference Name: csrfToken
Regular Expression: Set-Cookie: csrftoken=(.+?);
Template: $1$

Get the Response Cookie via the Regular Expression Extractor

DynCSRF_Regular_Expression

It is always better to have a user variable attached to the extracted value to be kept during the complete load test run.
select user defined variables and add a new variable with the same name as the reference name declared above in the regular expression Extractor.

DynCSRF_variable

The next step is to analyse each HTTP Request recorded in the scenario to replace the hard coded value for the X_CSRFToken header with the variable set by the Post Processor as shown below:

DynCSRF_HTTP_Header

To avoid having to check every request HTTP Header Manager as displayed above which can take some time and might introduce errors, a pre-processor can be used that checks the headers
and replace automatically the X_CSRFToekn hard coded value with the variable set by the post processor task. This kind of pre-processor can be time consuming and should be as simplest as possible. Thus I decided to not check if the X_CSRFToken exist in the request header and just call the remove header attribute and add the X_CSRFToken one to all requests. This worked fine for the site I was working on.

The pre-processor code used was the following:

import org.apache.jmeter.protocol.http.control.Header;

sampler.getHeaderManager().removeHeaderNamed("X-CSRFToken");
newValue=vars.get("csrfToken");
sampler.getHeaderManager().add(new Header("X-CSRFToken",newValue));

DynCSRF_BeasnShell

 

6 Comments

  • Candy Tellez says:

    Hi Pascal!

    First of all thank you for the post. Right now we are having problems with X_CSRFToken, we followed all the steps you mentioned in the post, but it is still failing :(. Looking at the results we saw something weird, we are not sure that this can be the problem but might be. After the variable passes the pre procesor the X_CSRFToken comes out encoded, is there any way it can show the value not encoded? because when we check the value before it passes re pre processor it is not encoded.
    Thank you very much for your valuable help and we are looking forward to your response.

     
    • Pascal Brand says:

      Hello Candy,

      Can you confirm the configuration you are having is the same ? I mean the csrftoken is set using a cookie and has to be injected back in the HTTP/S requests headers ?
      The preprocessor doesn’t encode the token. All it does is get the csrfToken value from the variable and set in in the subsequent HTTP/S requests headers.
      Make sure there is no typos in the variable name, neither in the cookie name.

      Hope this helps,
      Pascal

       
  • Hiren says:

    Hi Pascal, Nice Article. But i have few queries. could you please help me to solve out? As am extracting bearer token in jmeter.

    1. First i have added user defined variable and in next request i have extracted token by using regex.
    2. Now i have passed it on following request in header manager. as there were no authorization header displayed in HTTP header manager so i have added values in HTTP header manager as Name=authorization & Value= Bearer ${BEARER}. and finally it works. but my concern is that there are more than 50 request that i need to pass this values in all subsequent request in HTTP header manager. it has been time consuming while adding manually in each request.

    Could you please help me? or please give me your email id so i will email you with image.

    Regards

     
    • Pascal Brand says:

      Hello Hiren,
      I had a similar issue with Bearer token. It is not the same as the CSRF token. Bearer is a authentication token.
      I extracted it from the body of the first request to the web services with the regular expression below:

      access_token”:”(.*)”}

      put is in a variable named access_token and injected it in a pre-processor as below but only for the web services requests:

      import org.apache.jmeter.protocol.http.control.Header;
      import org.apache.jmeter.protocol.http.HTTPSamplerBase;

      String hostname = sampler.getDomain();

      String webserviceshostname = vars.get(“webserviceshostname”);

      if ( hostname.equals(webserviceshostname) ) {
      newValue=vars.get(“access_token”);
      if( newValue != “” ) {
      sampler.getHeaderManager().add(new Header(“Authorization”,”Bearer ” + newValue));
      }
      }

      Hope this helps,
      Pascal

       
  • Hiren says:

    Hi Pascal, Thanks for the quick response. The same way i tried and got 80% successes. but still i have queries. could you please look in to it.

    1. In request 221, I have passed user defined variable first(as you also mentioned in your answer)
    Image path: https://i.stack.imgur.com/N91Eb.png

    2. In request 222, I have extracted the token using regex(as you also mentioned in your answer)
    Image path: https://i.stack.imgur.com/RerEv.png

    3. In request 223 and all subsequent request, There are no authorization header defined in HTTP Header Manager. I have manually added values in HTTP header manager. Name = Authorization & Value= Bearer ${BEARER}
    Image path: https://i.stack.imgur.com/imNcn.png

    In above image see, there is no header in it and i have manually added name=”Authorization” & value= Bearer ${BEARER} (In your answer you mentioned that injected it in a pre-processor(IS IT BEANSHELL PREPROCESSOR?) as below but only for the web services requests: but how to add it? is there any way or approach that after adding user defined variable(in 221 request) and extracting token by regex(in 222 request) need to pass header values on all further request dynamically?

    Kindly advise. Looking forward to receiving your reply. Thank you. Hiren

     
    • Pascal Brand says:

      Hello Hiren,

      I think that the your issue is due to the place where you declared the variables. It must be global to be accessible in all requests.

      You can remove the test on the web services host name. It will then add the header dynamically to all requests. Having the regular expression extractor in the global part make it applied on all response body. If the bearer value changes, it will be taken in account automatically.

      Hope this helps,
      Pascal

       

Leave a Reply

Pascal Brand
Pascal Brand

Consultant & Middleware Technology Leader