OpenAPI Annotation Design
General Design
Background
Existing Problems and Challenges:
API Coverage:
Some parameters are almost impossible to generate randomly
Some API operations are critical in terms of logic (login, checkout, etc.), and cannot be arbitrarily called.
Resources are created on each run with very low efficiency
Multi-API vulnerabilities are not considered and discussed.
Goal: Annotate the original OpenAPI specification to guide the API fuzzing process, so that
Multi-API vulnerabilities are addressed
Resources are efficiently reused
Basic Idea: Annotation on each parameter and each operation
Parameter Annotation: label value rendering strategy
Group 1: parameter value property
- Fixed: use example list
- Dynamic: use the success result from previous calls in one testcase
- History: use history value list
- Mutation: mutate based on the example list or history value to improve coverage
- Random: a random generation strategy
Group 2: parameter source
- User-controlled
- System generated
Operation Annotation: label each operation
- Group 1: CRUD property
- pre-operations: operations that is required before others. Example: login, key generation, etc.
- post-operations: operations that is required after others. Doing this will change the whole service status. Example: logout, change password, checkout, etc.
- Switch: a switch button that will change service logic
- CREATE/UPDATE- READ/PROCESS - DELETE
- Group 2: processed parameter
Implementation with OpenAPI 3.0
Our idea is to utilize the “Specification Extensions“ concept (https://spec.openapis.org/oas/v3.1.0#specification-extensions) supported by OpenAPI 3.0 to achieve this. The general approach is to create a “x-annotation“ field as an additional property for each object. We may want to have a better name for it now. Below we give the example of how to annotate a piece of SpreeCommerce OpenAPI 3.0 specification with our design.
1 | paths: |
Such documentation can be directly taken by OpenAPI Swagger without any problems, while allows a better interpretation in API Testing process.
Initialization
*Parameter annotation: *
- Group 1:
- Use keywords: for instance, parameter like username, password etc. are labeld with fixed
- Manual: manually label the others
- Group 2:
- After graph construction, group 2 property can be auto labeled.
Operation annotation
- Group 1:
- Manual: manually label the key operations (login, etc.)
- The rest can be labeled based on HTTP request method.
- Group 2:
- Auto labeled. One operation can have multiple labels
Guided Fuzzing
General Strategy Description
Our strategy contains two rounds of execution feedback procedures. (1) It refines the generated \graph{} with an exploration strategy that tries to maximize the endpoints coverage. (2) It focuses on resources reuse to identify potential single/multi API vulnerabilities.
Parameter Generation Strategy
The annotation for each parameter is parsed by \tool{} and actively maintained during the fuzzing process. Each parameter is generated based on its annotation strategy in the following sequence.
1 | #1: Group2 -> user-controlled vs. system-generated |
Sequence Generation Strategy
We explain the two strategies
Strategy 1: Explore
This strategy generates all possible sequences by recursively visiting each parameter and concatenate the prior/posterior operations. Note that the pre/post operations are excluded from this step.
For testcase generation:
- Append necessary prior operations to each call sequence.
- Enumerate all the call sequences
- For each call sequence, render the parameters for each request in order and execute one by one. Note that for each call sequence, a full CRUD cycle is executed, and parameter values are never repeated if possible.
Strategy 2:
This strategy tries to maximize resource utilization so that it will efficiently identify possible vulnerabilities in target call sequences.
- It selects a user-controlled parameter that can be investigated.
- From the parameter, it generates all the possible call sequences for this parameter.
- Use CRUD filter to select those sequences where the parameter is in CREATE or UPDATE.
For testcase generation:
- Render the parameter values until the injection point. We consider the previous resources are “generated” and fixed, and repeatedly execute the rest of the sequences for vulnerability identification.
- Use mutation strategy to embed payloads into the injection target parameter.
- For each injection, execute until the end of the request sequence, excluding DELETE.
- Use after free is a special type of vulnerability. We will only test that after each round of testing to maximize resource utilization. (There are use-after-free type of API vulnerabilities, but very rare and we didn’t see that in our cases.)
Dynamic Updates
Parameters
During the test procedure, the annotations are dynamically updated to improve testing performance. The general idea is to use status code to reflect if a parameter is properly generated. The detailed strategies are explained below.
- Save all the 20x request parameter values into history database. The annotation for parameters with history is changed to mutation. (Consider to count success, and change strategy to fully random when possible?.)
- For each 40x request, at least one parameter value is not correctly rendered. The algorithm will change all random annotation to mutation, and one mutation annotation to history.
- For each 50x request, report as a bug. In this work, we do not focus on the reason of the bugs since they may not have security impacts.
Specially, when several parameters share the same value history, the graph will be refined and their source property may be changed.
Operations
The label for operations are generally not updated.