Skip to content

Commit

Permalink
chore(iast): taint parameter name in post requests in fastapi [backpo…
Browse files Browse the repository at this point in the history
…rt 2.20] (#12040)

Backport ff41c13 from #12038 to 2.20.

Continuation of #12009

## Checklist
- [x] PR author has checked that all the criteria below are met
- The PR description includes an overview of the change
- The PR description articulates the motivation for the change
- The change includes tests OR the PR description describes a testing
strategy
- The PR description notes risks associated with the change, if any
- Newly-added code is easy to change
- The change follows the [library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
- The change includes or references documentation updates if necessary
- Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))

## Reviewer Checklist
- [x] Reviewer has checked that all the criteria below are met 
- Title is accurate
- All changes are related to the pull request's stated goal
- Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- Testing strategy adequately addresses listed risks
- Newly-added code is easy to change
- Release note makes sense to a user of the library
- If necessary, author has acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment
- Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)

Co-authored-by: Alberto Vara <alberto.vara@datadoghq.com>
  • Loading branch information
github-actions[bot] and avara1986 authored Jan 23, 2025
1 parent d29bd1e commit 4eed1c5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
6 changes: 6 additions & 0 deletions ddtrace/appsec/_iast/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ def _on_iast_fastapi_patch():
"FormData.get",
functools.partial(if_iast_taint_returned_object_for, OriginType.BODY),
)
try_wrap_function_wrapper(
"starlette.datastructures",
"FormData.keys",
functools.partial(if_iast_taint_starlette_datastructures, OriginType.PARAMETER_NAME),
)

_set_metric_iast_instrumented_source(OriginType.BODY)

# Instrumented on _iast_starlette_scope_taint
Expand Down
35 changes: 34 additions & 1 deletion tests/contrib/fastapi/test_fastapi_appsec_iast.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ async def test_route(request: Request):
assert result["ranges_origin"] == "http.request.parameter"


def test_query_param_name_source(fastapi_application, client, tracer, test_spans):
def test_query_param_name_source_get(fastapi_application, client, tracer, test_spans):
@fastapi_application.get("/index.html")
async def test_route(request: Request):
query_params = [k for k in request.query_params.keys() if k == "iast_queryparam"][0]
Expand Down Expand Up @@ -139,6 +139,39 @@ async def test_route(request: Request):
assert result["ranges_origin"] == "http.request.parameter.name"


def test_query_param_name_source_post(fastapi_application, client, tracer, test_spans):
@fastapi_application.post("/index.html")
async def test_route(request: Request):
form_data = await request.form()
query_params = [k for k in form_data.keys() if k == "iast_queryparam"][0]
ranges_result = get_tainted_ranges(query_params)

return JSONResponse(
{
"result": query_params,
"is_tainted": len(ranges_result),
"ranges_start": ranges_result[0].start,
"ranges_length": ranges_result[0].length,
"ranges_origin": origin_to_str(ranges_result[0].source.origin),
}
)

with override_global_config(dict(_iast_enabled=True, _iast_request_sampling=100.0)):
# disable callback
_aux_appsec_prepare_tracer(tracer)
resp = client.post(
"/index.html",
data={"iast_queryparam": "test1234"},
)
assert resp.status_code == 200
result = json.loads(get_response_body(resp))
assert result["result"] == "iast_queryparam"
assert result["is_tainted"] == 1
assert result["ranges_start"] == 0
assert result["ranges_length"] == 15
assert result["ranges_origin"] == "http.request.parameter.name"


def test_header_value_source(fastapi_application, client, tracer, test_spans):
@fastapi_application.get("/index.html")
async def test_route(request: Request):
Expand Down

0 comments on commit 4eed1c5

Please sign in to comment.