Search code examples
c#visual-studioperformance-testingload-testingweb-performance

How to extract the X-XSRF_TOKEN in a web performance test


I had written a web performance test which was earlier working fine. Developers now have added a CSRF token validation (to prevent CSRF attack on the website). After this the test has started to fail (Error, Bad Request). I dug into it and found that the server is generating an XSRF-TOKEN on login request which has to be passed in every request there after. Now to extract the token we need to parse response to the login request. How can we do it?

My coded tests looks like this:

WebTestRequest request4 = new WebTestRequest("https://servertest:8080/WebConsole/Account/Login");
request4.Method = "POST";
request4.Headers.Add(new WebTestRequestHeader("Accept", "application/json, text/plain, */*"));
request4.Headers.Add(new WebTestRequestHeader("Referer", "https://servertest:8080/WebConsole/index.html#/"));
StringHttpBody request4Body = new StringHttpBody();
request4Body.ContentType = "application/json;charset=utf-8";
request4Body.InsertByteOrderMark = false;
request4Body.BodyString = "{\"UserName\":\"pkdomain\\\\administrator\",\"Password\":\"sqa@123\"}";
request4.Body = request4Body;
yield return request4;
request4 = null;

WebTestRequest request5 = new WebTestRequest("https://servertest:8080/WebConsole/scripts/home/Pages/home-view.html");
request5.ThinkTime = 4;
request5.Headers.Add(new WebTestRequestHeader("Accept", "text/html"));
request5.Headers.Add(new WebTestRequestHeader("Referer", "https://servertest:8080/WebConsole/index.html#/"));
yield return request5;
request5 = null;

Solution

  • I believe the XSRF-TOKEN is returned in a cookie. Assuming that this is true in your case then the Set-Cookie header field contains the value and the required cookie must be extracted from it and saved to a context parameter. Subsequently that context parameter can be used wherever needed.

    I suggest you create a sandbox .webtest file, do the steps below then convert it to coded test and copy the useful lines into the real test.

    In more detail the steps are:

    Add an Extract HTTP Header extraction rule for the Set-Cookie header field to the request that returns the XSRF-TOKEN value. Save the extracted value to a context parameter of your choice, give its name in one of the properties of the extraction rule; see the image below.

    Add a call of the plugin below to the first request after the one with the above extraction rule. It extracts the required field from the cookie header field. The image below shows setting the properties of the call. (You might change the plugin to be a PostRequest and add it to the same request as the one with the extraction rule.)

    public class ExtractCookieField : WebTestRequestPlugin
    {
        public string AllCookiesCP { get; set; }
    
        public string FieldWantedCP { get; set; }
    
        public string SavedFieldCP { get; set; }
    
        // Expected to be called with AllCookiesCP containing text similar to:
        //     SomeHeader=639025785406236250; path=/; XSRF-TOKEN=somestring; secure; HttpOnly
    
        public override void PreRequestDataBinding(object sender, PreRequestDataBindingEventArgs e)
        {
            string AllCookiesText = e.WebTest.Context[AllCookiesCP].ToString();
    
            foreach (string nameValuePair in AllCookiesText.Split(';'))
            {
                string[] nameAndValue = nameValuePair.Split(new char[] { '=' }, 2);
    
                if (nameAndValue[0].Trim() == FieldWantedCP)
                {
                    string sessionTokenId = nameAndValue[1].Trim();
                    e.WebTest.Context[SavedFieldCP] = sessionTokenId;
                    e.WebTest.AddCommentToResult(string.Format("Setting {{{0}}} to '{1}'", SavedFieldCP, sessionTokenId));
                    return;
                }
            }
    
            // Dropping out of the loop means that the field was not found.
            throw new WebTestException(string.Format("Cannot extract cookie field '{0}' from '{1}'", FieldWantedCP, AllCookiesText));
        }
    }
    

    The value of the XSRF-TOKEN should now be in the context parameter specified in the SavedFieldCP property of the plugin call.

    This image shows the add extraction rule dialogue and setting the context parameter where the extracted header field is saved, ie into CookieValues. It also show the add plugin and setting the three properties. After the plugin runs, assuming it is successful, the token value should be saved into the context parameter XsrfToken. The parameter values can be modified in the .webtest file via the properties panels of the extraction rule and the plugin. The values should also be clearly seen as simple variables and strings in a coded webb test.

    Properties panels for extraction rule and plugins