Skip to content

Commit

Permalink
chore(iast): django Invalid or empty source_value [backport 2.14] (#1…
Browse files Browse the repository at this point in the history
…0806)

Backport f73437b from #10801 to 2.14.

Fix telemetry log error: "ValueError: [IAST] Invalid or empty
source_value."

No release note needed, as this error occurs after this PR
#10740 that has not been
released yet

Task APPSEC-55017

## 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 <[email protected]>
  • Loading branch information
github-actions[bot] and avara1986 authored Sep 25, 2024
1 parent ca4dafd commit 8b42791
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 8 deletions.
27 changes: 20 additions & 7 deletions ddtrace/appsec/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,26 @@ def _on_django_func_wrapped(fn_args, fn_kwargs, first_arg_expected_type, *_):
http_req.COOKIES = taint_structure(http_req.COOKIES, OriginType.COOKIE_NAME, OriginType.COOKIE)
http_req.GET = taint_structure(http_req.GET, OriginType.PARAMETER_NAME, OriginType.PARAMETER)
http_req.POST = taint_structure(http_req.POST, OriginType.BODY, OriginType.BODY)
if not is_pyobject_tainted(getattr(http_req, "_body", None)):
http_req._body = taint_pyobject(
http_req.body,
source_name=origin_to_str(OriginType.BODY),
source_value=http_req.body,
source_origin=OriginType.BODY,
)
if getattr(http_req, "_body", None) is not None and not is_pyobject_tainted(getattr(http_req, "_body", None)):
try:
http_req._body = taint_pyobject(
http_req._body,
source_name=origin_to_str(OriginType.BODY),
source_value=http_req._body,
source_origin=OriginType.BODY,
)
except AttributeError:
log.debug("IAST can't set attribute http_req._body", exc_info=True)
elif getattr(http_req, "body", None) is not None and not is_pyobject_tainted(getattr(http_req, "body", None)):
try:
http_req.body = taint_pyobject(
http_req.body,
source_name=origin_to_str(OriginType.BODY),
source_value=http_req.body,
source_origin=OriginType.BODY,
)
except AttributeError:
log.debug("IAST can't set attribute http_req.body", exc_info=True)

http_req.headers = taint_structure(http_req.headers, OriginType.HEADER_NAME, OriginType.HEADER)
http_req.path = taint_pyobject(
Expand Down
2 changes: 1 addition & 1 deletion ddtrace/contrib/internal/django/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def _extract_body(request):
def _remake_body(request):
# some libs that utilize django (Spyne) require the body stream to be unread or else will throw errors
# see: https://github.com/arskom/spyne/blob/f105ec2f41495485fef1211fe73394231b3f76e5/spyne/server/wsgi.py#L538
if request.method in _BODY_METHODS:
if request.method in _BODY_METHODS and getattr(request, "_body", None):
try:
unread_body = io.BytesIO(request._body)
if unread_body.seekable():
Expand Down
14 changes: 14 additions & 0 deletions tests/contrib/django/test_django_appsec_iast.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import json
import logging

import pytest

Expand Down Expand Up @@ -32,6 +33,19 @@ def reset_context():
_ = create_context()


@pytest.fixture(autouse=True)
def check_native_code_exception_in_each_python_aspect_test(request, caplog):
if "skip_iast_check_logs" in request.keywords:
yield
else:
caplog.set_level(logging.DEBUG)
with override_env({IAST.ENV_DEBUG: "true"}), caplog.at_level(logging.DEBUG):
yield

log_messages = [record.message for record in caplog.get_records("call")]
assert not any("[IAST] " in message for message in log_messages), log_messages


def _aux_appsec_get_root_span(
client,
test_spans,
Expand Down

0 comments on commit 8b42791

Please sign in to comment.