相信前端开发工程师对CSRF(Cross-site request forgery)跨站请求伪造这个概念都很是熟悉,有的时候也简写成XSRF,是一种对网站的恶意利用。前端
尽管听起来像跨站脚本(XSS),但它与XSS很是不一样,XSS利用站点内的信任用户,而CSRF则经过假装成受信任用户的请求来利用受信任的网站。git
CSRF攻击的防护方式有多种,最简单最易实现的一种思路就是在客户端向服务器发起的请求中放入攻击者没法伪造的信息,而且该信息没有存储于 cookie 之中。技术上来讲,当客户端向服务器发起请求执行一些敏感操做以前(好比用HTTP post实现的转帐,扣款等功能),服务器端随机产生一个token,返回给客户端。客户端接下来的操做,必须在HTTP请求中以参数的形式把这个服务器端颁发的token带上。同时服务器端在实现给客户端分配token的同时,也要加入一个token校验机制。若是请求中没有 token 或者 token 内容不正确,则认为多是 CSRF 攻击而拒绝该请求。这个token咱们通常称为CSRF token。github
讲了这么多,是为了引入本文想要讨论的话题。假设我想用jMeter测试一个OOdata服务建立Service Ticket的性能。由于建立功能不像读操做,执行以后会对系统产生持久化影响(Persistence side-effect), 所以服务器端的实现加入了CSRF token的校验。这就是说,若是咱们直接用jMeter构造并发的HTTP post请求,是没有办法完成测试的,这些请求由于没有包含CSRF token,会被服务器端直接拒绝掉。正则表达式
根据前面描述的CSRF攻防原理,CSRF token是服务器端随机生成的,客户端没法用任何技术进行伪造,由于为了测试接口HTTP post操做进行Service Ticket的建立,咱们必须构造一个它的前置HTTP GET请求,专门用于获得服务器返回的CSRF token,而后再构造真正用于性能测试的HTTP POST请求,把第一步GET请求得到的CSRF token附到POST请求的头部中去。编程
本文介绍在jMeter里如何维护并配置这种具备依赖关系的一组请求。json
固然若是您不喜欢用jMeter,想本身写代码实现,也是能够的。能够参考我放在github上的Java代码实现。服务器
用jMeter的好处是不须要编程,经过简单的配置就能实现这个性能测试需求,通常没有开发背景的测试人员也能独立完成。cookie
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.app
从下图能看出,由于拿CSRF token的HTTP GET在逻辑上必须先于实际须要测试性能的HTTP POST请求,这实际上构成了一个Transaction-事务,因此我使用jMeter里提供的Transaction Controller来管理。
(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”:
在HTTP GET请求的头部加上一个名为x-csrf-token的字段,值赋成fetch。这样服务器接到这个请求,就知道这是客户端发起的CSRF token请求,因而服务器响应这个请求,把建立好的随机CSRF token经过HTTP response头部字段的方式返回给客户端。
下一个问题就是,服务器返回给客户端合法的CSRF token后,jMeter如何读取到这个token,并用于接下来的请求?
幸运的是,jMeter提供了正则表达式提取式,可让咱们很方便地从HTTP响应结构中提取出token来。
Create a Regular Expression Extractor to parse the XSRF token from response header and stored it to a variable named “jerrycsrftoken”.
下图构造了一个jMeter正则表达式提取器,工做于HTTP响应的头部字段,解析出的token值存储于变量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:
这个请求构造完以后,咱们先试着运行一次,确保在变量jerrycsrftoken里确实看到解析好的CSRF token。
(3) Create another HTTP request with type POST.
这时万事俱备,咱们能够开始构造真正要进行性能测试的HTTP post,即Service Ticket的建立请求了。
请求的报文正文: 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--
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.
前面说过,POST请求的头部须要加上合法的CSRF token,此处咱们使用前面GET请求已经拿到的而且存储于变量jerrycsrftoken中的token值:
我但愿最后经过并发测试生成的Service Ticket的描述信息的后缀是1到100的随机正整数,所以我使用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:
试着运行一下,发现这个POST操做确实按照咱们指望的那样,在HTTP头部字段里加上了正确合法的CSRF token:
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:
在UI上观测到我构造的5个并发请求建立的Service Ticket,说明CSRF token在服务器端的校验成功,同时发现描述信息都带上了随机数,说明个人jMeter随机数生成器的用法也正确。
但愿本文对你们的工做有所帮助。
要获取更多Jerry的原创文章,请关注公众号"汪子熙":