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.59k stars 297 forks source link

restler_custom_payload_uuid4_suffix used with PUT path parameter, but not with POST body parameter #116

Open rennhard opened 3 years ago

rennhard commented 3 years ago

When having a request PUT /users/{username} that allows to create users, grammar.py uses

primitives.restler_custom_payload_uuid4_suffix("username")

to create random usernames.

When having instead a request POST /users that uses a parameter username in the body (also to create users), grammar.py uses

primitives.restler_fuzzable_string("fuzzstring", quoted=True)

for the username parameter. Note that in this case, I removed the PUT request from the openapi spec to make sure it does not interfere.

I tried to force usage of random usernames in the POST request using the following in the fuzzing dictionary that is used for compiling and fuzzing, but it has no effect:

"restler_custom_payload_uuid4_suffix": {
    "username": "username"
}

The workaround I'm using in the POST case is replacing primitives.restler_fuzzable_string("fuzzstring", quoted=True) in grammar.py with primitives.restler_custom_payload_uuid4_suffix("username", quoted=True) and with this, I get the desired behavior with POST requests.

I have two questions in this context:

Thanks a lot - and thanks in general for this really valuable tool!

marina-p commented 3 years ago

Hello @rennhard,

We recently fixed a bug in configuring unique parameters. Could you please confirm that setting the dictionary as you have described (copied below) does not work in the most recent build of RESTler? This is the correct configuration, and should work. One potential issue with it is that a global replacement for username will be performed, and you may need to use an inline per-resource_settings dictionary to specify this just for one POST request (see /docs/user-guide/SettingsFile.md)

"restler_custom_payload_uuid4_suffix": {
    "username": "username"
}

The reason POST with body parameter is handled differently from PUT with path parameter is that, in examples we have seen, it is difficult to reliably infer which body parameter should be considered the "id" parameter for which a random uuid suffix type should be assigned. RESTler could handle this better by searching for other requests (PUT/GET/DELETE) with the same path prefix and a subsequent path parameter and comparing with the body of the POST. This would cover cases when names match nicely, such as in your example.

rennhard commented 3 years ago

Thanks for your response.

I'm using the latest version, I just checked again. I tried to solve it with per-resource_settings, but I think that can't work as these settings have no effect to the generated grammar.py (this is where the "problem" is introduced), as this setting can only be used with test/fuzz-lean/fuzz but not with compile (right?).

Anything else I could try? Otherwise, this issue can be closed. Maybe adding a feature to the compile step that allows to specify restler_custom_payload_uuid4_suffix for request body parameters would be a nice enhancement, but as there's an easy workaround (editing grammar.py), it's not absolutely needed.

marina-p commented 3 years ago

Hi Marc, Happy New Year,

There may be something specific to your grammar that is preventing the uuid4_suffix from being configured via the dictionary. If you have a few minutes, as a sanity check, could you please try compiling the demo_server grammar (/demo_server/swagger.json) and the following dictionary:

{
  "restler_custom_payload_uuid4_suffix": {
    "body": "123"
 }
}

Attached is the grammar we get, which has the uuid4_suffix entry in the body. Do you get the same behavior with demo_server as above? If yes, could you please share your specification so we can investigate further why this is not working for your schema?

grammar.zip

Regarding per-resource settings, I confirm the behavior you see that this does not currently get applied to grammar.py, and will open a separate issue to address it.

Thanks!

Marina

rennhard commented 3 years ago

Hi Marina

Now that's interesting: The grammer.py file I'm getting from swagger.json (when using the dictionary you proposed) uses

primitives.restler_static_string(""",
    "body":"""),
    primitives.restler_fuzzable_string("fuzzstring", quoted=True),

in the body parameter of the POST request and not a randomly created identifier.

I attached the files I used for compiling and also the resulting grammar.py and I used the following command for compiling:

./restler_bin/restler/Restler compile /home/user/Desktop/compiler_config_swagger.json

Note that before doing this, I downloaded and compiled the latest version. Before compiling, I did the following changes in src/driver/Program.fs:

compiler_config_swagger.json.zip dict_swagger.json.zip^ grammar.py.zip