It is believed that front-end development engineers are very familiar with the concept of CROSS-site Request Forgery (CSRF), sometimes abbreviated as XSRF, which is a malicious use of websites.

Although it sounds like cross-site scripting (XSS), it is very different from XSS, which exploits a trusted user within a site, whereas CSRF exploits a trusted site by masquerading as a trusted user’s request.

There are many ways to defend against CSRF attacks. One of the simplest and easiest ways to implement is to add information that the attacker cannot forge in the request initiated by the client to the server, and the information is not stored in cookies. Technically speaking, when the client sends a request to the server to perform some sensitive operations (such as transfer and deduction using HTTP POST), the server generates a token randomly and returns it to the client. The client’s next action must be to take the server-side token as a parameter in the HTTP request. At the same time, when the server allocates the token to the client, it also adds a token verification mechanism. If there is no token in the request or the token content is incorrect, the request may be rejected as a CSRF attack. This token is commonly called a CSRF token.

All this is to introduce the topic I want to discuss in this article. Suppose I want to test the performance of an OOdata Service to create a Service Ticket using jMeter. Because creation, unlike read operations, has a Persistence side-effect on the system after execution, the server-side implementation incorporates CSRF token verification. This means that if we were to construct concurrent HTTP POST requests directly with jMeter, we would not be able to complete the test. These requests would be rejected by the server because they do not contain the CSRF token.

According to the CSRF attack and defense principle described above, the CSRF token is generated randomly on the server side and cannot be forged by the client side using any technique, because in order to test the interface HTTP post operation to create a Service Ticket, we must construct a pre-HTTP GET request for it. It is used specifically to GET the CSRF token returned by the server, and then to construct the actual HTTP POST request for performance testing, attaching the CSRF token obtained in the first GET request to the header of the POST request.

This article describes how to maintain and configure this set of dependent requests in jMeter.

Of course, if you don’t like using jMeter, you can write your own code to implement it. Refer to the Java code IMPLEMENTATION I put on Github.

The advantage of using jMeter is that this performance testing requirement can be achieved through simple configuration with no programming required, and testers with no development background can do it on their own.

First let us have a look how JMeter could archive the same without even one line of programming.

My project in JMeter is displayed with the following hierarchy. I have configured with “Number of 5 threads” in my thread group, so once executed, the response time of these 5 threads are displayed in result table together with average response time.

As you can see from the following figure, because an HTTP GET with a CSRF token logically must precede an ACTUAL HTTP POST request that needs to test performance, this actually constitutes a transaction-transaction. So I used the Transaction Controller provided by jMeter to manage it.

Some key points for this JMeter project creation

(1) Since now one thread should cover both XSRF token fetch via HTTP get and Service request creation via HTTP post, so a transaction controller is necessary to include both request.

(2) Create the first HTTP request to fetch XSRF token. The setting could be found below: Adding a HTTP header field with name as X-CSRF-token and value as “fetch” :

Fetch is assigned to the header of the HTTP GET request with a field named X-CSRF-token. After receiving the request, the server knows that it is a CSRF token request initiated by the client. The server responds to the request by sending the created random CSRF token back to the client in the form of an HTTP response header field.

The next question is, after the server returns a valid CSRF token to the client, how does jMeter read that token and use it for subsequent requests?

Fortunately, jMeter provides regular expression extractors that make it easy to extract tokens from HTTP response structures.

Create a Regular Expression Extractor to parse the XSRF token from response header and stored it to a variable named “jerrycsrftoken”.

The following figure constructs a jMeter regular expression extractor that works in the header field of the HTTP response and stores the resolved token value in the variable JerryCsrFToken.

Before you continue, please make sure that the XSRF token is correctly parsed from request header, which could be confirmed by printing it out in a debug sample:

After the request is constructed, we first try to run it to make sure we actually see the resolved CSRF token in the variable JerryCsrFToken.

(3) Create another HTTP request with type POST.

At this point, we are ready to start constructing the HTTP POST, the creation request for the Service Ticket, for the real performance test.

Just paste the following text to the TAB “Body Data” :

--batch_1
Content-Type: multipart/mixed; boundary=changeset_1

--changeset_1
Content-Type: application/http
Content-Transfer-Encoding: binary

POST ServiceRequestCollection HTTP/1.1
Content-Length: 5000
Accept: application/json
Content-Type: application/json

{
"ServicePriorityCode": "2"."Name": {"content": "Jerry Testing ticket creation via JMeter ${uuid} "},
"ServiceRequestDescription": [{"Text": "Piston Rattling 1 - Generic OData Test Create"."TypeCode": "10004"
},
{
"Text": "Piston Rattling 2 - Generic OData Test Create"."TypeCode": "10007"
}
]
}
--changeset_1--

--batch_1--
Copy the code

In the body text I use a user-defined variable ${uuid} which we could create it in last step. And for this post request, use the XSRF token fetched from previous HTTP get request.

As stated earlier, the header of the POST request requires a valid CSRF token. Here we use the token value already obtained by the previous GET request and stored in the variable JerryCsrfToken:

I hope that the suffix of the description information of the Service Ticket generated through the concurrent test is a random positive integer ranging from 1 to 100, so I use a random number generator in jMeter:

(4) As the last step, create a user variable by using JMeter built-in function __Random, to create a random number between 1 ~ 100 as a fragment of created Service Request description.

Now execute the Thread group, and the execution detail for these three HTTP request could be reviewed separately in tree view:

This POST does exactly what we expected, adding the correct and valid CSRF token to the HTTP header field:

For example, the XSRF token is successfully fetched in the first request: rdPy7zNj_uKDYvQLgfQCFA==

And used as one header field in second HTTP Post request as expected:

And finally in UI we could find the created Service request with random number between 1 ~ 100 as postfix:

The Service Ticket created by the five concurrent requests constructed by me was observed on the UI, indicating that the CSRF token was successfully verified on the server side, and random numbers were found in the description information, indicating that the usage of my jMeter random number generator was correct.

I hope this article will be helpful to your work.

For more of Jerry’s original articles, please follow the public account “Wang Zixi “: