microsoft / restler-fuzzer

RESTler is the first stateful REST API fuzzing tool for automatically testing cloud services through their REST APIs and finding security and reliability bugs in these services.
MIT License
2.52k stars 284 forks source link

Do queries affect annotations? #768

Open mohona7428 opened 1 year ago

mohona7428 commented 1 year ago

Description

I'm trying to fuzz an API where the POST request must be completed first with some parameters like name, category, etc. Then a GET request must be performed using those parameters as queries. All the other requests (PUT, DELETE, etc) depend on getting the ID from the GET request.

  1. I tried to write an annotation for getting the ID from the GET request as something like this:

    {
        "producer_endpoint": "/setup",
    
            "producer_method": "GET",
    
            "producer_resource_name": "id",
    
            "consumer_param": "setID"
    }

But there's no change in the grammar file after compiling. I've enabled GET producers in the config file as well.

  1. Is it possible to add the dependency of the GET request getting the query parameters from the POST? The parameters are user generated and only present in the request body.
marina-p commented 1 year ago

Hello @mohona,

I believe everything you are asking for should be possible to configure. Just to make sure I understand the API pattern:

POST /product {name = "Name"; category = "Food"} -> returns 200 OK? or 201 with Location etc. ?

GET /product?name=Name&category=Food -> returns 200 OK {"id" = 12345; name = "Name", category = "Food"...}

PUT /product/12345 <-- /product/{setID} is the path as declared in OpenAPI

Can you please confirm this is the setup? I believe the easiest way to troubleshoot would be to have an OpenAPI spec sample to reproduce the issue. I am attaching an example with a dependency both as in your (1) and (2).

Config:

{
  "SwaggerSpecFilePath": [
    "../swagger.json"
  ],
  "DataFuzzing": true,
  "AnnotationFilePath": "annotations.json"
}

Annotation file:

{
  "x-restler-global-annotations": [
    {
      "producer_endpoint": "/setup",
      "producer_method": "GET",
      "producer_resource_name": "id",
      "consumer_param": "setID"
    },
    {
      "producer_endpoint": "/setup",
      "producer_method": "POST",
      "producer_resource_name": "/name",
      "consumer_param": "product_name",
      "consumer_endpoint": "/setup",
      "consumer_method": "GET"
    }

  ]
}

Swagger and resulting grammar with generated dependencies attached.

If there is something different about your Swagger/OpenAPI spec that makes the annotations not take effect, please send me your version of the spec that reproduces the issue. Or, please let me know what fixes you applied to make it work (perhaps there is a doc improvement we can make to better describe such examples).

grammar.py.txt swagger.json.txt

Thanks,

Marina

mohona7428 commented 1 year ago

Hi, these annotations really helped. I couldn't find any information in the documentation about how to retrieve a parameter from the body (eg. '/name').

However, I've run into another issue: one of the parameters needs to be sent as a string in the GET query, but it is in the form of an array in the POST request.

For example: POST /product {name = "name", models = ["abcd", "efgh"]}

GET /product?name="name"&model="abcd"

Is there a way to configure restler to extract the values from within the array?

marina-p commented 1 year ago

Hi @mohona7428,

Great. For extracting the array, the syntax is:

{
      "producer_endpoint": "/product",
      "producer_method": "POST",
      "producer_resource_name": "/models/[0]",
      "consumer_param": "model",
      "consumer_endpoint": "/product",
      "consumer_method": "GET"
}

The documentation has an example at the bottom of Annotations.md, search for 'JSON pointer notation'.

Thanks,

Marina

mohona7428 commented 1 year ago

Hi, I included the above in the annotation, but instead of sending an array, a single value was sent for the "models" field.

For example: Before: POST /product {name = "name", models = ["abcd", "efgh"]} After: POST /product {name = "name", models = "fuzzstring"}

Here is the change in grammar.py for reference: Before: image002

After: image001

mohona7428 commented 1 year ago

I tried to workaround this by manually changing the grammar to include the brackets and the request is giving a 200 status code however it's rendered invalid due to a parser failure.