Enhanced API Scanning with Postman Support in Qualys WAS

Due to the fast-growing usage of REST APIs, having a way to test them for vulnerabilities in an automated, reliable way is more important than ever.  Automated testing of APIs is a little trickier than for web applications.  You can’t simply enter a starting URL for the scanner and click “Go”.  Additional setup is required to describe the API endpoints for the scanner.  The good news is that Qualys Web Application Scanning (WAS) offers multiple ways to set up a scan for your APIs.

Up to now Qualys WAS has provided two methods to set up scanning of your APIs:

  1. Proxy capture method
  2. Swagger/OpenAPI file method

Now, WAS supports a 3rd method – Postman Collections. As we’ll explain, this method can provide better vulnerability testing compared to the others.

What is a Postman Collection?

Postman is a widely-used tool for functional testing of REST APIs. A Postman Collection is a file that can be exported from the tool that clubs together related requests (API endpoints). Many organizations who have developed REST APIs for their services have published Postman Collection files for them. Two examples are Box and Okta.

The Postman tool includes a facility to export the Postman Collection and share them with other users. These collections are exported in JSON format.  Postman Collections also support Variables.  A variable is replaced by its actual value at run-time. Variables can also be defined at different levels: Collection level, Environment level, and Global level.

Postman Collection support in WAS

With the release of Postman Collection support in Qualys WAS, customers have the option to configure their API scans using the Postman Collection for their API.

The process is simple:

  • Postman collections created for functional testing can directly be used for security testing through Qualys WAS.
  • From the Postman tool, export your Collection file(s).
  • Upload the Collection file into Qualys WAS (specifically, the Application Details panel when editing a Web App).
  • Optionally, upload related files: 1) a Postman Environment Variables file, and 2) a Postman Global Variables file.

Customers can configure scan settings as normal before launching a scan. The crawling and testing of the API will be limited to the requests present in the Collection.

Advantages of a Postman Collection scan

There are several advantages to using a Postman Collection to scan your APIs.

  1. Requests typically include valid values for all query parameters and request body parameters. These values should pass the server side data validation.
  2. The requests can be in a functional workflow. For example, the proper functional flow for a blog site is for a user to first create the blog post and then subsequently add a comment to the blog post. This flow can be described in a Postman Collection and is extracted by the scanner so that tests can be performed in the correct order and will be accepted by server.
  3. Variables allow the scanner to extract a value from the output of one API call and use it in a subsequent API call.

Here we will present two scenarios where using a Postman Collection would provide a better scan compared to using a Swagger file or using the proxy capture method.

Scenario 1: Testing the Edit operation for a particular endpoint

A. Using Postman Collection

  1.  A Postman Collection is created with the proper workflow for functional testing.
  2.  The user uploads the Postman Collection into WAS to set up the scan.
  3.  The Collection has a “Create Object” POST request defined first. Here the API endpoint is “/students”

    REQUEST

    POST /students HTTP/1.1
    Content-Type: application/json
    User-Agent: PostmanRuntime/7.15.2
    Accept: */*
    Cache-Control: no-cache
    Postman-Token: 5d2f73c6-c63b-47b0-869f-fdcbd77dd9d2
    Host: 10.115.77.114:3333
    Accept-Encoding: gzip, deflate
    Content-Length: 239
    Connection: close
    
    {
    	"Student_Name": "new Student Added",
    	"Parent_Name": "new Parent Added",
    	"Emergency_Ph_No": "784561235",
    	"Student_Email": "newstudentAdded12@gmail.com",
    	"Role_Id": 1,
    	"Class_Id": 3
    }
    

    RESPONSE

    HTTP/1.1 200 OK
    X-Powered-By: Express
    Access-Control-Allow-Origin: *
    Content-Type: application/json; charset=utf-8
    Content-Length: 130
    ETag: w/"82-DiJZ3k94I9eUbXfFdLkuQTUJuas
    Date: Thu, 18 Jul 2019 12:51:02 GMT
    Connection: close
    
    {"fieldCount": 0, "affectedRows": 1, "insertId": 1241, "serverStatus": 2, "warningCount": 0, "message": "", "protocol41": true, "ChangedRows": 0}
    
  4. The POST request creates a new student record and a numeric value called “insertId” is returned, representing the ID of the student just created.
  5. Using a script under “Tests”, the value for “insertId” is saved to an environment variable.
    Screenshot of code to save "insertId" as an environment variable
  6. The next request is a PUT request to update the student record.  In the definition of the request, the “insertId” environment variable is used for the “Student_Id” parameter.
    Screenshot of PUT request with "insertId"
  7. When the PUT request to update the student record is done, the actual value of “insertId” is used, resulting in a valid request for an existing student.

    REQUEST

    PUT /students/1241 HTTP/1.1
    Content-Type: application/json
    User-Agent: PostmanRuntime/7.15.2
    Accept: */*
    Cache-Control: no-cache
    Postman-Token: 5d2f73c6-c63b-47b0-869f-fdcbd77dd9d2
    Host: 10.115.77.114:3333
    Accept-Encoding: gzip, deflate
    Content-Length: 255
    Connection: close
    
    {
    "Student_Id": 1241,
    "Student_Name": "test new updated",
    "Parent_Name": "test updated",
    "Emergency_Ph_No": "784561235",
    "Student_Email": "userupdated@gmail.com",
    "Role_Id": 1,
    "Class_Id": 3
    }
    

    RESPONSE

    HTTP/1.1 200 OK
    X-Powered-By: Express
    Access-Control-Allow-Origin: *
    Content-Type: application/json; charset=utf-8
    Content-Length: 168
    ETag: w/"82-DiJZ3k94I9eUbXfFdLkuQTUJuas
    Date: Thu, 18 Jul 2019 12:51:02 GMT
    Connection: close
    
    {"fieldCount": 0, "affectedRows": 1, "insertId": 0, "serverStatus": 2, "warningCount": 0, "message": "Rows matched:1 Changed: 0 Warnings: 0", "protocol41": true, "ChangedRows": 0}
  8. As part of the Postman Collection scan, WAS will crawl both the POST and PUT requests with valid IDs.
  9. When WAS tests/fuzzes the PUT request with various payloads, it will use a valid ID, so the server will accept it and perform the PUT operation. If the endpoint is vulnerable, WAS should be able to detect it.

B. Using Swagger/OpenAPI

  1. The user sets the web app’s target URL in WAS as the location of the Swagger file.
  2. A scan is launched, and the scanner parses the Swagger file to extract all the API endpoints along with example data, if present.
  3. The API endpoints are crawled with random values or example values provided.
    1. The POST request to create the student record may succeed, because the request has values with appropriate data.
    2. The student ID value in the PUT request (to update the student record) is a random integer, so it is unlikely to be valid.
    3. The PUT request returns an error saying “Student record not found”.
  4. WAS proceeds to test/fuzz the crawled PUT request with various payloads, but all the fuzzed requests return an error saying “Student record not found”.
  5. In this case, the PUT request is not tested as thoroughly compared to the Postman Collection method.

Scenario 2: Testing the Add Comment operation for a particular endpoint

Consider a scenario of adding the comment to the published blog. There are three validations that come into picture:

  1. The blog post first needs to be created.
  2. The post needs to be published.
  3. Once in published state, any user can add comments to the blog post.
  4. The API endpoints are defined as follows:
    1. Add blog post:
      POST http://domain.com/api/blogs
    2. Publish blog post:
      PUT http://domain.com/api/blogs/{blogId}  Body: {blogId: “<blogId>”, plublished: “true”}
    3. Add a comment to the blog post:
      POST http://domain.com/api/blogs/{blogId}/comments    Body: {AddedBy: “username”, comment: “<comment_text>”}

A. Using Postman Collection

  1. The user creates the Postman Collection to test the complete functional work flow.
  2. The user adds the requests in proper sequence in the Collection and also defines a Postman variable to extract blogId from the POST request
  3. The variable is used in the PUT request as well as in adding a comment via the POST request.
  4. When this kind of Postman Collection is provided for a WAS scan, the scanner will crawl all the endpoints and do the correct vulnerability test on them.
  5. The endpoint to add a comment will be tested properly for all the vulnerabilities

B. Using Swagger/OpenAPI:

  1. The user sets the web app’s target URL in WAS as the location of the Swagger file.
  2. A scan is launched, and the scanner parses the Swagger file to extract all the API endpoints along with example data, if present.
  3. The API endpoints are crawled with random values or example values provided.
    1. The POST request to create the blog record may succeed, because the request has values with appropriate data.
    2. The value of “blogId” used in the PUT request is a random integer, so it is unlikely to be valid.
    3. The PUT request to publish returns an error saying “Unable to publish – blogId not valid”.
    4. The POST request for adding a comment also fails with an error saying “Comment not added – blogId not valid”.
  4. Similar to scenario #1, vulnerability testing of the PUT request and the POST request would not tested as thoroughly compared to the Postman Collection method.

Current Limitations

Postman Collections may include JavaScript code. This code is executed in a sandboxed JavaScript environment. In case of the WAS scanning engine, the JavaScript environment has a few limitations, including:

  1. In the Test scripts, dynamic variables are not supported.  This includes {{$guid}}, {{$timestamp}}, and {{$randomInt}}.
  2. In the Test scripts, the “pm.sendRequest()” function is not supported.
  3. In the Prerequest scripts and Test Scripts, currently only ES5-compliant JS code is supported. Support for ES6-compliant JS code will be added in future.

Resources

Leave a Reply