Skip to content

Commit bcd7147

Browse files
feat(asm): support for session id waf address (#12760)
- add support for session_id waf address - add auto instrumentation for session_id in Django. This also support anonymous sessions. - This will also be tested by new system tests on all django weblogs APPSEC-57027 ## 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)
1 parent a1e9f39 commit bcd7147

File tree

4 files changed

+28
-9
lines changed

4 files changed

+28
-9
lines changed

ddtrace/appsec/_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class WAF_DATA_NAMES(metaclass=Constant_Class):
194194
REQUEST_HTTP_IP: Literal["http.client_ip"] = "http.client_ip"
195195
REQUEST_USER_ID: Literal["usr.id"] = "usr.id"
196196
REQUEST_USERNAME: Literal["usr.login"] = "usr.login"
197+
REQUEST_SESSION_ID: Literal["usr.session_id"] = "usr.session_id"
197198
RESPONSE_STATUS: Literal["server.response.status"] = "server.response.status"
198199
RESPONSE_HEADERS_NO_COOKIES: Literal["server.response.headers.no_cookies"] = "server.response.headers.no_cookies"
199200
RESPONSE_BODY: Literal["server.response.body"] = "server.response.body"
@@ -209,6 +210,7 @@ class WAF_DATA_NAMES(metaclass=Constant_Class):
209210
REQUEST_HTTP_IP,
210211
REQUEST_USER_ID,
211212
REQUEST_USERNAME,
213+
REQUEST_SESSION_ID,
212214
RESPONSE_STATUS,
213215
RESPONSE_HEADERS_NO_COOKIES,
214216
RESPONSE_BODY,

ddtrace/appsec/_trace_utils.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,15 @@ def track_user_login_success_event(
138138
span.set_tag_str(APPSEC.USER_LOGIN_USERID, str(user_id))
139139
set_user(tracer, user_id, name, email, scope, role, session_id, propagate, span, may_block=False)
140140
if in_asm_context():
141+
custom_data = {
142+
"REQUEST_USER_ID": str(initial_user_id) if initial_user_id else None,
143+
"REQUEST_USERNAME": initial_login,
144+
"LOGIN_SUCCESS": real_mode,
145+
}
146+
if session_id:
147+
custom_data["REQUEST_SESSION_ID"] = session_id
141148
res = call_waf_callback(
142-
custom_data={
143-
"REQUEST_USER_ID": str(initial_user_id) if initial_user_id else None,
144-
"REQUEST_USERNAME": initial_login,
145-
"LOGIN_SUCCESS": real_mode,
146-
},
149+
custom_data=custom_data,
147150
force_sent=True,
148151
)
149152
if res and any(action in [WAF_ACTIONS.BLOCK_ACTION, WAF_ACTIONS.REDIRECT_ACTION] for action in res.actions):
@@ -342,7 +345,7 @@ def _on_django_login(pin, request, user, mode, info_retriever, django_config):
342345
)
343346
if user_is_authenticated(user):
344347
with pin.tracer.trace("django.contrib.auth.login", span_type=SpanTypes.AUTH):
345-
session_key = getattr(request, "session_key", None)
348+
session_key = getattr(getattr(request, "session", None), "session_key", None)
346349
track_user_login_success_event(
347350
pin.tracer,
348351
user_id=user_id,
@@ -411,10 +414,11 @@ def get_user_info(info_retriever, django_config, kwargs={}):
411414
return user_id_found or user_id, user_extra
412415

413416

414-
def _on_django_process(result_user, mode, kwargs, pin, info_retriever, django_config):
417+
def _on_django_process(result_user, session_key, mode, kwargs, pin, info_retriever, django_config):
415418
if (not asm_config._asm_enabled) or mode == LOGIN_EVENTS_MODE.DISABLED:
416419
return
417420
user_id, user_extra = get_user_info(info_retriever, django_config, kwargs)
421+
res = None
418422
if result_user and result_user.is_authenticated:
419423
span = pin.tracer.current_root_span()
420424
if mode == LOGIN_EVENTS_MODE.ANON and isinstance(user_id, str):
@@ -441,9 +445,13 @@ def _on_django_process(result_user, mode, kwargs, pin, info_retriever, django_co
441445
"REQUEST_USERNAME": user_extra.get("login"),
442446
"LOGIN_SUCCESS": real_mode,
443447
}
448+
if session_key:
449+
custom_data["REQUEST_SESSION_ID"] = session_key
444450
res = call_waf_callback(custom_data=custom_data, force_sent=True)
445-
if res and any(action in [WAF_ACTIONS.BLOCK_ACTION, WAF_ACTIONS.REDIRECT_ACTION] for action in res.actions):
446-
raise BlockingException(get_blocked())
451+
elif in_asm_context() and session_key:
452+
res = call_waf_callback(custom_data={"REQUEST_SESSION_ID": session_key})
453+
if res and any(action in [WAF_ACTIONS.BLOCK_ACTION, WAF_ACTIONS.REDIRECT_ACTION] for action in res.actions):
454+
raise BlockingException(get_blocked())
447455

448456

449457
def _on_django_signup_user(django_config, pin, func, instance, args, kwargs, user, info_retriever):

ddtrace/contrib/internal/django/patch.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,10 +860,15 @@ def traced_process_request(django, pin, func, instance, args, kwargs):
860860
request_user = request.user._wrapped
861861
else:
862862
request_user = request.user
863+
if hasattr(request, "session") and hasattr(request.session, "session_key"):
864+
session_key = request.session.session_key
865+
else:
866+
session_key = None
863867
core.dispatch(
864868
"django.process_request",
865869
(
866870
request_user,
871+
session_key,
867872
mode,
868873
kwargs,
869874
pin,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
features:
3+
- |
4+
ASM: This introduces support for automatic instrumentation of session monitoring and blocking for Django.

0 commit comments

Comments
 (0)