diff --git a/docs/weblog/README.md b/docs/weblog/README.md index 2ce6d69223..ea15d90e73 100644 --- a/docs/weblog/README.md +++ b/docs/weblog/README.md @@ -305,6 +305,50 @@ A POST request which will receive the following JSON body: Where the value for `value` must be used in the vulnerability. +### POST /iast/sc/* + +These group of endpoints should trigger vulnerabilities detected by IAST with untrusted data coming from certain sources although the data is validated or sanitized by a configured security control + +#### POST /iast/sc/s/configured + +A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control configured for this vulnerability. + +#### POST /sc/s/not-configured + +A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control that is not configured for this vulnerability. + +#### POST /sc/s/all + +A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control configured for all vulnerabilities. + +#### POST /sc/iv/configured + +A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control configured for this vulnerability. + +#### POST /sc/iv/not-configured + +A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control that is not configured for this vulnerability. + +#### POST /sc/iv/all + +A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control configured for all vulnerabilities. + +#### POST /sc/iv/overloaded/secure + +A post request using two parameters that triggers a vulnerability. The values should be validated by an input validator security control with an overloaded method configured for all vulnerabilities. + +#### POST /sc/iv/overloaded/insecure + +A post request using two parameters that triggers a vulnerability. The values should be validated by an input validator security control with an overloaded method configured for other method signature. + +#### POST /sc/s/overloaded/secure + +A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control with an overloaded method configured for all vulnerabilities. + +#### POST /sc/s/overloaded/insecure + +A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control with an overloaded method configured for other method signature. + ### GET /make_distant_call This endpoint accept a mandatory parameter `url`. It'll make a call to these url, and should returns a JSON response : diff --git a/manifests/cpp.yml b/manifests/cpp.yml index 10d7f95601..87ad48ea4f 100644 --- a/manifests/cpp.yml +++ b/manifests/cpp.yml @@ -53,6 +53,7 @@ tests/: test_path.py: irrelevant (ASM is not implemented in C++) test_path_parameter.py: irrelevant (ASM is not implemented in C++) test_uri.py: irrelevant (ASM is not implemented in C++) + test_security_controls.py: irrelevant (ASM is not implemented in C++) rasp/: test_lfi.py: irrelevant (ASM is not implemented in C++) test_libddwaf.py: irrelevant (ASM is not implemented in C++) diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index ebedcc09d8..a76c583fe4 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -147,6 +147,8 @@ tests/: TestPathParameter: missing_feature test_uri.py: TestURI: irrelevant + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: Test_Lfi_BodyJson: v2.51.0 diff --git a/manifests/golang.yml b/manifests/golang.yml index 5d3a554ccf..ac1611af3b 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -155,6 +155,8 @@ tests/: TestPathParameter: missing_feature test_uri.py: TestURI: missing_feature + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: missing_feature test_libddwaf.py: missing_feature diff --git a/manifests/java.yml b/manifests/java.yml index dba8a769cf..ac84d14f5e 100644 --- a/manifests/java.yml +++ b/manifests/java.yml @@ -562,6 +562,12 @@ tests/: spring-boot-3-native: missing_feature (GraalVM. Tracing support only) vertx3: missing_feature vertx4: missing_feature + test_security_controls.py: + TestSecurityControls: + '*': missing_feature (No endpoint implemented) + play: missing_feature (No endpoint implemented) + ratpack: missing_feature (No endpoint implemented) + spring-boot-3-native: missing_feature (GraalVM. Tracing support only) rasp/: test_lfi.py: Test_Lfi_BodyJson: diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 7f3efaaaca..571591ec2e 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -271,6 +271,8 @@ tests/: nextjs: missing_feature test_uri.py: TestURI: missing_feature + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: Test_Lfi_BodyJson: diff --git a/manifests/php.yml b/manifests/php.yml index 356224a0e8..bb863a4499 100644 --- a/manifests/php.yml +++ b/manifests/php.yml @@ -146,6 +146,8 @@ tests/: TestPathParameter: missing_feature test_uri.py: TestURI: missing_feature + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: missing_feature test_libddwaf.py: missing_feature diff --git a/manifests/python.yml b/manifests/python.yml index 8bba17a4c8..081c2460f1 100644 --- a/manifests/python.yml +++ b/manifests/python.yml @@ -235,6 +235,8 @@ tests/: uwsgi-poc: v2.13.0 test_uri.py: TestURI: missing_feature + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: Test_Lfi_BodyJson: v2.10.0 diff --git a/manifests/ruby.yml b/manifests/ruby.yml index ea2e17afc8..c507ba509a 100644 --- a/manifests/ruby.yml +++ b/manifests/ruby.yml @@ -147,6 +147,8 @@ tests/: TestPathParameter: missing_feature test_uri.py: TestURI: missing_feature + test_security_controls.py: + TestSecurityControls: missing_feature rasp/: test_lfi.py: missing_feature test_libddwaf.py: missing_feature diff --git a/tests/appsec/iast/test_security_controls.py b/tests/appsec/iast/test_security_controls.py new file mode 100644 index 0000000000..90978e80ed --- /dev/null +++ b/tests/appsec/iast/test_security_controls.py @@ -0,0 +1,133 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2021 Datadog, Inc. + +from utils import features, rfc, weblog, interfaces +from tests.appsec.iast.utils import BaseSinkTest, assert_iast_vulnerability + + +@features.iast_security_controls +@rfc("https://docs.google.com/document/d/1j1hp87-2wJnXUGADZxzLnvKJmaF_Gd6ZR1hPS3LVguQ/edit?pli=1&tab=t.0") +class TestSecurityControls: + @staticmethod + def assert_iast_is_enabled(request): + product_enabled = False + for _, _, span in interfaces.library.get_spans(request=request): + # Check if the product is enabled in meta + meta = span["meta"] + if "_dd.iast.json" in meta: + product_enabled = True + break + # Check if the product is enabled in meta_struct + meta_struct = span["meta_struct"] + if meta_struct and meta_struct.get("vulnerability"): + product_enabled = True + break + assert product_enabled, "IAST is not available" + + def setup_iast_is_enabled(self): + self.check_r = weblog.post("/iast/sc/iv/not-configured", data={"param": "param"}) + + def setup_vulnerability_suppression_with_an_input_validator_configured_for_a_specific_vulnerability(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/iv/configured", data={"param": "param"}) + + def test_vulnerability_suppression_with_an_input_validator_configured_for_a_specific_vulnerability(self): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "COMMAND_INJECTION") + + def setup_no_vulnerability_suppression_with_an_input_validator_configured_for_a_different_vulnerability(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/iv/not-configured", data={"param": "param"}) + + def test_no_vulnerability_suppression_with_an_input_validator_configured_for_a_different_vulnerability(self): + self.assert_iast_is_enabled(self.check_r) + assert_iast_vulnerability( + request=self.r, vulnerability_count=1, vulnerability_type="SQL_INJECTION", + ) + + def setup_vulnerability_suppression_with_an_input_validator_configured_for_all_vulnerabilities(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/iv/all", data={"param": "param"}) + + def test_vulnerability_suppression_with_an_input_validator_configured_for_all_vulnerabilities(self): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "SQL_INJECTION") + + def setup_vulnerability_suppression_with_an_input_validator_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.setup_iast_is_enabled() + self.r = weblog.post("iast/sc/iv/overloaded/secure", data={"user": "usr1", "password": "pass"}) + + def test_vulnerability_suppression_with_an_input_validator_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "SQL_INJECTION") + + def setup_no_vulnerability_suppression_with_an_input_validator_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.setup_iast_is_enabled() + self.r = weblog.post("iast/sc/iv/overloaded/insecure", data={"user": "usr1", "password": "pass"}) + + def test_no_vulnerability_suppression_with_an_input_validator_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.assert_iast_is_enabled(self.check_r) + assert_iast_vulnerability( + request=self.r, vulnerability_count=1, vulnerability_type="SQL_INJECTION", + ) + + def setup_vulnerability_suppression_with_a_sanitizer_configured_for_a_specific_vulnerability(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/s/configured", data={"param": "param"}) + + def test_vulnerability_suppression_with_a_sanitizer_configured_for_a_specific_vulnerability(self): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "COMMAND_INJECTION") + + def setup_no_vulnerability_suppression_with_a_sanitizer_configured_for_a_different_vulnerability(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/s/not-configured", data={"param": "param"}) + + def test_no_vulnerability_suppression_with_a_sanitizer_configured_for_a_different_vulnerability(self): + self.assert_iast_is_enabled(self.check_r) + assert_iast_vulnerability( + request=self.r, vulnerability_count=1, vulnerability_type="SQL_INJECTION", + ) + + def setup_vulnerability_suppression_with_a_sanitizer_configured_for_all_vulnerabilities(self): + self.setup_iast_is_enabled() + self.r = weblog.post("/iast/sc/s/all", data={"param": "param"}) + + def test_vulnerability_suppression_with_a_sanitizer_configured_for_all_vulnerabilities(self): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "SQL_INJECTION") + + def setup_vulnerability_suppression_with_a_sanitizer_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.setup_iast_is_enabled() + self.r = weblog.post("iast/sc/s/overloaded/secure", data={"param": "param"}) + + def test_vulnerability_suppression_with_a_sanitizer_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.assert_iast_is_enabled(self.check_r) + BaseSinkTest.assert_no_iast_event(self.r, "COMMAND_INJECTION") + + def setup_no_vulnerability_suppression_with_a_sanitizer_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.setup_iast_is_enabled() + self.r = weblog.post("iast/sc/s/overloaded/insecure", data={"param": "param"}) + + def test_no_vulnerability_suppression_with_a_sanitizer_configured_for_an_overloaded_method_with_specific_signature( + self, + ): + self.assert_iast_is_enabled(self.check_r) + assert_iast_vulnerability( + request=self.r, vulnerability_count=1, vulnerability_type="COMMAND_INJECTION", + ) diff --git a/utils/_context/_scenarios/default.py b/utils/_context/_scenarios/default.py index cedb669f0d..cc118255f6 100644 --- a/utils/_context/_scenarios/default.py +++ b/utils/_context/_scenarios/default.py @@ -2,6 +2,20 @@ from .endtoend import EndToEndScenario +# When Security Controls configuration is set, tracers must instrument all the designated methods in the configuration as security controls. +# RFC(https://docs.google.com/document/d/1j1hp87-2wJnXUGADZxzLnvKJmaF_Gd6ZR1hPS3LVguQ/edit?pli=1&tab=t.0) +_iast_security_controls_map = { + "cpp": "TODO", + "dotnet": "TODO", + "golang": "TODO", + "java": "SANITIZER:COMMAND_INJECTION:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:sanitize;SANITIZER:*:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:sanitizeForAllVulns;SANITIZER:*:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:overloadedSanitize:java.lang.String;INPUT_VALIDATOR:COMMAND_INJECTION:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:validate;INPUT_VALIDATOR:*:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:validateForAllVulns;INPUT_VALIDATOR:*:com.datadoghq.system_tests.iast.utils.SecurityControlUtil:overloadedValidation:java.lang.Object,java.lang.String,java.lang.String:1,2", + "nodejs": "TODO", + "php": "TODO", + "python": "TODO", + "ruby": "TODO", +} + + class DefaultScenario(EndToEndScenario): def __init__(self, name: str): super().__init__( @@ -18,3 +32,10 @@ def __init__(self, name: str): scenario_groups=[ScenarioGroup.ESSENTIALS], doc="Default scenario, spawn tracer, the Postgres databases and agent, and run most of exisiting tests", ) + + def configure(self, config): + super().configure(config) + + library = self.weblog_container.image.env["SYSTEM_TESTS_LIBRARY"] + value = _iast_security_controls_map[library] + self.weblog_container.environment["DD_IAST_SECURITY_CONTROLS_CONFIGURATION"] = value diff --git a/utils/_features.py b/utils/_features.py index 7db6614618..af60d0382f 100644 --- a/utils/_features.py +++ b/utils/_features.py @@ -2487,3 +2487,13 @@ def iast_stack_trace(test_object): """ pytest.mark.features(feature_id=329)(test_object) return test_object + + @staticmethod + def iast_security_controls(test_object): + """ + IAST: Security Controls + + https://feature-parity.us1.prod.dog/#/?feature=343 + """ + pytest.mark.features(feature_id=343)(test_object) + return test_object diff --git a/utils/build/docker/java/akka-http/src/main/scala/com/datadoghq/akka_http/IastRoutes.scala b/utils/build/docker/java/akka-http/src/main/scala/com/datadoghq/akka_http/IastRoutes.scala index 024025d323..62da2341ab 100644 --- a/utils/build/docker/java/akka-http/src/main/scala/com/datadoghq/akka_http/IastRoutes.scala +++ b/utils/build/docker/java/akka-http/src/main/scala/com/datadoghq/akka_http/IastRoutes.scala @@ -196,6 +196,93 @@ object IastRoutes { } } } + pathPrefix("sc") { + pathPrefix("s") { + post { + path("configured") { + formField("param") { param => + val sanitized = SecurityControlUtil.sanitize(param) + cmd.insecureCmd(sanitized) + complete(StatusCodes.OK) + } + } ~ + path("not-configured") { + formField("param") { param => + val sanitized = SecurityControlUtil.sanitize(param) + complete(StatusCodes.OK, sql.insecureSql(sanitized, "password"))(jsonMarshaller) + } + } ~ + path("all") { + formField("param") { param => + val sanitized = SecurityControlUtil.sanitizeForAllVulns(param) + complete(StatusCodes.OK, sql.insecureSql(sanitized, "password"))(jsonMarshaller) + } + } ~ + pathPrefix("overloaded") { + path("secure") { + formField("param") { param => + val sanitized = SecurityControlUtil.overloadedSanitize(param) + cmd.insecureCmd(sanitized) + complete(StatusCodes.OK) + } + } ~ + path("insecure") { + formField("param") { param => + val sanitized = SecurityControlUtil.overloadedSanitize(param, null) + cmd.insecureCmd(sanitized) + complete(StatusCodes.OK) + } + } + } + } + } ~ + pathPrefix("iv") { + post { + path("configured") { + formField("param") { param => + if (SecurityControlUtil.validate(param)) { + cmd.insecureCmd(param) + } + complete(StatusCodes.OK) + } + } ~ + path("not-configured") { + formField("param") { param => + if (SecurityControlUtil.validate(param)) { + sql.insecureSql(param, "password") + } + complete(StatusCodes.OK) + } + } ~ + path("all") { + formField("param") { param => + if (SecurityControlUtil.validateForAllVulns(param)) { + sql.insecureSql(param, "password") + } + complete(StatusCodes.OK) + } + } ~ + pathPrefix("overloaded") { + path("secure") { + formFields("user", "password") { (user, pass) => + if (SecurityControlUtil.overloadedValidation(null, user, pass)) { + sql.insecureSql(user, pass) + } + complete(StatusCodes.OK) + } + } ~ + path("insecure") { + formFields("user", "password") { (user, pass) => + if (SecurityControlUtil.overloadedValidation(user, pass)) { + sql.insecureSql(user, pass) + } + complete(StatusCodes.OK) + } + } + } + } + } + } } private def paramOrFormField(p: String) = { diff --git a/utils/build/docker/java/iast-common/src/main/java/com/datadoghq/system_tests/iast/utils/SecurityControlUtil.java b/utils/build/docker/java/iast-common/src/main/java/com/datadoghq/system_tests/iast/utils/SecurityControlUtil.java new file mode 100644 index 0000000000..254aef0085 --- /dev/null +++ b/utils/build/docker/java/iast-common/src/main/java/com/datadoghq/system_tests/iast/utils/SecurityControlUtil.java @@ -0,0 +1,37 @@ +package com.datadoghq.system_tests.iast.utils; + +public class SecurityControlUtil { + + public static String sanitize(String input) { + return "Sanitized " + input; + } + + public static String sanitizeForAllVulns(String input) { + return "Sanitized for all vulns " + input; + } + + public static String overloadedSanitize(String input) { + return "Sanitized " + input; + } + + public static String overloadedSanitize(String input, Object o) { + return "Sanitized " + input; + } + + public static boolean validate(String input) { + return true; // dummy implementation + } + + public static boolean validateForAllVulns(String input) { + return true; // dummy implementation + } + + public static boolean overloadedValidation(String input, String input2) { + return true; // dummy implementation + } + + public static boolean overloadedValidation(Object o, String input, String input2) { + return true; // dummy implementation + } + +} diff --git a/utils/build/docker/java/jersey-grizzly2/src/main/java/com/datadoghq/jersey/IastSinkResource.java b/utils/build/docker/java/jersey-grizzly2/src/main/java/com/datadoghq/jersey/IastSinkResource.java index c087b7e302..11770f9346 100644 --- a/utils/build/docker/java/jersey-grizzly2/src/main/java/com/datadoghq/jersey/IastSinkResource.java +++ b/utils/build/docker/java/jersey-grizzly2/src/main/java/com/datadoghq/jersey/IastSinkResource.java @@ -271,4 +271,88 @@ public String insecureReflection(@FormParam("param") final String className) { return "Insecure"; } + @POST + @Path("/sc/s/configured") + public String scSanitizeConfigured(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitize(param); + cmd.insecureCmd(sanitized); + return "ok"; + } + + @POST + @Path("/sc/s/not-configured") + public Object scSanitizeSqli(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitize(param); + return sql.insecureSql(sanitized, "password"); + } + + @POST + @Path("/sc/s/all") + public Object scSanitizeForAllVulns(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitizeForAllVulns(param); + sql.insecureSql(sanitized, "password"); + return "ok"; + } + + @POST + @Path("/sc/iv/configured") + public String scValidateXSS(@FormParam("param") String param){ + if (SecurityControlUtil.validate(param)) { + cmd.insecureCmd(param); + } + return "ok"; + } + + @POST + @Path("/sc/iv/not-configured") + public String scValidateSqli(@FormParam("param") String param){ + if (SecurityControlUtil.validate(param)) { + sql.insecureSql(param, "password"); + } + return "ok"; + } + + @POST + @Path("/sc/iv/all") + public String scValidateForAllVulns(@FormParam("param") String param){ + if (SecurityControlUtil.validateForAllVulns(param)) { + sql.insecureSql(param, "password"); + } + return "ok"; + } + + @POST + @Path("/sc/iv/overloaded/secure") + public String scIVOverloadedSecure(@FormParam("user") String user, @FormParam("password") String pass){ + if (SecurityControlUtil.overloadedValidation(null, user, pass)) { + sql.insecureSql(user, pass); + } + return "ok"; + } + + @POST + @Path("/sc/iv/overloaded/insecure") + public String scIVOverloadedInsecure(@FormParam("user") String user, @FormParam("password") String pass){ + if (SecurityControlUtil.overloadedValidation(user, pass)) { + sql.insecureSql(user, pass); + } + return "ok"; + } + + @POST + @Path("/sc/s/overloaded/secure") + public String scSOverloadedSecure(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.overloadedSanitize(param); + cmd.insecureCmd(sanitized); + return "ok"; + } + + @POST + @Path("/sc/s/overloaded/insecure") + public String scSOverloadedInsecure(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.overloadedSanitize(param, null); + cmd.insecureCmd(sanitized); + return "ok"; + } + } diff --git a/utils/build/docker/java/resteasy-netty3/src/main/java/com/datadoghq/resteasy/IastSinkResource.java b/utils/build/docker/java/resteasy-netty3/src/main/java/com/datadoghq/resteasy/IastSinkResource.java index c70ab8fc0a..57e8c7610d 100644 --- a/utils/build/docker/java/resteasy-netty3/src/main/java/com/datadoghq/resteasy/IastSinkResource.java +++ b/utils/build/docker/java/resteasy-netty3/src/main/java/com/datadoghq/resteasy/IastSinkResource.java @@ -271,4 +271,87 @@ public String insecureReflection(@FormParam("param") final String className) { reflectionExamples.insecureClassForName(className); return "Insecure"; } + + @POST + @Path("/sc/s/configured") + public String scSanitizeConfigured(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitize(param); + cmd.insecureCmd(sanitized); + return "ok"; + } + + @POST + @Path("/sc/s/not-configured") + public Object scSanitizeSqli(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitize(param); + return sql.insecureSql(sanitized, "password"); + } + + @POST + @Path("/sc/s/all") + public Object scSanitizeForAllVulns(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.sanitizeForAllVulns(param); + return sql.insecureSql(sanitized, "password"); + } + + @POST + @Path("/sc/iv/configured") + public String scValidateXSS(@FormParam("param") String param){ + if (SecurityControlUtil.validate(param)) { + cmd.insecureCmd(param); + } + return "ok"; + } + + @POST + @Path("/sc/iv/not-configured") + public String scValidateSqli(@FormParam("param") String param){ + if (SecurityControlUtil.validate(param)) { + sql.insecureSql(param, "password"); + } + return "ok"; + } + + @POST + @Path("/sc/iv/all") + public String scValidateForAllVulns(@FormParam("param") String param){ + if (SecurityControlUtil.validateForAllVulns(param)) { + sql.insecureSql(param, "password"); + } + return "ok"; + } + + @POST + @Path("/sc/iv/overloaded/secure") + public String scIVOverloadedSecure(@FormParam("user") String user, @FormParam("password") String pass){ + if (SecurityControlUtil.overloadedValidation(null, user, pass)) { + sql.insecureSql(user, pass); + } + return "ok"; + } + + @POST + @Path("/sc/iv/overloaded/insecure") + public String scIVOverloadedInsecure(@FormParam("user") String user, @FormParam("password") String pass){ + if (SecurityControlUtil.overloadedValidation(user, pass)) { + sql.insecureSql(user, pass); + } + return "ok"; + } + + @POST + @Path("/sc/s/overloaded/secure") + public String scSOverloadedSecure(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.overloadedSanitize(param); + cmd.insecureCmd(sanitized); + return "ok"; + } + + @POST + @Path("/sc/s/overloaded/insecure") + public String scSOverloadedInsecure(@FormParam("param") String param){ + String sanitized = SecurityControlUtil.overloadedSanitize(param, null); + cmd.insecureCmd(sanitized); + return "ok"; + } } diff --git a/utils/build/docker/java/spring-boot/src/main/java/com/datadoghq/system_tests/springboot/AppSecIast.java b/utils/build/docker/java/spring-boot/src/main/java/com/datadoghq/system_tests/springboot/AppSecIast.java index 1010a79c97..62754180c8 100644 --- a/utils/build/docker/java/spring-boot/src/main/java/com/datadoghq/system_tests/springboot/AppSecIast.java +++ b/utils/build/docker/java/spring-boot/src/main/java/com/datadoghq/system_tests/springboot/AppSecIast.java @@ -380,6 +380,78 @@ public String secureUntrustedDeserialization(final HttpServletRequest request) t return "ok"; } + @PostMapping("/sc/s/configured") + void scSanitizeConfigured(final ServletRequest request, final ServletResponse response) throws IOException { + String sanitized = SecurityControlUtil.sanitize(request.getParameter("param")); + cmdExamples.insecureCmd(sanitized); + } + + @PostMapping("/sc/s/not-configured") + Object scSanitizeSqli(final ServletRequest request, final ServletResponse response) throws IOException { + String sanitized = SecurityControlUtil.sanitize(request.getParameter("param")); + return sqlExamples.insecureSql(sanitized, "password"); + } + + @PostMapping("/sc/s/all") + Object scSanitizeForAllVulns(final ServletRequest request, final ServletResponse response) throws IOException { + String sanitized = SecurityControlUtil.sanitizeForAllVulns(request.getParameter("param")); + return sqlExamples.insecureSql(sanitized, "password"); + } + + @PostMapping("/sc/iv/configured") + void scValidateXSS(final ServletRequest request, final ServletResponse response) throws IOException { + String param = request.getParameter("param"); + if (SecurityControlUtil.validate(param)) { + cmdExamples.insecureCmd(param); + } + } + + @PostMapping("/sc/iv/not-configured") + void scValidateSqli(final ServletRequest request, final ServletResponse response) throws IOException { + String param = request.getParameter("param"); + if(SecurityControlUtil.validate(param)) { + sqlExamples.insecureSql(param, "password"); + } + } + + @PostMapping("/sc/iv/all") + void scValidateForAllVulns(final ServletRequest request, final ServletResponse response) throws IOException { + String param = request.getParameter("param"); + if(SecurityControlUtil.validateForAllVulns(param)) { + sqlExamples.insecureSql(param, "password"); + } + } + + @PostMapping("/sc/iv/overloaded/secure") + void scIVOverloadedSecure(final ServletRequest request, final ServletResponse response) throws IOException { + String user = request.getParameter("user"); + String pass = request.getParameter("password"); + if(SecurityControlUtil.overloadedValidation(null, user, pass)) { + sqlExamples.insecureSql(user, pass); + } + } + + @PostMapping("/sc/iv/overloaded/insecure") + void scIVOverloadedInsecure(final ServletRequest request, final ServletResponse response) throws IOException { + String user = request.getParameter("user"); + String pass = request.getParameter("password"); + if(SecurityControlUtil.overloadedValidation(user, pass)) { + sqlExamples.insecureSql(user, pass); + } + } + + @PostMapping("/sc/s/overloaded/secure") + void scSOverloadedSecure(final ServletRequest request, final ServletResponse response) throws IOException { + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParameter("param")); + cmdExamples.insecureCmd(sanitized); + } + + @PostMapping("/sc/s/overloaded/insecure") + void scSOverloadedInsecure(final ServletRequest request, final ServletResponse response) throws IOException { + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParameter("param"), null); + cmdExamples.insecureCmd(sanitized); + } + /** * TODO: Ldap is failing to startup in native image this method ensures it's started lazily diff --git a/utils/build/docker/java/vertx3/src/main/java/com/datadoghq/vertx3/iast/routes/IastSinkRouteProvider.java b/utils/build/docker/java/vertx3/src/main/java/com/datadoghq/vertx3/iast/routes/IastSinkRouteProvider.java index 586299ca8f..46f22b1c45 100644 --- a/utils/build/docker/java/vertx3/src/main/java/com/datadoghq/vertx3/iast/routes/IastSinkRouteProvider.java +++ b/utils/build/docker/java/vertx3/src/main/java/com/datadoghq/vertx3/iast/routes/IastSinkRouteProvider.java @@ -159,5 +159,84 @@ public void accept(final Router router) { final String param = request.getParam("param"); ctx.response().end(reflection.insecureClassForName(param)); }); + router.post("/iast/sc/s/configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitize(request.getParam("param")); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); + + router.post("/iast/sc/s/not-configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitize(request.getParam("param")); + ctx.response().end(Json.encodeToBuffer(sql.insecureSql(sanitized, "password"))); + }); + + router.post("/iast/sc/s/all").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitizeForAllVulns(request.getParam("param")); + ctx.response().end(Json.encodeToBuffer(sql.insecureSql(sanitized, "password"))); + }); + + router.post("/iast/sc/iv/configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validate(param)) { + cmd.insecureCmd(param); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/not-configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validate(param)) { + sql.insecureSql(param, "password"); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/all").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validateForAllVulns(param)) { + sql.insecureSql(param, "password"); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/overloaded/secure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String user = request.getParam("user"); + String pass = request.getParam("password"); + if (SecurityControlUtil.overloadedValidation(null, user, pass)) { + sql.insecureSql(user, pass); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/overloaded/insecure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String user = request.getParam("user"); + String pass = request.getParam("password"); + if (SecurityControlUtil.overloadedValidation(user, pass)) { + sql.insecureSql(user, pass); + } + ctx.response().end(); + }); + + router.post("/iast/sc/s/overloaded/secure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParam("param")); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); + + router.post("/iast/sc/s/overloaded/insecure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParam("param"), null); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); } } diff --git a/utils/build/docker/java/vertx4/src/main/java/com/datadoghq/vertx4/iast/routes/IastSinkRouteProvider.java b/utils/build/docker/java/vertx4/src/main/java/com/datadoghq/vertx4/iast/routes/IastSinkRouteProvider.java index 79a824f205..3e171d1ae0 100644 --- a/utils/build/docker/java/vertx4/src/main/java/com/datadoghq/vertx4/iast/routes/IastSinkRouteProvider.java +++ b/utils/build/docker/java/vertx4/src/main/java/com/datadoghq/vertx4/iast/routes/IastSinkRouteProvider.java @@ -164,6 +164,84 @@ public void accept(final Router router) { final String param = request.getParam("param"); ctx.response().end(reflection.insecureClassForName(param)); }); + router.post("/iast/sc/s/configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitize(request.getParam("param")); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); + + router.post("/iast/sc/s/not-configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitize(request.getParam("param")); + ctx.response().end(Json.encodeToBuffer(sql.insecureSql(sanitized, "password"))); + }); + + router.post("/iast/sc/s/all").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.sanitizeForAllVulns(request.getParam("param")); + ctx.response().end(Json.encodeToBuffer(sql.insecureSql(sanitized, "password"))); + }); + + router.post("/iast/sc/iv/configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validate(param)) { + cmd.insecureCmd(param); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/not-configured").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validate(param)) { + sql.insecureSql(param, "password"); + } + ctx.response().end(); + }); + router.post("/iast/sc/iv/all").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String param = request.getParam("param"); + if (SecurityControlUtil.validateForAllVulns(param)) { + sql.insecureSql(param, "password"); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/overloaded/secure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String user = request.getParam("user"); + String pass = request.getParam("password"); + if (SecurityControlUtil.overloadedValidation(null, user, pass)) { + sql.insecureSql(user, pass); + } + ctx.response().end(); + }); + + router.post("/iast/sc/iv/overloaded/insecure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String user = request.getParam("user"); + String pass = request.getParam("password"); + if (SecurityControlUtil.overloadedValidation(user, pass)) { + sql.insecureSql(user, pass); + } + ctx.response().end(); + }); + + router.post("/iast/sc/s/overloaded/secure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParam("param")); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); + + router.post("/iast/sc/s/overloaded/insecure").handler(ctx -> { + final HttpServerRequest request = ctx.request(); + String sanitized = SecurityControlUtil.overloadedSanitize(request.getParam("param"), null); + cmd.insecureCmd(sanitized); + ctx.response().end(); + }); } }