From 9f92dc81d01b7b26017ca74d0118791bef264274 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:29:25 +0100 Subject: [PATCH 1/8] Add Header injection reflected exclusion test --- .../appsec/iast/sink/test_header_injection.py | 34 ++++++++++++++- tests/appsec/iast/utils.py | 42 +++++++++++++++++++ .../docker/nodejs/express4-typescript/iast.ts | 34 +++++++++++++++ .../docker/nodejs/express4/iast/index.js | 30 +++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index 242f7587616..21627def78f 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -3,7 +3,7 @@ # Copyright 2021 Datadog, Inc. from utils import context, features, missing_feature -from ..utils import BaseSinkTest +from ..utils import BaseSinkTest, BaseTestHeaderInjectionReflectedExclusion @features.iast_sink_header_injection @@ -25,3 +25,35 @@ def test_telemetry_metric_instrumented_sink(self): @missing_feature(context.library < "java@1.22.0", reason="Metrics not implemented") def test_telemetry_metric_executed_sink(self): super().test_telemetry_metric_executed_sink() + + +class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Pragma reflexion exclusion""" + + origin_header="cache-control" + reflected_header="pragma" + headers={"cache-control": "cacheControlValue"} + + +class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Transfer-Encoding reflexion exclusion""" + + origin_header="accept-encoding" + reflected_header="transfer-encoding" + headers={"accept-encoding": "foo, bar"} + + +class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Content-Encoding reflexion exclusion""" + + origin_header="accept-encoding" + reflected_header="content-encoding" + headers={"accept-encoding": "foo, bar"} + + +class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Access-Control-Allow-* reflexion exclusion""" + + origin_header="x-custom-header" + reflected_header="access-control-allow-origin" + headers={"x-custom-header": "allowed-origin"} diff --git a/tests/appsec/iast/utils.py b/tests/appsec/iast/utils.py index 39772c8f869..349d049d0e1 100644 --- a/tests/appsec/iast/utils.py +++ b/tests/appsec/iast/utils.py @@ -394,3 +394,45 @@ def test_cookie_name_filter(self): meta_req3 = _get_span_meta(self.req3) assert "_dd.iast.json" not in meta_req3 + + +class BaseTestHeaderInjectionReflectedExclusion: + origin_header: None + reflected_header: None + headers: None + + exclusion_request: None + no_exclusion_request: None + + def setup_no_exclusion(self): + assert self.origin_header is not None, f"Please set {self}.origin_header" + assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" + assert self.reflected_header is not None, f"Please set {self}.reflected_header" + assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" + + self.no_exclusion_request = weblog.get( + path="/iast/header_injection/reflected/no-exclusion", + params={"origin": self.origin_header, "reflected": self.reflected_header}, + ) + + def test_no_exclusion(self): + assert_iast_vulnerability( + request=self.no_exclusion_request, + vulnerability_count=1, + vulnerability_type="HEADER_INJECTION", + ) + + def setup_exclusion(self): + assert self.origin_header is not None, f"Please set {self}.origin_header" + assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" + assert self.reflected_header is not None, f"Please set {self}.reflected_header" + assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" + + self.exclusion_request = weblog.get( + path="/iast/header_injection/reflected/exclusion", + params={"origin": self.origin_header, "reflected": self.reflected_header}, + headers=self.headers + ) + + def test_exclusion(self): + BaseSinkTest.assert_no_iast_event(self.exclusion_request) diff --git a/utils/build/docker/nodejs/express4-typescript/iast.ts b/utils/build/docker/nodejs/express4-typescript/iast.ts index 754236c366e..64ec68020d4 100644 --- a/utils/build/docker/nodejs/express4-typescript/iast.ts +++ b/utils/build/docker/nodejs/express4-typescript/iast.ts @@ -317,6 +317,40 @@ function initSinkRoutes (app: Express): void { res.send(`OK:${token}`) }) + app.get('/iast/header_injection/reflected/exclusion', ({ headers, query }: Request, res: Response): void => { + const reflectedHeaderName: string = `${query.reflected}` + const originHeaderName: string = `${query.origin}` + res.setHeader(reflectedHeaderName, `${headers[originHeaderName]}`) + res.send('OK') + }) + + app.get('/iast/header_injection/reflected/no-exclusion', ({ query }: Request, res: Response): void => { + // There is a reason for this: to avoid vulnerabilities deduplication, + // which caused the non-exclusion test to fail for all tests after the first one, + // since they are all in the same location (the hash is calculated based on the location). + + const reflectedHeaderName: string = `${query.reflected}` + const originHeaderName: string = `${query.origin}` + switch (reflectedHeaderName) { + case 'pragma': + res.setHeader(reflectedHeaderName, originHeaderName) + break + case 'transfer-encoding': + res.setHeader(reflectedHeaderName, originHeaderName) + break + case 'content-encoding': + res.setHeader(reflectedHeaderName, originHeaderName) + break + case 'access-control-allow-origin': + res.setHeader(reflectedHeaderName, originHeaderName) + break + default: + res.setHeader(reflectedHeaderName, originHeaderName) + break + } + res.send('OK') + }) + app.post('/iast/header_injection/test_insecure', (req: Request, res: Response): void => { res.setHeader('testheader', req.body.test) res.send('OK') diff --git a/utils/build/docker/nodejs/express4/iast/index.js b/utils/build/docker/nodejs/express4/iast/index.js index 3dae1cdaa51..3e50e08d974 100644 --- a/utils/build/docker/nodejs/express4/iast/index.js +++ b/utils/build/docker/nodejs/express4/iast/index.js @@ -302,6 +302,36 @@ function initRoutes (app, tracer) { res.send(`OK:${token}`) }) + app.get('/iast/header_injection/reflected/exclusion', (req, res) => { + res.setHeader(req.query.reflected, req.headers[req.query.origin]) + res.send('OK') + }) + + app.get('/iast/header_injection/reflected/no-exclusion', (req, res) => { + // There is a reason for this: to avoid vulnerabilities deduplication, + // which caused the non-exclusion test to fail for all tests after the first one, + // since they are all in the same location (the hash is calculated based on the location). + + switch (req.query.reflected) { + case 'pragma': + res.setHeader(req.query.reflected, req.query.origin) + break + case 'transfer-encoding': + res.setHeader(req.query.reflected, req.query.origin) + break + case 'content-encoding': + res.setHeader(req.query.reflected, req.query.origin) + break + case 'access-control-allow-origin': + res.setHeader(req.query.reflected, req.query.origin) + break + default: + res.setHeader(req.query.reflected, req.query.origin) + break + } + res.send('OK') + }) + app.post('/iast/header_injection/test_insecure', (req, res) => { res.setHeader('testheader', req.body.test) res.send('OK') From b49d27a94d08f2b777d13a53a3331ef535c43d6a Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:29:42 +0100 Subject: [PATCH 2/8] Update manifests --- manifests/dotnet.yml | 4 ++++ manifests/golang.yml | 4 ++++ manifests/java.yml | 4 ++++ manifests/nodejs.yml | 13 +++++++++++++ manifests/php.yml | 4 ++++ manifests/python.yml | 4 ++++ manifests/ruby.yml | 4 ++++ 7 files changed, 37 insertions(+) diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index 79aced4e5f8..0ec7311c35d 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -36,6 +36,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: v2.46.0 + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: v2.44.0 test_insecure_auth_protocol.py: diff --git a/manifests/golang.yml b/manifests/golang.yml index bc1804fe2dd..8d063a1007b 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -45,6 +45,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/java.yml b/manifests/java.yml index eea5a919fa0..92fdf397b60 100644 --- a/manifests/java.yml +++ b/manifests/java.yml @@ -89,6 +89,10 @@ tests/: spring-boot-undertow: v1.27.0 spring-boot-wildfly: v1.27.0 uds-spring-boot: v1.27.0 + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: '*': v1.20.0 diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 1f6a2b37e82..ebb918e9887 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -38,6 +38,7 @@ refs: - &ref_5_23_0 '>=5.23.0 || ^4.47.0' - &ref_5_24_0 '>=5.24.0 || ^4.48.0' - &ref_5_25_0 '>=5.25.0 || ^4.49.0' + - &ref_5_26_0 '>=5.26.0 || ^4.50.0' tests/: apm_tracing_e2e/: @@ -96,6 +97,18 @@ tests/: TestHeaderInjection: '*': *ref_4_21_0 nextjs: missing_feature + TestHeaderInjectionExclusionPragma: + '*': *ref_5_26_0 + nextjs: missing_feature + TestHeaderInjectionExclusionTransferEncoding: + '*': *ref_5_26_0 + nextjs: missing_feature + TestHeaderInjectionExclusionContentEncoding: + '*': *ref_5_26_0 + nextjs: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: + '*': *ref_5_26_0 + nextjs: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: '*': *ref_4_8_0 diff --git a/manifests/php.yml b/manifests/php.yml index de05990e00b..e9a82a7a4b7 100644 --- a/manifests/php.yml +++ b/manifests/php.yml @@ -36,6 +36,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/python.yml b/manifests/python.yml index 37969654ab5..6d93bd93a68 100644 --- a/manifests/python.yml +++ b/manifests/python.yml @@ -74,6 +74,10 @@ tests/: TestHeaderInjection: '*': v2.10.0 fastapi: missing_feature + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/ruby.yml b/manifests/ruby.yml index b25d1a79b39..22a0797a97a 100644 --- a/manifests/ruby.yml +++ b/manifests/ruby.yml @@ -38,6 +38,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionPragma: missing_feature + TestHeaderInjectionExclusionTransferEncoding: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: From ac6a5bb4714fc1d1b6278cfe59ef0c77f08648a2 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:39:35 +0100 Subject: [PATCH 3/8] Add feature decorator --- tests/appsec/iast/sink/test_header_injection.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index 21627def78f..3ccb01e5592 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -27,6 +27,7 @@ def test_telemetry_metric_executed_sink(self): super().test_telemetry_metric_executed_sink() +@features.iast_sink_header_injection class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Pragma reflexion exclusion""" @@ -35,6 +36,7 @@ class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusi headers={"cache-control": "cacheControlValue"} +@features.iast_sink_header_injection class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Transfer-Encoding reflexion exclusion""" @@ -43,6 +45,7 @@ class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflec headers={"accept-encoding": "foo, bar"} +@features.iast_sink_header_injection class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Content-Encoding reflexion exclusion""" @@ -51,6 +54,7 @@ class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflect headers={"accept-encoding": "foo, bar"} +@features.iast_sink_header_injection class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Access-Control-Allow-* reflexion exclusion""" From d740a2c67fa73a979ea4c062b5cd1266421ef689 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:41:00 +0100 Subject: [PATCH 4/8] Fix lint problems --- .../appsec/iast/sink/test_header_injection.py | 32 +++++++++---------- tests/appsec/iast/utils.py | 20 ++++++------ .../docker/nodejs/express4-typescript/iast.ts | 2 +- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index 3ccb01e5592..db664cdb8ba 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -30,34 +30,34 @@ def test_telemetry_metric_executed_sink(self): @features.iast_sink_header_injection class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Pragma reflexion exclusion""" - - origin_header="cache-control" - reflected_header="pragma" - headers={"cache-control": "cacheControlValue"} + + origin_header = "cache-control" + reflected_header = "pragma" + headers = {"cache-control": "cacheControlValue"} @features.iast_sink_header_injection class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Transfer-Encoding reflexion exclusion""" - - origin_header="accept-encoding" - reflected_header="transfer-encoding" - headers={"accept-encoding": "foo, bar"} + + origin_header = "accept-encoding" + reflected_header = "transfer-encoding" + headers = {"accept-encoding": "foo, bar"} @features.iast_sink_header_injection class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Content-Encoding reflexion exclusion""" - - origin_header="accept-encoding" - reflected_header="content-encoding" - headers={"accept-encoding": "foo, bar"} + + origin_header = "accept-encoding" + reflected_header = "content-encoding" + headers = {"accept-encoding": "foo, bar"} @features.iast_sink_header_injection class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Access-Control-Allow-* reflexion exclusion""" - - origin_header="x-custom-header" - reflected_header="access-control-allow-origin" - headers={"x-custom-header": "allowed-origin"} + + origin_header = "x-custom-header" + reflected_header = "access-control-allow-origin" + headers = {"x-custom-header": "allowed-origin"} diff --git a/tests/appsec/iast/utils.py b/tests/appsec/iast/utils.py index 349d049d0e1..ea1f7a07df2 100644 --- a/tests/appsec/iast/utils.py +++ b/tests/appsec/iast/utils.py @@ -400,39 +400,37 @@ class BaseTestHeaderInjectionReflectedExclusion: origin_header: None reflected_header: None headers: None - + exclusion_request: None no_exclusion_request: None - + def setup_no_exclusion(self): assert self.origin_header is not None, f"Please set {self}.origin_header" assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" assert self.reflected_header is not None, f"Please set {self}.reflected_header" assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" - + self.no_exclusion_request = weblog.get( path="/iast/header_injection/reflected/no-exclusion", params={"origin": self.origin_header, "reflected": self.reflected_header}, ) - + def test_no_exclusion(self): assert_iast_vulnerability( - request=self.no_exclusion_request, - vulnerability_count=1, - vulnerability_type="HEADER_INJECTION", + request=self.no_exclusion_request, vulnerability_count=1, vulnerability_type="HEADER_INJECTION", ) - + def setup_exclusion(self): assert self.origin_header is not None, f"Please set {self}.origin_header" assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" assert self.reflected_header is not None, f"Please set {self}.reflected_header" assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" - + self.exclusion_request = weblog.get( path="/iast/header_injection/reflected/exclusion", params={"origin": self.origin_header, "reflected": self.reflected_header}, - headers=self.headers + headers=self.headers, ) - + def test_exclusion(self): BaseSinkTest.assert_no_iast_event(self.exclusion_request) diff --git a/utils/build/docker/nodejs/express4-typescript/iast.ts b/utils/build/docker/nodejs/express4-typescript/iast.ts index 64ec68020d4..505e3d4d7c2 100644 --- a/utils/build/docker/nodejs/express4-typescript/iast.ts +++ b/utils/build/docker/nodejs/express4-typescript/iast.ts @@ -328,7 +328,7 @@ function initSinkRoutes (app: Express): void { // There is a reason for this: to avoid vulnerabilities deduplication, // which caused the non-exclusion test to fail for all tests after the first one, // since they are all in the same location (the hash is calculated based on the location). - + const reflectedHeaderName: string = `${query.reflected}` const originHeaderName: string = `${query.origin}` switch (reflectedHeaderName) { From 4297e371d5a53a69db70e0285a7f68ee95c5a6b2 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:43:42 +0100 Subject: [PATCH 5/8] Sort correctly new tests --- .../appsec/iast/sink/test_header_injection.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index db664cdb8ba..8bea2cfb0d1 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -28,36 +28,36 @@ def test_telemetry_metric_executed_sink(self): @features.iast_sink_header_injection -class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): - """Verify Header injection Pragma reflexion exclusion""" +class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Access-Control-Allow-* reflexion exclusion""" - origin_header = "cache-control" - reflected_header = "pragma" - headers = {"cache-control": "cacheControlValue"} + origin_header = "x-custom-header" + reflected_header = "access-control-allow-origin" + headers = {"x-custom-header": "allowed-origin"} @features.iast_sink_header_injection -class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): - """Verify Header injection Transfer-Encoding reflexion exclusion""" +class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Content-Encoding reflexion exclusion""" origin_header = "accept-encoding" - reflected_header = "transfer-encoding" + reflected_header = "content-encoding" headers = {"accept-encoding": "foo, bar"} @features.iast_sink_header_injection -class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): - """Verify Header injection Content-Encoding reflexion exclusion""" +class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Pragma reflexion exclusion""" - origin_header = "accept-encoding" - reflected_header = "content-encoding" - headers = {"accept-encoding": "foo, bar"} + origin_header = "cache-control" + reflected_header = "pragma" + headers = {"cache-control": "cacheControlValue"} @features.iast_sink_header_injection -class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): - """Verify Header injection Access-Control-Allow-* reflexion exclusion""" +class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): + """Verify Header injection Transfer-Encoding reflexion exclusion""" - origin_header = "x-custom-header" - reflected_header = "access-control-allow-origin" - headers = {"x-custom-header": "allowed-origin"} + origin_header = "accept-encoding" + reflected_header = "transfer-encoding" + headers = {"accept-encoding": "foo, bar"} From 36511b53727dc438676facf1bd027a7d875f25a7 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Thu, 7 Nov 2024 22:46:59 +0100 Subject: [PATCH 6/8] Sort correctly new tests in manifests --- manifests/dotnet.yml | 4 ++-- manifests/golang.yml | 4 ++-- manifests/java.yml | 4 ++-- manifests/nodejs.yml | 8 ++++---- manifests/php.yml | 4 ++-- manifests/python.yml | 4 ++-- manifests/ruby.yml | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index 0ec7311c35d..7350fe40edd 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -36,10 +36,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: v2.46.0 + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: v2.44.0 test_insecure_auth_protocol.py: diff --git a/manifests/golang.yml b/manifests/golang.yml index 8d063a1007b..190648e6888 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -45,10 +45,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/java.yml b/manifests/java.yml index 92fdf397b60..8829c1eb353 100644 --- a/manifests/java.yml +++ b/manifests/java.yml @@ -89,10 +89,10 @@ tests/: spring-boot-undertow: v1.27.0 spring-boot-wildfly: v1.27.0 uds-spring-boot: v1.27.0 + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: '*': v1.20.0 diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index ebb918e9887..1ee600158bd 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -97,16 +97,16 @@ tests/: TestHeaderInjection: '*': *ref_4_21_0 nextjs: missing_feature - TestHeaderInjectionExclusionPragma: + TestHeaderInjectionExclusionAccessControlAllow: '*': *ref_5_26_0 nextjs: missing_feature - TestHeaderInjectionExclusionTransferEncoding: + TestHeaderInjectionExclusionContentEncoding: '*': *ref_5_26_0 nextjs: missing_feature - TestHeaderInjectionExclusionContentEncoding: + TestHeaderInjectionExclusionPragma: '*': *ref_5_26_0 nextjs: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: + TestHeaderInjectionExclusionTransferEncoding: '*': *ref_5_26_0 nextjs: missing_feature test_hsts_missing_header.py: diff --git a/manifests/php.yml b/manifests/php.yml index e9a82a7a4b7..3bd2b963c59 100644 --- a/manifests/php.yml +++ b/manifests/php.yml @@ -36,10 +36,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/python.yml b/manifests/python.yml index 6d93bd93a68..7a6af5938f9 100644 --- a/manifests/python.yml +++ b/manifests/python.yml @@ -74,10 +74,10 @@ tests/: TestHeaderInjection: '*': v2.10.0 fastapi: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: diff --git a/manifests/ruby.yml b/manifests/ruby.yml index 22a0797a97a..18f1b770c49 100644 --- a/manifests/ruby.yml +++ b/manifests/ruby.yml @@ -38,10 +38,10 @@ tests/: Test_HardcodedSecretsExtended: missing_feature test_header_injection.py: TestHeaderInjection: missing_feature + TestHeaderInjectionExclusionAccessControlAllow: missing_feature + TestHeaderInjectionExclusionContentEncoding: missing_feature TestHeaderInjectionExclusionPragma: missing_feature TestHeaderInjectionExclusionTransferEncoding: missing_feature - TestHeaderInjectionExclusionContentEncoding: missing_feature - TestHeaderInjectionExclusionAccessControlAllow: missing_feature test_hsts_missing_header.py: Test_HstsMissingHeader: missing_feature test_insecure_auth_protocol.py: From 0be2d3b2e3d39b09760547b4c46dc5076b2120f9 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Mon, 11 Nov 2024 08:34:46 +0100 Subject: [PATCH 7/8] Move reflected header exclusion base test to header injection file --- .../appsec/iast/sink/test_header_injection.py | 44 ++++++++++++++++++- tests/appsec/iast/utils.py | 40 ----------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index 8bea2cfb0d1..9a318dc1986 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -2,8 +2,48 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2021 Datadog, Inc. -from utils import context, features, missing_feature -from ..utils import BaseSinkTest, BaseTestHeaderInjectionReflectedExclusion +from utils import context, features, missing_feature, weblog +from ..utils import BaseSinkTest, assert_iast_vulnerability + + +class BaseTestHeaderInjectionReflectedExclusion: + origin_header: None + reflected_header: None + headers: None + + exclusion_request: None + no_exclusion_request: None + + def setup_no_exclusion(self): + assert self.origin_header is not None, f"Please set {self}.origin_header" + assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" + assert self.reflected_header is not None, f"Please set {self}.reflected_header" + assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" + + self.no_exclusion_request = weblog.get( + path="/iast/header_injection/reflected/no-exclusion", + params={"origin": self.origin_header, "reflected": self.reflected_header}, + ) + + def test_no_exclusion(self): + assert_iast_vulnerability( + request=self.no_exclusion_request, vulnerability_count=1, vulnerability_type="HEADER_INJECTION", + ) + + def setup_exclusion(self): + assert self.origin_header is not None, f"Please set {self}.origin_header" + assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" + assert self.reflected_header is not None, f"Please set {self}.reflected_header" + assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" + + self.exclusion_request = weblog.get( + path="/iast/header_injection/reflected/exclusion", + params={"origin": self.origin_header, "reflected": self.reflected_header}, + headers=self.headers, + ) + + def test_exclusion(self): + BaseSinkTest.assert_no_iast_event(self.exclusion_request) @features.iast_sink_header_injection diff --git a/tests/appsec/iast/utils.py b/tests/appsec/iast/utils.py index ea1f7a07df2..39772c8f869 100644 --- a/tests/appsec/iast/utils.py +++ b/tests/appsec/iast/utils.py @@ -394,43 +394,3 @@ def test_cookie_name_filter(self): meta_req3 = _get_span_meta(self.req3) assert "_dd.iast.json" not in meta_req3 - - -class BaseTestHeaderInjectionReflectedExclusion: - origin_header: None - reflected_header: None - headers: None - - exclusion_request: None - no_exclusion_request: None - - def setup_no_exclusion(self): - assert self.origin_header is not None, f"Please set {self}.origin_header" - assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" - assert self.reflected_header is not None, f"Please set {self}.reflected_header" - assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" - - self.no_exclusion_request = weblog.get( - path="/iast/header_injection/reflected/no-exclusion", - params={"origin": self.origin_header, "reflected": self.reflected_header}, - ) - - def test_no_exclusion(self): - assert_iast_vulnerability( - request=self.no_exclusion_request, vulnerability_count=1, vulnerability_type="HEADER_INJECTION", - ) - - def setup_exclusion(self): - assert self.origin_header is not None, f"Please set {self}.origin_header" - assert isinstance(self.origin_header, str), f"Please set {self}.origin_header" - assert self.reflected_header is not None, f"Please set {self}.reflected_header" - assert isinstance(self.reflected_header, str), f"Please set {self}.reflected_header" - - self.exclusion_request = weblog.get( - path="/iast/header_injection/reflected/exclusion", - params={"origin": self.origin_header, "reflected": self.reflected_header}, - headers=self.headers, - ) - - def test_exclusion(self): - BaseSinkTest.assert_no_iast_event(self.exclusion_request) From fdebc0ac7d8f940401fabe35e8f6fd2ddaa9da54 Mon Sep 17 00:00:00 2001 From: CarlesDD Date: Tue, 12 Nov 2024 11:05:19 +0100 Subject: [PATCH 8/8] Rename BaseTest class following python convention for private members --- tests/appsec/iast/sink/test_header_injection.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/appsec/iast/sink/test_header_injection.py b/tests/appsec/iast/sink/test_header_injection.py index 9a318dc1986..1dff965071d 100644 --- a/tests/appsec/iast/sink/test_header_injection.py +++ b/tests/appsec/iast/sink/test_header_injection.py @@ -6,7 +6,7 @@ from ..utils import BaseSinkTest, assert_iast_vulnerability -class BaseTestHeaderInjectionReflectedExclusion: +class _BaseTestHeaderInjectionReflectedExclusion: origin_header: None reflected_header: None headers: None @@ -68,7 +68,7 @@ def test_telemetry_metric_executed_sink(self): @features.iast_sink_header_injection -class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionReflectedExclusion): +class TestHeaderInjectionExclusionAccessControlAllow(_BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Access-Control-Allow-* reflexion exclusion""" origin_header = "x-custom-header" @@ -77,7 +77,7 @@ class TestHeaderInjectionExclusionAccessControlAllow(BaseTestHeaderInjectionRefl @features.iast_sink_header_injection -class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflectedExclusion): +class TestHeaderInjectionExclusionContentEncoding(_BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Content-Encoding reflexion exclusion""" origin_header = "accept-encoding" @@ -86,7 +86,7 @@ class TestHeaderInjectionExclusionContentEncoding(BaseTestHeaderInjectionReflect @features.iast_sink_header_injection -class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusion): +class TestHeaderInjectionExclusionPragma(_BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Pragma reflexion exclusion""" origin_header = "cache-control" @@ -95,7 +95,7 @@ class TestHeaderInjectionExclusionPragma(BaseTestHeaderInjectionReflectedExclusi @features.iast_sink_header_injection -class TestHeaderInjectionExclusionTransferEncoding(BaseTestHeaderInjectionReflectedExclusion): +class TestHeaderInjectionExclusionTransferEncoding(_BaseTestHeaderInjectionReflectedExclusion): """Verify Header injection Transfer-Encoding reflexion exclusion""" origin_header = "accept-encoding"