From d29533e59509338883260d465d94b505663c00c5 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Fri, 8 Nov 2024 14:10:15 +0100 Subject: [PATCH 01/16] feat(appsec): update ruleset configuration --- appsec/recommended.json | 519 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 489 insertions(+), 30 deletions(-) diff --git a/appsec/recommended.json b/appsec/recommended.json index d572c00391..01156e6f20 100644 --- a/appsec/recommended.json +++ b/appsec/recommended.json @@ -1,7 +1,7 @@ { "version": "2.2", "metadata": { - "rules_version": "1.10.0" + "rules_version": "1.13.2" }, "rules": [ { @@ -141,7 +141,10 @@ "appscan_fingerprint", "w00tw00t.at.isc.sans.dfind", "w00tw00t.at.blackhats.romanian.anti-sec" - ] + ], + "options": { + "enforce_word_boundary": true + } }, "operator": "phrase_match" } @@ -1778,7 +1781,10 @@ "windows\\win.ini", "default\\ntuser.dat", "/var/run/secrets/kubernetes.io/serviceaccount" - ] + ], + "options": { + "enforce_word_boundary": true + } }, "operator": "phrase_match" } @@ -1895,6 +1901,9 @@ "address": "graphql.server.resolver" } ], + "options": { + "enforce_word_boundary": true + }, "list": [ "${cdpath}", "${dirstack}", @@ -1912,7 +1921,6 @@ "$ifs", "$oldpwd", "$ostype", - "$path", "$pwd", "dev/fd/", "dev/null", @@ -2471,7 +2479,10 @@ "settings.local.php", "local.xml", ".env" - ] + ], + "options": { + "enforce_word_boundary": true + } }, "operator": "phrase_match" } @@ -2567,6 +2578,9 @@ "address": "graphql.server.resolver" } ], + "options": { + "enforce_word_boundary": true + }, "list": [ "$globals", "$_cookie", @@ -2765,7 +2779,10 @@ "wp_safe_remote_post", "wp_safe_remote_request", "zlib_decode" - ] + ], + "options": { + "enforce_word_boundary": true + } }, "operator": "phrase_match" } @@ -2980,9 +2997,6 @@ { "address": "server.request.path_params" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -3037,9 +3051,6 @@ { "address": "server.request.path_params" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -3271,6 +3282,9 @@ "address": "graphql.server.resolver" } ], + "options": { + "enforce_word_boundary": true + }, "list": [ "document.cookie", "document.write", @@ -3546,9 +3560,6 @@ { "address": "server.request.path_params" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -3863,9 +3874,6 @@ { "address": "server.request.path_params" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -4454,7 +4462,10 @@ "org.apache.struts2", "org.omg.corba", "java.beans.xmldecode" - ] + ], + "options": { + "enforce_word_boundary": true + } }, "operator": "phrase_match" } @@ -4581,9 +4592,6 @@ { "address": "server.request.path_params" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -5342,6 +5350,40 @@ ], "transformers": [] }, + { + "id": "dog-920-001", + "name": "JWT authentication bypass", + "tags": { + "type": "http_protocol_violation", + "category": "attack_attempt", + "cwe": "287", + "capec": "1000/225/115", + "confidence": "0" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.cookies" + }, + { + "address": "server.request.headers.no_cookies", + "key_path": [ + "authorization" + ] + } + ], + "regex": "^(?:Bearer )?ey[A-Za-z0-9+_\\-/]*([QY][UW]x[Hn]Ij([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiAi[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]Ij([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDogI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]IiA6ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]Ij([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiAi[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciOiAi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciIDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgOiJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]IiA6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]Ij([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciOiJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgOiAi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]IjogI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]IiA6I[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6I[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6I[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciIDogI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]IiA6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]IiA6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ciO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6I[km]5[Pv][Tb][km][U-X]|[QY][UW]x[Hn]IiA6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ID([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gI[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yIgO([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[\\x2b\\x2f-9A-Za-z]ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*ICJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]I([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*IDoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]A6I[km]5[Pv][Tb][km][U-X]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]y([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiJ[Ou][Tb][02]5[Fl]|[QY][UW]x[Hn]Ijoi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z]{2}[159BFJNRVZdhlptx][Bh][Tb][EG]ci([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[048AEIMQUYcgkosw]gOiAi[Tb][km]9[Ou][RZ][Q-Za-f]|[\\x2b\\x2f-9A-Za-z][02EGUWkm]F[Ms][RZ]yI6([048ACEIMQSUYcgikoswy]|[\\x2b\\x2f-9A-Za-z]I)*[CSiy]Ai[Tb][km]9[Ou][RZ][Q-Za-f])[A-Za-z0-9+-/]*\\.[A-Za-z0-9+_\\-/]+\\.(?:[A-Za-z0-9+_\\-/]+)?$", + "options": { + "case_sensitive": true + } + }, + "operator": "match_regex" + } + ], + "transformers": [] + }, { "id": "dog-931-001", "name": "RFI: URL Payload to well known RFI target", @@ -5603,6 +5645,9 @@ { "operator": "phrase_match", "parameters": { + "options": { + "enforce_word_boundary": true + }, "inputs": [ { "address": "server.request.uri.raw" @@ -5803,7 +5848,8 @@ "/website.php", "/stats.php", "/assets/plugins/mp3_id/mp3_id.php", - "/siteminderagent/forms/smpwservices.fcc" + "/siteminderagent/forms/smpwservices.fcc", + "/eval-stdin.php" ] } } @@ -6190,6 +6236,200 @@ ], "transformers": [] }, + { + "id": "rasp-930-100", + "name": "Local file inclusion exploit", + "tags": { + "type": "lfi", + "category": "vulnerability_trigger", + "cwe": "22", + "capec": "1000/255/153/126", + "confidence": "0", + "module": "rasp" + }, + "conditions": [ + { + "parameters": { + "resource": [ + { + "address": "server.io.fs.file" + } + ], + "params": [ + { + "address": "server.request.query" + }, + { + "address": "server.request.body" + }, + { + "address": "server.request.path_params" + }, + { + "address": "grpc.server.request.message" + }, + { + "address": "graphql.server.all_resolvers" + }, + { + "address": "graphql.server.resolver" + } + ] + }, + "operator": "lfi_detector" + } + ], + "transformers": [], + "on_match": [ + "stack_trace" + ] + }, + { + "id": "rasp-932-100", + "name": "Command injection exploit", + "tags": { + "type": "command_injection", + "category": "vulnerability_trigger", + "cwe": "77", + "capec": "1000/152/248/88", + "confidence": "0", + "module": "rasp" + }, + "conditions": [ + { + "parameters": { + "resource": [ + { + "address": "server.sys.shell.cmd" + } + ], + "params": [ + { + "address": "server.request.query" + }, + { + "address": "server.request.body" + }, + { + "address": "server.request.path_params" + }, + { + "address": "grpc.server.request.message" + }, + { + "address": "graphql.server.all_resolvers" + }, + { + "address": "graphql.server.resolver" + } + ] + }, + "operator": "shi_detector" + } + ], + "transformers": [], + "on_match": [ + "stack_trace" + ] + }, + { + "id": "rasp-934-100", + "name": "Server-side request forgery exploit", + "tags": { + "type": "ssrf", + "category": "vulnerability_trigger", + "cwe": "918", + "capec": "1000/225/115/664", + "confidence": "0", + "module": "rasp" + }, + "conditions": [ + { + "parameters": { + "resource": [ + { + "address": "server.io.net.url" + } + ], + "params": [ + { + "address": "server.request.query" + }, + { + "address": "server.request.body" + }, + { + "address": "server.request.path_params" + }, + { + "address": "grpc.server.request.message" + }, + { + "address": "graphql.server.all_resolvers" + }, + { + "address": "graphql.server.resolver" + } + ] + }, + "operator": "ssrf_detector" + } + ], + "transformers": [], + "on_match": [ + "stack_trace" + ] + }, + { + "id": "rasp-942-100", + "name": "SQL injection exploit", + "tags": { + "type": "sql_injection", + "category": "vulnerability_trigger", + "cwe": "89", + "capec": "1000/152/248/66", + "confidence": "0", + "module": "rasp" + }, + "conditions": [ + { + "parameters": { + "resource": [ + { + "address": "server.db.statement" + } + ], + "params": [ + { + "address": "server.request.query" + }, + { + "address": "server.request.body" + }, + { + "address": "server.request.path_params" + }, + { + "address": "graphql.server.all_resolvers" + }, + { + "address": "graphql.server.resolver" + } + ], + "db_type": [ + { + "address": "server.db.system" + } + ] + }, + "operator": "sqli_detector@v2" + } + ], + "transformers": [], + "on_match": [ + "stack_trace" + ] + }, { "id": "sqr-000-001", "name": "SSRF: Try to access the credential manager of the main cloud services", @@ -6606,9 +6846,6 @@ { "address": "server.request.headers.no_cookies" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -6654,9 +6891,6 @@ { "address": "server.request.headers.no_cookies" }, - { - "address": "grpc.server.request.message" - }, { "address": "graphql.server.all_resolvers" }, @@ -8199,6 +8433,57 @@ } ], "processors": [ + { + "id": "http-endpoint-fingerprint", + "generator": "http_endpoint_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "method": [ + { + "address": "server.request.method" + } + ], + "uri_raw": [ + { + "address": "server.request.uri.raw" + } + ], + "body": [ + { + "address": "server.request.body" + } + ], + "query": [ + { + "address": "server.request.query" + } + ], + "output": "_dd.appsec.fp.http.endpoint" + } + ] + }, + "evaluate": false, + "output": true + }, { "id": "extract-content", "generator": "extract_schema", @@ -8348,9 +8633,155 @@ }, "evaluate": false, "output": true + }, + { + "id": "http-header-fingerprint", + "generator": "http_header_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.header" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-network-fingerprint", + "generator": "http_network_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.network" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "session-fingerprint", + "generator": "session_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "cookies": [ + { + "address": "server.request.cookies" + } + ], + "session_id": [ + { + "address": "usr.session_id" + } + ], + "user_id": [ + { + "address": "usr.id" + } + ], + "output": "_dd.appsec.fp.session" + } + ] + }, + "evaluate": false, + "output": true } ], "scanners": [ + { + "id": "406f8606-52c4-4663-8db9-df70f9e8766c", + "name": "ZIP Code", + "key": { + "operator": "match_regex", + "parameters": { + "regex": "\\b(?:zip|postal)\\b", + "options": { + "case_sensitive": false, + "min_length": 3 + } + } + }, + "value": { + "operator": "match_regex", + "parameters": { + "regex": "^[0-9]{5}(?:-[0-9]{4})?$", + "options": { + "case_sensitive": true, + "min_length": 5 + } + } + }, + "tags": { + "type": "zipcode", + "category": "address" + } + }, { "id": "JU1sRk3mSzqSUJn6GrVn7g", "name": "American Express Card Scanner (4+4+4+3 digits)", @@ -9117,6 +9548,34 @@ "category": "payment" } }, + { + "id": "18b608bd7a764bff5b2344c0", + "name": "Phone number", + "key": { + "operator": "match_regex", + "parameters": { + "regex": "\\bphone|number|mobile\\b", + "options": { + "case_sensitive": false, + "min_length": 3 + } + } + }, + "value": { + "operator": "match_regex", + "parameters": { + "regex": "^(?:\\(\\+\\d{1,3}\\)|\\+\\d{1,3}|00\\d{1,3})?[-\\s\\.]?(?:\\(\\d{3}\\)[-\\s\\.]?)?(?:\\d[-\\s\\.]?){6,10}$", + "options": { + "case_sensitive": false, + "min_length": 6 + } + } + }, + "tags": { + "type": "phone", + "category": "pii" + } + }, { "id": "de0899e0cbaaa812bb624cf04c912071012f616d-mod", "name": "UK National Insurance Number Scanner", @@ -9317,4 +9776,4 @@ } } ] -} \ No newline at end of file +} From b51ecd6a26a05263c3ee4fc1e49495b218cea9dc Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Fri, 15 Nov 2024 15:45:32 +0100 Subject: [PATCH 02/16] test(helper): add request shutdown fingerprint test Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 64 +++++++++++++++++++++++++++ appsec/tests/helper/main.cpp | 68 +++++++++++++++++++++++++---- 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 8303494bec..109c12970f 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1763,6 +1764,69 @@ TEST(ClientTest, RequestExecWithAttack) } } +TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) +{ + auto smanager = std::make_shared(); + auto broker = new mock::broker(); + + client c(smanager, std::unique_ptr(broker)); + + set_extension_configuration_to(broker, c, EXTENSION_CONFIGURATION_ENABLED); + + // Request Init + { + network::request_init::request msg; + + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); + + msg.data = parameter::map(); + msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); + msg.data.add("server.request.method", parameter::string("GET"sv)); + msg.data.add("server.request.query", std::move(query)); + + network::request req(std::move(msg)); + + std::shared_ptr res; + EXPECT_CALL(*broker, recv(_)).WillOnce(Return(req)); + EXPECT_CALL(*broker, + send( + testing::An &>())) + .WillOnce(DoAll(testing::SaveArg<0>(&res), Return(true))); + + EXPECT_TRUE(c.run_request()); + auto msg_res = + dynamic_cast(res.get()); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "ok"); + EXPECT_EQ(msg_res->triggers.size(), 0); + } + + // Request Execution + { + network::request_shutdown::request msg; + msg.data = parameter::map(); + msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); + + network::request req(std::move(msg)); + + std::shared_ptr res; + EXPECT_CALL(*broker, recv(_)).WillOnce(Return(req)); + EXPECT_CALL(*broker, + send( + testing::An &>())) + .WillOnce(DoAll(testing::SaveArg<0>(&res), Return(true))); + + EXPECT_TRUE(c.run_request()); + auto msg_res = + dynamic_cast(res.get()); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + EXPECT_FALSE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + std::regex( + "http-get-[A-Za-z0-9]{8}-[A-Za-z0-9]{8}-([A-Za-z0-9]{8})?"))); + } +} + TEST(ClientTest, RequestExecWithoutClientInit) { auto smanager = std::make_shared(); diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 064f9e1ce5..00cff2e2f0 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -122,9 +122,9 @@ std::string create_sample_rules_ok() "address": "server.response.code" } ], - "regex":1991, + "regex": 1991, "options": { - "case_sensitive": "false" + "case_sensitive": "false" } }, "operator": "match_regex" @@ -164,13 +164,12 @@ std::string create_sample_rules_ok() "output": "_dd.appsec.s.req.headers.no_cookies" }, { - "inputs": [ - { - "address": "server.request.body" - } - ], - "output": "_dd.appsec.s.req.body" - } + "inputs": [ { + "address": "server.request.body" + } + ], + "output": "_dd.appsec.s.req.body" + } ], "scanners": [ { @@ -182,6 +181,57 @@ std::string create_sample_rules_ok() }, "evaluate": false, "output": true + }, + { + "id": "http-endpoint-fingerprint", + "generator": "http_endpoint_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "method": [ + { + "address": "server.request.method" + } + ], + "uri_raw": [ + { + "address": "server.request.uri.raw" + } + ], + "body": [ + { + "address": "server.request.body" + } + ], + "query": [ + { + "address": "server.request.query" + } + ], + "output": "_dd.appsec.fp.http.endpoint" + } + ] + }, + "evaluate": false, + "output": true } ], "scanners": [], From 218d34b2eca39c42ea884b238558c8a7b6f958b2 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Mon, 18 Nov 2024 14:32:18 +0100 Subject: [PATCH 03/16] feat(helper): avoid meta compression for fingerprints Signed-off-by: Alexandre Rulleau --- appsec/src/helper/subscriber/waf.cpp | 4 +++- appsec/tests/helper/client_test.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/appsec/src/helper/subscriber/waf.cpp b/appsec/src/helper/subscriber/waf.cpp index edffb4691e..93894419c7 100644 --- a/appsec/src/helper/subscriber/waf.cpp +++ b/appsec/src/helper/subscriber/waf.cpp @@ -266,7 +266,9 @@ void instance::listener::get_meta_and_metrics( for (const auto &[key, value] : schemas_) { std::string schema = value; - if (value.length() > max_plain_schema_allowed) { + if (value.length() > max_plain_schema_allowed && + key.starts_with("_dd.appsec.s")) { + auto encoded = compress(schema); if (encoded) { schema = base64_encode(encoded.value(), false); diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 109c12970f..8dd0f8fb2f 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1801,7 +1801,7 @@ TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) EXPECT_EQ(msg_res->triggers.size(), 0); } - // Request Execution + // Request Shutdown { network::request_shutdown::request msg; msg.data = parameter::map(); From 5e0cb00762eb28d0e08f8bfd051ceba56b1eb6fb Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Mon, 18 Nov 2024 15:42:03 +0100 Subject: [PATCH 04/16] test(integration): add integration test for fingerprints Signed-off-by: Alexandre Rulleau --- .../appsec/php/integration/CommonTests.groovy | 5 + .../integration/src/test/waf/recommended.json | 271 ++++++++++++++---- 2 files changed, 226 insertions(+), 50 deletions(-) diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy index 84ca54e07a..70b4587714 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy @@ -222,6 +222,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" != '' } @Test @@ -236,6 +237,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" != '' } @Test @@ -249,6 +251,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" != '' } @Test @@ -262,6 +265,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" != '' } @Test @@ -278,6 +282,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' assert span.meta."appsec.blocked" == "true" + assert span.meta."_dd.appsec.fp.http.endpoint" != '' } @Test diff --git a/appsec/tests/integration/src/test/waf/recommended.json b/appsec/tests/integration/src/test/waf/recommended.json index 0fbc7b4c01..17add7f0d7 100644 --- a/appsec/tests/integration/src/test/waf/recommended.json +++ b/appsec/tests/integration/src/test/waf/recommended.json @@ -6754,15 +6754,15 @@ "parameters": { "inputs": [ { - "address": "server.request.body", - "key_path": [ - "message" - ] + "address": "server.request.body", + "key_path": [ + "message" + ] }, { "address": "server.response.body", "key_path": [ - "message" + "message" ] } ], @@ -6777,24 +6777,24 @@ "id": "poison-in-json-block", "name": "poison-in-json-block", "tags": { - "type": "security_scanner", - "category": "attack_attempt" + "type": "security_scanner", + "category": "attack_attempt" }, "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.response.body", - "key_path": [ - "message" - ] - } - ], - "regex": "(?i)block_this" - }, - "operator": "match_regex" - } + { + "parameters": { + "inputs": [ + { + "address": "server.response.body", + "key_path": [ + "message" + ] + } + ], + "regex": "(?i)block_this" + }, + "operator": "match_regex" + } ], "transformers": [], "on_match": [ @@ -6802,35 +6802,35 @@ ] }, { - "id": "poison-in-xml", - "name": "poison-in-xml", - "tags": { - "type": "security_scanner", - "category": "attack_attempt" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.request.body", - "key_path": [ - "note" - ] - }, - { - "address": "server.response.body", - "key_path": [ - "note" - ] - } - ], - "regex": "(?i).*poison.*" - }, - "operator": "match_regex" - } - ], - "transformers": [] + "id": "poison-in-xml", + "name": "poison-in-xml", + "tags": { + "type": "security_scanner", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.body", + "key_path": [ + "note" + ] + }, + { + "address": "server.response.body", + "key_path": [ + "note" + ] + } + ], + "regex": "(?i).*poison.*" + }, + "operator": "match_regex" + } + ], + "transformers": [] } ], "rules_data": [ @@ -6884,5 +6884,176 @@ "location": "https://datadoghq.com" } } + ], + "processors": [ + { + "id": "http-endpoint-fingerprint", + "generator": "http_endpoint_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "method": [ + { + "address": "server.request.method" + } + ], + "uri_raw": [ + { + "address": "server.request.uri.raw" + } + ], + "body": [ + { + "address": "server.request.body" + } + ], + "query": [ + { + "address": "server.request.query" + } + ], + "output": "_dd.appsec.fp.http.endpoint" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-header-fingerprint", + "generator": "http_header_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.header" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-network-fingerprint", + "generator": "http_network_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.network" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "session-fingerprint", + "generator": "session_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "cookies": [ + { + "address": "server.request.cookies" + } + ], + "session_id": [ + { + "address": "usr.session_id" + } + ], + "user_id": [ + { + "address": "usr.id" + } + ], + "output": "_dd.appsec.fp.session" + } + ] + }, + "evaluate": false, + "output": true + } ] } From 7e3a0f802bdfb496fb3cdfceedb7a6c1f02df6af Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 19 Nov 2024 10:43:44 +0100 Subject: [PATCH 05/16] chore(helper): correct variable names Signed-off-by: Alexandre Rulleau --- appsec/src/helper/subscriber/waf.cpp | 19 ++++++++++--------- appsec/src/helper/subscriber/waf.hpp | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/appsec/src/helper/subscriber/waf.cpp b/appsec/src/helper/subscriber/waf.cpp index 93894419c7..f258ea548c 100644 --- a/appsec/src/helper/subscriber/waf.cpp +++ b/appsec/src/helper/subscriber/waf.cpp @@ -233,9 +233,10 @@ void instance::listener::call(dds::parameter_view &data, event &event) // NOLINTNEXTLINE total_runtime_ += res.total_runtime / 1000.0; - const parameter_view schemas{res.derivatives}; - for (const auto &schema : schemas) { - schemas_.emplace(schema.key(), std::move(parameter_to_json(schema))); + const parameter_view derivatives{res.derivatives}; + for (const auto &derivative : derivatives) { + derivatives_.emplace( + derivative.key(), std::move(parameter_to_json(derivative))); } switch (code) { @@ -264,19 +265,19 @@ void instance::listener::get_meta_and_metrics( meta[std::string(tag::event_rules_version)] = ruleset_version_; metrics[tag::waf_duration] = total_runtime_; - for (const auto &[key, value] : schemas_) { - std::string schema = value; + for (const auto &[key, value] : derivatives_) { + std::string derivative = value; if (value.length() > max_plain_schema_allowed && key.starts_with("_dd.appsec.s")) { - auto encoded = compress(schema); + auto encoded = compress(derivative); if (encoded) { - schema = base64_encode(encoded.value(), false); + derivative = base64_encode(encoded.value(), false); } } - if (schema.length() <= max_schema_size) { - meta.emplace(key, std::move(schema)); + if (derivative.length() <= max_schema_size) { + meta.emplace(key, std::move(derivative)); } } } diff --git a/appsec/src/helper/subscriber/waf.hpp b/appsec/src/helper/subscriber/waf.hpp index 513855ddf6..2b6f9c9e68 100644 --- a/appsec/src/helper/subscriber/waf.hpp +++ b/appsec/src/helper/subscriber/waf.hpp @@ -46,7 +46,7 @@ class instance : public dds::subscriber { std::chrono::microseconds waf_timeout_; double total_runtime_{0.0}; std::string_view ruleset_version_; - std::map schemas_; + std::map derivatives_; }; // NOLINTNEXTLINE(google-runtime-references) From 1a0b9721f872404387cf4a9f7b1f9e8eaed54285 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 19 Nov 2024 13:43:36 +0100 Subject: [PATCH 06/16] test: apply reviewer suggestions Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 21 +++++++++---------- .../appsec/php/integration/CommonTests.groovy | 10 ++++----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 8dd0f8fb2f..c69002f9ff 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1764,7 +1764,7 @@ TEST(ClientTest, RequestExecWithAttack) } } -TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) +TEST(ClientTest, RequestShutdownWithWithAttackAndFingerprint) { auto smanager = std::make_shared(); auto broker = new mock::broker(); @@ -1776,14 +1776,7 @@ TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) // Request Init { network::request_init::request msg; - - auto query = parameter::map(); - query.add("query", parameter::string("asdfds"sv)); - msg.data = parameter::map(); - msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); - msg.data.add("server.request.method", parameter::string("GET"sv)); - msg.data.add("server.request.query", std::move(query)); network::request req(std::move(msg)); @@ -1804,8 +1797,15 @@ TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) // Request Shutdown { network::request_shutdown::request msg; + + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); + msg.data = parameter::map(); msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); + msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); + msg.data.add("server.request.method", parameter::string("GET"sv)); + msg.data.add("server.request.query", std::move(query)); network::request req(std::move(msg)); @@ -1820,10 +1820,9 @@ TEST(ClientTest, RequestShutdownWithAttackAndFingerprint) auto msg_res = dynamic_cast(res.get()); EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); - EXPECT_FALSE(std::regex_match( + EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex( - "http-get-[A-Za-z0-9]{8}-[A-Za-z0-9]{8}-([A-Za-z0-9]{8})?"))); + std::regex("\"http-get(-[A-Za-z0-9]*){2,3}\""))); } } diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy index 70b4587714..6a572c7453 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy @@ -222,7 +222,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -237,7 +237,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -251,7 +251,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -265,7 +265,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -282,7 +282,7 @@ trait CommonTests { assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' assert span.meta."appsec.blocked" == "true" - assert span.meta."_dd.appsec.fp.http.endpoint" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test From 72477a7bac5106af8e5056f31130c321d2aa0429 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 19 Nov 2024 15:04:53 +0100 Subject: [PATCH 07/16] test(integration): add integration test for all fingerprints types Signed-off-by: Alexandre Rulleau --- .../appsec/php/integration/CommonTests.groovy | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy index 6a572c7453..6026f82de2 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy @@ -222,7 +222,6 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -237,7 +236,24 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ + } + + @Test + void 'user login fingerprint'() { + def trace = container.traceFromRequest('/user_login_success.php?id=user2020') { HttpResponse resp -> + assert resp.statusCode() == 403 + assert resp.body().text.contains('blocked') + } + + Span span = trace.first() + assert span.meta."appsec.blocked" == "true" + assert span.metrics."_dd.appsec.enabled" == 1.0d + assert span.metrics."_dd.appsec.waf.duration" > 0.0d + assert span.meta."_dd.appsec.event_rules.version" != '' + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3}"$/ + assert span.meta."_dd.appsec.fp.http.header" ==~ /^"hdr(-[0-9]*-[a-zA-Z0-9]*){2}"$/ + assert span.meta."_dd.appsec.fp.http.network" ==~ /^"net-[0-9]*-[a-zA-Z0-9]*"$/ + assert span.meta."_dd.appsec.fp.session" ==~ /^"ssn(-[a-zA-Z0-9]*){4}"$/ } @Test @@ -251,7 +267,6 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -265,7 +280,6 @@ trait CommonTests { assert span.metrics."_dd.appsec.enabled" == 1.0d assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test @@ -282,7 +296,6 @@ trait CommonTests { assert span.metrics."_dd.appsec.waf.duration" > 0.0d assert span.meta."_dd.appsec.event_rules.version" != '' assert span.meta."appsec.blocked" == "true" - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3,4}"$/ } @Test From ab78a5bf6e60225ef8df26c3051dd21f3931f252 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 19 Nov 2024 15:51:42 +0100 Subject: [PATCH 08/16] test(helper): add unitary test for all fingerprints types Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 33 ++++++- appsec/tests/helper/main.cpp | 140 ++++++++++++++++++++++++++-- 2 files changed, 162 insertions(+), 11 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index c69002f9ff..3c088acda3 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1764,7 +1764,7 @@ TEST(ClientTest, RequestExecWithAttack) } } -TEST(ClientTest, RequestShutdownWithWithAttackAndFingerprint) +TEST(ClientTest, RequestShutdownWithFingerprints) { auto smanager = std::make_shared(); auto broker = new mock::broker(); @@ -1798,15 +1798,25 @@ TEST(ClientTest, RequestShutdownWithWithAttackAndFingerprint) { network::request_shutdown::request msg; - auto query = parameter::map(); - query.add("query", parameter::string("asdfds"sv)); - msg.data = parameter::map(); msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); + + // Endpoint Fingerprint inputs + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); msg.data.add("server.request.method", parameter::string("GET"sv)); msg.data.add("server.request.query", std::move(query)); + // Network and Headers Fingerprint inputs + msg.data.add( + "server.request.headers.no_cookies", parameter::string(""sv)); + + // Session Fingerprint inputs + msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); + msg.data.add("usr.session_id", parameter::string("asdfds"sv)); + msg.data.add("usr.id", parameter::string("asdfds"sv)); + network::request req(std::move(msg)); std::shared_ptr res; @@ -1820,9 +1830,22 @@ TEST(ClientTest, RequestShutdownWithWithAttackAndFingerprint) auto msg_res = dynamic_cast(res.get()); EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("\"http-get(-[A-Za-z0-9]*){2,3}\""))); + std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + + EXPECT_TRUE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), + std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); } } diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 00cff2e2f0..61329c36e6 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -13,7 +13,9 @@ std::string create_sample_rules_ok() { const static char data[] = R"({ "version": "2.1", - "metadata": { "rules_version" : "1.2.3" }, + "metadata": { + "rules_version": "1.2.3" + }, "rules": [ { "id": "blk-001-001", @@ -30,7 +32,9 @@ std::string create_sample_rules_ok() "address": "http.client_ip" } ], - "list": ["192.168.1.1"] + "list": [ + "192.168.1.1" + ] }, "operator": "ip_match" } @@ -55,7 +59,9 @@ std::string create_sample_rules_ok() "address": "http.client_ip" } ], - "list": ["192.168.1.2"] + "list": [ + "192.168.1.2" + ] }, "operator": "ip_match" } @@ -91,7 +97,9 @@ std::string create_sample_rules_ok() "operator": "phrase_match" } ], - "transformers": ["lowercase"] + "transformers": [ + "lowercase" + ] }, { "id": "req_shutdown_rule", @@ -164,7 +172,8 @@ std::string create_sample_rules_ok() "output": "_dd.appsec.s.req.headers.no_cookies" }, { - "inputs": [ { + "inputs": [ + { "address": "server.request.body" } ], @@ -232,6 +241,124 @@ std::string create_sample_rules_ok() }, "evaluate": false, "output": true + }, + { + "id": "http-header-fingerprint", + "generator": "http_header_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.header" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-network-fingerprint", + "generator": "http_network_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.network" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "session-fingerprint", + "generator": "session_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "cookies": [ + { + "address": "server.request.cookies" + } + ], + "session_id": [ + { + "address": "usr.session_id" + } + ], + "user_id": [ + { + "address": "usr.id" + } + ], + "output": "_dd.appsec.fp.session" + } + ] + }, + "evaluate": false, + "output": true } ], "scanners": [], @@ -244,7 +371,8 @@ std::string create_sample_rules_ok() } } ] -})"; +} +)"; char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; int fd = mkstemp(tmpl); From 5816afa71baf4f3ac6f4bd6d1e25d9c5b86e8526 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Tue, 19 Nov 2024 18:16:28 +0100 Subject: [PATCH 09/16] test(helper): create separate config for fingerprints Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 17 +- appsec/tests/helper/common.hpp | 1 + appsec/tests/helper/main.cpp | 376 ++-------------------------- 3 files changed, 32 insertions(+), 362 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 3c088acda3..76dee19ade 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1771,7 +1771,22 @@ TEST(ClientTest, RequestShutdownWithFingerprints) client c(smanager, std::unique_ptr(broker)); - set_extension_configuration_to(broker, c, EXTENSION_CONFIGURATION_ENABLED); + // Set Extension Configuration + { + auto fn = create_sample_rules_ok_with_fingerprint(); + network::client_init::request msg; + msg.pid = 1729; + msg.enabled_configuration = true; + msg.runtime_version = "1.0"; + msg.client_version = "2.0"; + msg.engine_settings.rules_file = fn; + msg.engine_settings.waf_timeout_us = 1000000; + msg.engine_settings.schema_extraction.enabled = false; + msg.engine_settings.schema_extraction.sample_rate = 1; + + msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; + send_client_init(broker, c, std::move(msg)); + } // Request Init { diff --git a/appsec/tests/helper/common.hpp b/appsec/tests/helper/common.hpp index 0a27bc7269..95e919633d 100644 --- a/appsec/tests/helper/common.hpp +++ b/appsec/tests/helper/common.hpp @@ -32,4 +32,5 @@ using namespace std::literals; using namespace std::chrono_literals; std::string create_sample_rules_ok(); +std::string create_sample_rules_ok_with_fingerprint(); std::string create_sample_rules_invalid(); diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 61329c36e6..abc4626461 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -11,368 +11,22 @@ std::string create_sample_rules_ok() { - const static char data[] = R"({ - "version": "2.1", - "metadata": { - "rules_version": "1.2.3" - }, - "rules": [ - { - "id": "blk-001-001", - "name": "Block IP Addresses", - "tags": { - "type": "block_ip", - "category": "security_response" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "http.client_ip" - } - ], - "list": [ - "192.168.1.1" - ] - }, - "operator": "ip_match" - } - ], - "transformers": [], - "on_match": [ - "block" - ] - }, - { - "id": "blk-001-002", - "name": "Block IP Addresses with all actions", - "tags": { - "type": "block_ip", - "category": "security_response" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "http.client_ip" - } - ], - "list": [ - "192.168.1.2" - ] - }, - "operator": "ip_match" - } - ], - "transformers": [], - "on_match": [ - "block", - "redirect", - "stack_trace", - "extract_schema" - ] - }, - { - "id": "crs-913-110", - "name": "Found request header associated with Acunetix security scanner", - "tags": { - "type": "security_scanner", - "crs_id": "913110", - "category": "attack_attempt" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "list": [ - "acunetix-product" - ] - }, - "operator": "phrase_match" - } - ], - "transformers": [ - "lowercase" - ] - }, - { - "id": "req_shutdown_rule", - "name": "Rule match on response code", - "tags": { - "type": "req_shutdown_type", - "crs_id": "none", - "category": "attack_attempt" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "list": [ - "Arachni" - ] - }, - "operator": "phrase_match" - }, - { - "parameters": { - "inputs": [ - { - "address": "server.response.code" - } - ], - "regex": 1991, - "options": { - "case_sensitive": "false" - } - }, - "operator": "match_regex" - } - ] - } - ], - "processors": [ - { - "id": "processor-001", - "generator": "extract_schema", - "conditions": [ - { - "operator": "equals", - "parameters": { - "inputs": [ - { - "address": "waf.context.processor", - "key_path": [ - "extract-schema" - ] - } - ], - "type": "boolean", - "value": true - } - } - ], - "parameters": { - "mappings": [ - { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "output": "_dd.appsec.s.req.headers.no_cookies" - }, - { - "inputs": [ - { - "address": "server.request.body" - } - ], - "output": "_dd.appsec.s.req.body" - } - ], - "scanners": [ - { - "tags": { - "category": "pii" - } - } - ] - }, - "evaluate": false, - "output": true - }, - { - "id": "http-endpoint-fingerprint", - "generator": "http_endpoint_fingerprint", - "conditions": [ - { - "operator": "exists", - "parameters": { - "inputs": [ - { - "address": "waf.context.event" - }, - { - "address": "server.business_logic.users.login.failure" - }, - { - "address": "server.business_logic.users.login.success" - } - ] - } - } - ], - "parameters": { - "mappings": [ - { - "method": [ - { - "address": "server.request.method" - } - ], - "uri_raw": [ - { - "address": "server.request.uri.raw" - } - ], - "body": [ - { - "address": "server.request.body" - } - ], - "query": [ - { - "address": "server.request.query" - } - ], - "output": "_dd.appsec.fp.http.endpoint" - } - ] - }, - "evaluate": false, - "output": true - }, - { - "id": "http-header-fingerprint", - "generator": "http_header_fingerprint", - "conditions": [ - { - "operator": "exists", - "parameters": { - "inputs": [ - { - "address": "waf.context.event" - }, - { - "address": "server.business_logic.users.login.failure" - }, - { - "address": "server.business_logic.users.login.success" - } - ] - } - } - ], - "parameters": { - "mappings": [ - { - "headers": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "output": "_dd.appsec.fp.http.header" - } - ] - }, - "evaluate": false, - "output": true - }, - { - "id": "http-network-fingerprint", - "generator": "http_network_fingerprint", - "conditions": [ - { - "operator": "exists", - "parameters": { - "inputs": [ - { - "address": "waf.context.event" - }, - { - "address": "server.business_logic.users.login.failure" - }, - { - "address": "server.business_logic.users.login.success" - } - ] - } - } - ], - "parameters": { - "mappings": [ - { - "headers": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "output": "_dd.appsec.fp.http.network" - } - ] - }, - "evaluate": false, - "output": true - }, - { - "id": "session-fingerprint", - "generator": "session_fingerprint", - "conditions": [ - { - "operator": "exists", - "parameters": { - "inputs": [ - { - "address": "waf.context.event" - }, - { - "address": "server.business_logic.users.login.failure" - }, - { - "address": "server.business_logic.users.login.success" - } - ] - } - } - ], - "parameters": { - "mappings": [ - { - "cookies": [ - { - "address": "server.request.cookies" - } - ], - "session_id": [ - { - "address": "usr.session_id" - } - ], - "user_id": [ - { - "address": "usr.id" - } - ], - "output": "_dd.appsec.fp.session" - } - ] - }, - "evaluate": false, - "output": true - } - ], - "scanners": [], - "actions": [ - { - "id": "redirect", - "type": "redirect_request", - "parameters": { - "location": "https://localhost" - } - } - ] + const static char data[] = + R"({"version":"2.1","metadata":{"rules_version":"1.2.3"},"rules":[{"id":"blk-001-001","name":"BlockIPAddresses","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.1"]},"operator":"ip_match"}],"transformers":[],"on_match":["block"]},{"id":"blk-001-002","name":"BlockIPAddresseswithallactions","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.2"]},"operator":"ip_match"}],"transformers":[],"on_match":["block","redirect","stack_trace","extract_schema"]},{"id":"crs-913-110","name":"FoundrequestheaderassociatedwithAcunetixsecurityscanner","tags":{"type":"security_scanner","crs_id":"913110","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["acunetix-product"]},"operator":"phrase_match"}],"transformers":["lowercase"]},{"id":"req_shutdown_rule","name":"Rulematchonresponsecode","tags":{"type":"req_shutdown_type","crs_id":"none","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["Arachni"]},"operator":"phrase_match"},{"parameters":{"inputs":[{"address":"server.response.code"}],"regex":1991,"options":{"case_sensitive":"false"}},"operator":"match_regex"}]}],"processors":[{"id":"processor-001","generator":"extract_schema","conditions":[{"operator":"equals","parameters":{"inputs":[{"address":"waf.context.processor","key_path":["extract-schema"]}],"type":"boolean","value":true}}],"parameters":{"mappings":[{"inputs":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.s.req.headers.no_cookies"},{"inputs":[{"address":"server.request.body"}],"output":"_dd.appsec.s.req.body"}],"scanners":[{"tags":{"category":"pii"}}]},"evaluate":false,"output":true}],"scanners":[],"actions":[{"id":"redirect","type":"redirect_request","parameters":{"location":"https://localhost"}}]})"; + + char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; + int fd = mkstemp(tmpl); + std::FILE *tmpf = fdopen(fd, "wb+"); + std::fwrite(data, sizeof(data) - 1, 1, tmpf); + std::fclose(tmpf); + + return tmpl; } -)"; + +std::string create_sample_rules_ok_with_fingerprint() +{ + const static char data[] = + R"({"version":"2.1","metadata":{"rules_version":"1.2.3"},"rules":[{"id":"blk-001-001","name":"BlockIPAddresses","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.1"]},"operator":"ip_match"}],"transformers":[],"on_match":["block"]},{"id":"blk-001-002","name":"BlockIPAddresseswithallactions","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.2"]},"operator":"ip_match"}],"transformers":[],"on_match":["block","redirect","stack_trace","extract_schema"]},{"id":"crs-913-110","name":"FoundrequestheaderassociatedwithAcunetixsecurityscanner","tags":{"type":"security_scanner","crs_id":"913110","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["acunetix-product"]},"operator":"phrase_match"}],"transformers":["lowercase"]},{"id":"req_shutdown_rule","name":"Rulematchonresponsecode","tags":{"type":"req_shutdown_type","crs_id":"none","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["Arachni"]},"operator":"phrase_match"},{"parameters":{"inputs":[{"address":"server.response.code"}],"regex":1991,"options":{"case_sensitive":"false"}},"operator":"match_regex"}]}],"processors":[{"id":"processor-001","generator":"extract_schema","conditions":[{"operator":"equals","parameters":{"inputs":[{"address":"waf.context.processor","key_path":["extract-schema"]}],"type":"boolean","value":true}}],"parameters":{"mappings":[{"inputs":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.s.req.headers.no_cookies"},{"inputs":[{"address":"server.request.body"}],"output":"_dd.appsec.s.req.body"}],"scanners":[{"tags":{"category":"pii"}}]},"evaluate":false,"output":true},{"id":"http-endpoint-fingerprint","generator":"http_endpoint_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"method":[{"address":"server.request.method"}],"uri_raw":[{"address":"server.request.uri.raw"}],"body":[{"address":"server.request.body"}],"query":[{"address":"server.request.query"}],"output":"_dd.appsec.fp.http.endpoint"}]},"evaluate":false,"output":true},{"id":"http-header-fingerprint","generator":"http_header_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"headers":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.fp.http.header"}]},"evaluate":false,"output":true},{"id":"http-network-fingerprint","generator":"http_network_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"headers":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.fp.http.network"}]},"evaluate":false,"output":true},{"id":"session-fingerprint","generator":"session_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"cookies":[{"address":"server.request.cookies"}],"session_id":[{"address":"usr.session_id"}],"user_id":[{"address":"usr.id"}],"output":"_dd.appsec.fp.session"}]},"evaluate":false,"output":true}],"scanners":[],"actions":[{"id":"redirect","type":"redirect_request","parameters":{"location":"https://localhost"}}]})"; char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; int fd = mkstemp(tmpl); From bff8feb4cb4642c7c27f2e6b78d5fec4c499c7b1 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 20 Nov 2024 14:24:29 +0100 Subject: [PATCH 10/16] test(helper): add unitary test for all request types Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 199 ++++++++++++++++++++++++---- 1 file changed, 174 insertions(+), 25 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 76dee19ade..f300e668a8 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -4,9 +4,11 @@ // This product includes software developed at Datadog // (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc. #include "common.hpp" +#include "parameter.hpp" #include #include #include +#include #include #include #include @@ -75,9 +77,17 @@ int count_schemas(const std::map &meta) return schemas; } -network::client_init::request get_default_client_init_msg() +network::client_init::request get_default_client_init_msg( + std::string rule_config = "valid") { - auto fn = create_sample_rules_ok(); + std::string fn; + if (rule_config == "valid") + fn = create_sample_rules_ok(); + else if (rule_config == "fingerprint") + fn = create_sample_rules_ok_with_fingerprint(); + else + fn = create_sample_rules_invalid(); + network::client_init::request msg; msg.pid = 1729; msg.enabled_configuration = true; @@ -91,10 +101,11 @@ network::client_init::request get_default_client_init_msg() return msg; } -void set_extension_configuration_to( - mock::broker *broker, client &c, std::optional status) +void set_extension_configuration_to(mock::broker *broker, client &c, + std::optional status, std::string rule_config = "valid") { - network::client_init::request msg = get_default_client_init_msg(); + network::client_init::request msg = + get_default_client_init_msg(rule_config); msg.enabled_configuration = status; send_client_init(broker, c, std::move(msg)); @@ -104,9 +115,6 @@ void request_init(mock::broker *broker, client &c) { network::request_init::request msg; msg.data = parameter::map(); - msg.data.add( - "server.request.headers.no_cookies", parameter::string("Arachni"sv)); - msg.data.add("server.request.body", parameter::string("asdfds"sv)); network::request req(std::move(msg)); @@ -787,6 +795,8 @@ TEST(ClientTest, RequestShutdown) network::request_shutdown::request msg; msg.data = parameter::map(); msg.data.add("server.response.code", parameter::string("1991"sv)); + msg.data.add("server.request.headers.no_cookies", + parameter::string("Arachni"sv)); network::request req(std::move(msg)); @@ -1764,34 +1774,38 @@ TEST(ClientTest, RequestExecWithAttack) } } -TEST(ClientTest, RequestShutdownWithFingerprints) +TEST(ClientTest, RequestInitWithFingerprint) { auto smanager = std::make_shared(); auto broker = new mock::broker(); client c(smanager, std::unique_ptr(broker)); - // Set Extension Configuration - { - auto fn = create_sample_rules_ok_with_fingerprint(); - network::client_init::request msg; - msg.pid = 1729; - msg.enabled_configuration = true; - msg.runtime_version = "1.0"; - msg.client_version = "2.0"; - msg.engine_settings.rules_file = fn; - msg.engine_settings.waf_timeout_us = 1000000; - msg.engine_settings.schema_extraction.enabled = false; - msg.engine_settings.schema_extraction.sample_rate = 1; - - msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; - send_client_init(broker, c, std::move(msg)); - } + set_extension_configuration_to( + broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); // Request Init { network::request_init::request msg; + msg.data = parameter::map(); + msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); + + // Endpoint Fingerprint inputs + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); + msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); + msg.data.add("server.request.method", parameter::string("GET"sv)); + msg.data.add("server.request.query", std::move(query)); + + // Network and Headers Fingerprint inputs + msg.data.add( + "server.request.headers.no_cookies", parameter::string(""sv)); + + // Session Fingerprint inputs + msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); + msg.data.add("usr.session_id", parameter::string("asdfds"sv)); + msg.data.add("usr.id", parameter::string("asdfds"sv)); network::request req(std::move(msg)); @@ -1805,9 +1819,144 @@ TEST(ClientTest, RequestShutdownWithFingerprints) EXPECT_TRUE(c.run_request()); auto msg_res = dynamic_cast(res.get()); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + } + + // Request Shutdown + { + network::request_shutdown::request msg; + msg.data = parameter::map(); + + network::request req(std::move(msg)); + + std::shared_ptr res; + EXPECT_CALL(*broker, recv(_)).WillOnce(Return(req)); + EXPECT_CALL(*broker, + send( + testing::An &>())) + .WillOnce(DoAll(testing::SaveArg<0>(&res), Return(true))); + + EXPECT_TRUE(c.run_request()); + auto msg_res = + dynamic_cast(res.get()); EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "ok"); EXPECT_EQ(msg_res->triggers.size(), 0); + + EXPECT_TRUE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + + EXPECT_TRUE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), + std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); } +} + +TEST(ClientTest, RequestExecWithFingerprint) +{ + auto smanager = std::make_shared(); + auto broker = new mock::broker(); + + client c(smanager, std::unique_ptr(broker)); + + set_extension_configuration_to( + broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); + + request_init(broker, c); + + // Request Exec + { + network::request_exec::request msg; + msg.data = parameter::map(); + msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); + + // Endpoint Fingerprint inputs + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); + msg.data.add("server.request.uri.raw", parameter::string("asdfds"sv)); + msg.data.add("server.request.method", parameter::string("GET"sv)); + msg.data.add("server.request.query", std::move(query)); + + // Network and Headers Fingerprint inputs + msg.data.add( + "server.request.headers.no_cookies", parameter::string(""sv)); + + // Session Fingerprint inputs + msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); + msg.data.add("usr.session_id", parameter::string("asdfds"sv)); + msg.data.add("usr.id", parameter::string("asdfds"sv)); + + network::request req(std::move(msg)); + + std::shared_ptr res; + EXPECT_CALL(*broker, recv(_)).WillOnce(Return(req)); + EXPECT_CALL(*broker, + send( + testing::An &>())) + .WillOnce(DoAll(testing::SaveArg<0>(&res), Return(true))); + + EXPECT_TRUE(c.run_request()); + auto msg_res = + dynamic_cast(res.get()); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + } + + // Request Shutdown + { + network::request_shutdown::request msg; + msg.data = parameter::map(); + + network::request req(std::move(msg)); + + std::shared_ptr res; + EXPECT_CALL(*broker, recv(_)).WillOnce(Return(req)); + EXPECT_CALL(*broker, + send( + testing::An &>())) + .WillOnce(DoAll(testing::SaveArg<0>(&res), Return(true))); + + EXPECT_TRUE(c.run_request()); + auto msg_res = + dynamic_cast(res.get()); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "ok"); + + EXPECT_TRUE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + + EXPECT_TRUE(std::regex_match( + msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + + EXPECT_TRUE( + std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), + std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); + } +} + +TEST(ClientTest, RequestShutdownWithFingerprint) +{ + auto smanager = std::make_shared(); + auto broker = new mock::broker(); + + client c(smanager, std::unique_ptr(broker)); + + set_extension_configuration_to( + broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); + + request_init(broker, c); // Request Shutdown { From f8f3c99a0d6948d53a55efd1a2a65ec73b3e3901 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 20 Nov 2024 15:11:38 +0100 Subject: [PATCH 11/16] chore(appsec: tests): apply feedbacks Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 38 +- appsec/tests/helper/main.cpp | 555 +++++++++++++++++- .../appsec/php/integration/CommonTests.groovy | 4 - 3 files changed, 571 insertions(+), 26 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index f300e668a8..1ebec947ac 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -77,17 +77,9 @@ int count_schemas(const std::map &meta) return schemas; } -network::client_init::request get_default_client_init_msg( - std::string rule_config = "valid") +network::client_init::request get_default_client_init_msg() { - std::string fn; - if (rule_config == "valid") - fn = create_sample_rules_ok(); - else if (rule_config == "fingerprint") - fn = create_sample_rules_ok_with_fingerprint(); - else - fn = create_sample_rules_invalid(); - + auto fn = create_sample_rules_ok(); network::client_init::request msg; msg.pid = 1729; msg.enabled_configuration = true; @@ -101,11 +93,10 @@ network::client_init::request get_default_client_init_msg( return msg; } -void set_extension_configuration_to(mock::broker *broker, client &c, - std::optional status, std::string rule_config = "valid") +void set_extension_configuration_to( + mock::broker *broker, client &c, std::optional status) { - network::client_init::request msg = - get_default_client_init_msg(rule_config); + network::client_init::request msg = get_default_client_init_msg(); msg.enabled_configuration = status; send_client_init(broker, c, std::move(msg)); @@ -1781,8 +1772,11 @@ TEST(ClientTest, RequestInitWithFingerprint) client c(smanager, std::unique_ptr(broker)); - set_extension_configuration_to( - broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); + network::client_init::request msg = get_default_client_init_msg(); + msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); + msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; + + send_client_init(broker, c, std::move(msg)); // Request Init { @@ -1867,9 +1861,11 @@ TEST(ClientTest, RequestExecWithFingerprint) client c(smanager, std::unique_ptr(broker)); - set_extension_configuration_to( - broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); + network::client_init::request msg = get_default_client_init_msg(); + msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); + msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; + send_client_init(broker, c, std::move(msg)); request_init(broker, c); // Request Exec @@ -1953,9 +1949,11 @@ TEST(ClientTest, RequestShutdownWithFingerprint) client c(smanager, std::unique_ptr(broker)); - set_extension_configuration_to( - broker, c, EXTENSION_CONFIGURATION_ENABLED, "fingerprint"); + network::client_init::request msg = get_default_client_init_msg(); + msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); + msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; + send_client_init(broker, c, std::move(msg)); request_init(broker, c); // Request Shutdown diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index abc4626461..1176d3d489 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -12,7 +12,198 @@ std::string create_sample_rules_ok() { const static char data[] = - R"({"version":"2.1","metadata":{"rules_version":"1.2.3"},"rules":[{"id":"blk-001-001","name":"BlockIPAddresses","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.1"]},"operator":"ip_match"}],"transformers":[],"on_match":["block"]},{"id":"blk-001-002","name":"BlockIPAddresseswithallactions","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.2"]},"operator":"ip_match"}],"transformers":[],"on_match":["block","redirect","stack_trace","extract_schema"]},{"id":"crs-913-110","name":"FoundrequestheaderassociatedwithAcunetixsecurityscanner","tags":{"type":"security_scanner","crs_id":"913110","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["acunetix-product"]},"operator":"phrase_match"}],"transformers":["lowercase"]},{"id":"req_shutdown_rule","name":"Rulematchonresponsecode","tags":{"type":"req_shutdown_type","crs_id":"none","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["Arachni"]},"operator":"phrase_match"},{"parameters":{"inputs":[{"address":"server.response.code"}],"regex":1991,"options":{"case_sensitive":"false"}},"operator":"match_regex"}]}],"processors":[{"id":"processor-001","generator":"extract_schema","conditions":[{"operator":"equals","parameters":{"inputs":[{"address":"waf.context.processor","key_path":["extract-schema"]}],"type":"boolean","value":true}}],"parameters":{"mappings":[{"inputs":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.s.req.headers.no_cookies"},{"inputs":[{"address":"server.request.body"}],"output":"_dd.appsec.s.req.body"}],"scanners":[{"tags":{"category":"pii"}}]},"evaluate":false,"output":true}],"scanners":[],"actions":[{"id":"redirect","type":"redirect_request","parameters":{"location":"https://localhost"}}]})"; + R"({ + "version": "2.1", + "metadata": { + "rules_version": "1.2.3" + }, + "rules": [ + { + "id": "blk-001-001", + "name": "BlockIPAddresses", + "tags": { + "type": "block_ip", + "category": "security_response" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "http.client_ip" + } + ], + "list": [ + "192.168.1.1" + ] + }, + "operator": "ip_match" + } + ], + "transformers": [], + "on_match": [ + "block" + ] + }, + { + "id": "blk-001-002", + "name": "BlockIPAddresseswithallactions", + "tags": { + "type": "block_ip", + "category": "security_response" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "http.client_ip" + } + ], + "list": [ + "192.168.1.2" + ] + }, + "operator": "ip_match" + } + ], + "transformers": [], + "on_match": [ + "block", + "redirect", + "stack_trace", + "extract_schema" + ] + }, + { + "id": "crs-913-110", + "name": "FoundrequestheaderassociatedwithAcunetixsecurityscanner", + "tags": { + "type": "security_scanner", + "crs_id": "913110", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "list": [ + "acunetix-product" + ] + }, + "operator": "phrase_match" + } + ], + "transformers": [ + "lowercase" + ] + }, + { + "id": "req_shutdown_rule", + "name": "Rulematchonresponsecode", + "tags": { + "type": "req_shutdown_type", + "crs_id": "none", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "list": [ + "Arachni" + ] + }, + "operator": "phrase_match" + }, + { + "parameters": { + "inputs": [ + { + "address": "server.response.code" + } + ], + "regex": 1991, + "options": { + "case_sensitive": "false" + } + }, + "operator": "match_regex" + } + ] + } + ], + "processors": [ + { + "id": "processor-001", + "generator": "extract_schema", + "conditions": [ + { + "operator": "equals", + "parameters": { + "inputs": [ + { + "address": "waf.context.processor", + "key_path": [ + "extract-schema" + ] + } + ], + "type": "boolean", + "value": true + } + } + ], + "parameters": { + "mappings": [ + { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.s.req.headers.no_cookies" + }, + { + "inputs": [ + { + "address": "server.request.body" + } + ], + "output": "_dd.appsec.s.req.body" + } + ], + "scanners": [ + { + "tags": { + "category": "pii" + } + } + ] + }, + "evaluate": false, + "output": true + } + ], + "scanners": [], + "actions": [ + { + "id": "redirect", + "type": "redirect_request", + "parameters": { + "location": "https://localhost" + } + } + ] +})"; char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; int fd = mkstemp(tmpl); @@ -26,7 +217,367 @@ std::string create_sample_rules_ok() std::string create_sample_rules_ok_with_fingerprint() { const static char data[] = - R"({"version":"2.1","metadata":{"rules_version":"1.2.3"},"rules":[{"id":"blk-001-001","name":"BlockIPAddresses","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.1"]},"operator":"ip_match"}],"transformers":[],"on_match":["block"]},{"id":"blk-001-002","name":"BlockIPAddresseswithallactions","tags":{"type":"block_ip","category":"security_response"},"conditions":[{"parameters":{"inputs":[{"address":"http.client_ip"}],"list":["192.168.1.2"]},"operator":"ip_match"}],"transformers":[],"on_match":["block","redirect","stack_trace","extract_schema"]},{"id":"crs-913-110","name":"FoundrequestheaderassociatedwithAcunetixsecurityscanner","tags":{"type":"security_scanner","crs_id":"913110","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["acunetix-product"]},"operator":"phrase_match"}],"transformers":["lowercase"]},{"id":"req_shutdown_rule","name":"Rulematchonresponsecode","tags":{"type":"req_shutdown_type","crs_id":"none","category":"attack_attempt"},"conditions":[{"parameters":{"inputs":[{"address":"server.request.headers.no_cookies"}],"list":["Arachni"]},"operator":"phrase_match"},{"parameters":{"inputs":[{"address":"server.response.code"}],"regex":1991,"options":{"case_sensitive":"false"}},"operator":"match_regex"}]}],"processors":[{"id":"processor-001","generator":"extract_schema","conditions":[{"operator":"equals","parameters":{"inputs":[{"address":"waf.context.processor","key_path":["extract-schema"]}],"type":"boolean","value":true}}],"parameters":{"mappings":[{"inputs":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.s.req.headers.no_cookies"},{"inputs":[{"address":"server.request.body"}],"output":"_dd.appsec.s.req.body"}],"scanners":[{"tags":{"category":"pii"}}]},"evaluate":false,"output":true},{"id":"http-endpoint-fingerprint","generator":"http_endpoint_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"method":[{"address":"server.request.method"}],"uri_raw":[{"address":"server.request.uri.raw"}],"body":[{"address":"server.request.body"}],"query":[{"address":"server.request.query"}],"output":"_dd.appsec.fp.http.endpoint"}]},"evaluate":false,"output":true},{"id":"http-header-fingerprint","generator":"http_header_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"headers":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.fp.http.header"}]},"evaluate":false,"output":true},{"id":"http-network-fingerprint","generator":"http_network_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"headers":[{"address":"server.request.headers.no_cookies"}],"output":"_dd.appsec.fp.http.network"}]},"evaluate":false,"output":true},{"id":"session-fingerprint","generator":"session_fingerprint","conditions":[{"operator":"exists","parameters":{"inputs":[{"address":"waf.context.event"},{"address":"server.business_logic.users.login.failure"},{"address":"server.business_logic.users.login.success"}]}}],"parameters":{"mappings":[{"cookies":[{"address":"server.request.cookies"}],"session_id":[{"address":"usr.session_id"}],"user_id":[{"address":"usr.id"}],"output":"_dd.appsec.fp.session"}]},"evaluate":false,"output":true}],"scanners":[],"actions":[{"id":"redirect","type":"redirect_request","parameters":{"location":"https://localhost"}}]})"; + R"({ + "version": "2.1", + "metadata": { + "rules_version": "1.2.3" + }, + "rules": [ + { + "id": "blk-001-001", + "name": "BlockIPAddresses", + "tags": { + "type": "block_ip", + "category": "security_response" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "http.client_ip" + } + ], + "list": [ + "192.168.1.1" + ] + }, + "operator": "ip_match" + } + ], + "transformers": [], + "on_match": [ + "block" + ] + }, + { + "id": "blk-001-002", + "name": "BlockIPAddresseswithallactions", + "tags": { + "type": "block_ip", + "category": "security_response" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "http.client_ip" + } + ], + "list": [ + "192.168.1.2" + ] + }, + "operator": "ip_match" + } + ], + "transformers": [], + "on_match": [ + "block", + "redirect", + "stack_trace", + "extract_schema" + ] + }, + { + "id": "crs-913-110", + "name": "FoundrequestheaderassociatedwithAcunetixsecurityscanner", + "tags": { + "type": "security_scanner", + "crs_id": "913110", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "list": [ + "acunetix-product" + ] + }, + "operator": "phrase_match" + } + ], + "transformers": [ + "lowercase" + ] + }, + { + "id": "req_shutdown_rule", + "name": "Rulematchonresponsecode", + "tags": { + "type": "req_shutdown_type", + "crs_id": "none", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "list": [ + "Arachni" + ] + }, + "operator": "phrase_match" + }, + { + "parameters": { + "inputs": [ + { + "address": "server.response.code" + } + ], + "regex": 1991, + "options": { + "case_sensitive": "false" + } + }, + "operator": "match_regex" + } + ] + } + ], + "processors": [ + { + "id": "processor-001", + "generator": "extract_schema", + "conditions": [ + { + "operator": "equals", + "parameters": { + "inputs": [ + { + "address": "waf.context.processor", + "key_path": [ + "extract-schema" + ] + } + ], + "type": "boolean", + "value": true + } + } + ], + "parameters": { + "mappings": [ + { + "inputs": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.s.req.headers.no_cookies" + }, + { + "inputs": [ + { + "address": "server.request.body" + } + ], + "output": "_dd.appsec.s.req.body" + } + ], + "scanners": [ + { + "tags": { + "category": "pii" + } + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-endpoint-fingerprint", + "generator": "http_endpoint_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "method": [ + { + "address": "server.request.method" + } + ], + "uri_raw": [ + { + "address": "server.request.uri.raw" + } + ], + "body": [ + { + "address": "server.request.body" + } + ], + "query": [ + { + "address": "server.request.query" + } + ], + "output": "_dd.appsec.fp.http.endpoint" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-header-fingerprint", + "generator": "http_header_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.header" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "http-network-fingerprint", + "generator": "http_network_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "headers": [ + { + "address": "server.request.headers.no_cookies" + } + ], + "output": "_dd.appsec.fp.http.network" + } + ] + }, + "evaluate": false, + "output": true + }, + { + "id": "session-fingerprint", + "generator": "session_fingerprint", + "conditions": [ + { + "operator": "exists", + "parameters": { + "inputs": [ + { + "address": "waf.context.event" + }, + { + "address": "server.business_logic.users.login.failure" + }, + { + "address": "server.business_logic.users.login.success" + } + ] + } + } + ], + "parameters": { + "mappings": [ + { + "cookies": [ + { + "address": "server.request.cookies" + } + ], + "session_id": [ + { + "address": "usr.session_id" + } + ], + "user_id": [ + { + "address": "usr.id" + } + ], + "output": "_dd.appsec.fp.session" + } + ] + }, + "evaluate": false, + "output": true + } + ], + "scanners": [], + "actions": [ + { + "id": "redirect", + "type": "redirect_request", + "parameters": { + "location": "https://localhost" + } + } + ] +})"; char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; int fd = mkstemp(tmpl); diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy index 6026f82de2..a7562bc190 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy @@ -246,10 +246,6 @@ trait CommonTests { } Span span = trace.first() - assert span.meta."appsec.blocked" == "true" - assert span.metrics."_dd.appsec.enabled" == 1.0d - assert span.metrics."_dd.appsec.waf.duration" > 0.0d - assert span.meta."_dd.appsec.event_rules.version" != '' assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3}"$/ assert span.meta."_dd.appsec.fp.http.header" ==~ /^"hdr(-[0-9]*-[a-zA-Z0-9]*){2}"$/ assert span.meta."_dd.appsec.fp.http.network" ==~ /^"net-[0-9]*-[a-zA-Z0-9]*"$/ From 96999d08f4fb8511f344722c49749cd4769056d1 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 20 Nov 2024 18:13:35 +0100 Subject: [PATCH 12/16] test(appsec: helper): fix client_test configurations split Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 24 +--- appsec/tests/helper/common.hpp | 1 - appsec/tests/helper/main.cpp | 209 +--------------------------- 3 files changed, 8 insertions(+), 226 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 1ebec947ac..2709806930 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1772,11 +1772,7 @@ TEST(ClientTest, RequestInitWithFingerprint) client c(smanager, std::unique_ptr(broker)); - network::client_init::request msg = get_default_client_init_msg(); - msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); - msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; - - send_client_init(broker, c, std::move(msg)); + set_extension_configuration_to(broker, c, EXTENSION_CONFIGURATION_ENABLED); // Request Init { @@ -1794,7 +1790,7 @@ TEST(ClientTest, RequestInitWithFingerprint) // Network and Headers Fingerprint inputs msg.data.add( - "server.request.headers.no_cookies", parameter::string(""sv)); + "server.request.headers.no_cookies_fp", parameter::string(""sv)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); @@ -1861,11 +1857,7 @@ TEST(ClientTest, RequestExecWithFingerprint) client c(smanager, std::unique_ptr(broker)); - network::client_init::request msg = get_default_client_init_msg(); - msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); - msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; - - send_client_init(broker, c, std::move(msg)); + set_extension_configuration_to(broker, c, EXTENSION_CONFIGURATION_ENABLED); request_init(broker, c); // Request Exec @@ -1883,7 +1875,7 @@ TEST(ClientTest, RequestExecWithFingerprint) // Network and Headers Fingerprint inputs msg.data.add( - "server.request.headers.no_cookies", parameter::string(""sv)); + "server.request.headers.no_cookies_fp", parameter::string(""sv)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); @@ -1949,11 +1941,7 @@ TEST(ClientTest, RequestShutdownWithFingerprint) client c(smanager, std::unique_ptr(broker)); - network::client_init::request msg = get_default_client_init_msg(); - msg.engine_settings.rules_file = create_sample_rules_ok_with_fingerprint(); - msg.enabled_configuration = EXTENSION_CONFIGURATION_ENABLED; - - send_client_init(broker, c, std::move(msg)); + set_extension_configuration_to(broker, c, EXTENSION_CONFIGURATION_ENABLED); request_init(broker, c); // Request Shutdown @@ -1972,7 +1960,7 @@ TEST(ClientTest, RequestShutdownWithFingerprint) // Network and Headers Fingerprint inputs msg.data.add( - "server.request.headers.no_cookies", parameter::string(""sv)); + "server.request.headers.no_cookies_fp", parameter::string(""sv)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); diff --git a/appsec/tests/helper/common.hpp b/appsec/tests/helper/common.hpp index 95e919633d..0a27bc7269 100644 --- a/appsec/tests/helper/common.hpp +++ b/appsec/tests/helper/common.hpp @@ -32,5 +32,4 @@ using namespace std::literals; using namespace std::chrono_literals; std::string create_sample_rules_ok(); -std::string create_sample_rules_ok_with_fingerprint(); std::string create_sample_rules_invalid(); diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 1176d3d489..96571ecae5 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -141,211 +141,6 @@ std::string create_sample_rules_ok() ] } ], - "processors": [ - { - "id": "processor-001", - "generator": "extract_schema", - "conditions": [ - { - "operator": "equals", - "parameters": { - "inputs": [ - { - "address": "waf.context.processor", - "key_path": [ - "extract-schema" - ] - } - ], - "type": "boolean", - "value": true - } - } - ], - "parameters": { - "mappings": [ - { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "output": "_dd.appsec.s.req.headers.no_cookies" - }, - { - "inputs": [ - { - "address": "server.request.body" - } - ], - "output": "_dd.appsec.s.req.body" - } - ], - "scanners": [ - { - "tags": { - "category": "pii" - } - } - ] - }, - "evaluate": false, - "output": true - } - ], - "scanners": [], - "actions": [ - { - "id": "redirect", - "type": "redirect_request", - "parameters": { - "location": "https://localhost" - } - } - ] -})"; - - char tmpl[] = "/tmp/test_ddappsec_XXXXXX"; - int fd = mkstemp(tmpl); - std::FILE *tmpf = fdopen(fd, "wb+"); - std::fwrite(data, sizeof(data) - 1, 1, tmpf); - std::fclose(tmpf); - - return tmpl; -} - -std::string create_sample_rules_ok_with_fingerprint() -{ - const static char data[] = - R"({ - "version": "2.1", - "metadata": { - "rules_version": "1.2.3" - }, - "rules": [ - { - "id": "blk-001-001", - "name": "BlockIPAddresses", - "tags": { - "type": "block_ip", - "category": "security_response" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "http.client_ip" - } - ], - "list": [ - "192.168.1.1" - ] - }, - "operator": "ip_match" - } - ], - "transformers": [], - "on_match": [ - "block" - ] - }, - { - "id": "blk-001-002", - "name": "BlockIPAddresseswithallactions", - "tags": { - "type": "block_ip", - "category": "security_response" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "http.client_ip" - } - ], - "list": [ - "192.168.1.2" - ] - }, - "operator": "ip_match" - } - ], - "transformers": [], - "on_match": [ - "block", - "redirect", - "stack_trace", - "extract_schema" - ] - }, - { - "id": "crs-913-110", - "name": "FoundrequestheaderassociatedwithAcunetixsecurityscanner", - "tags": { - "type": "security_scanner", - "crs_id": "913110", - "category": "attack_attempt" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "list": [ - "acunetix-product" - ] - }, - "operator": "phrase_match" - } - ], - "transformers": [ - "lowercase" - ] - }, - { - "id": "req_shutdown_rule", - "name": "Rulematchonresponsecode", - "tags": { - "type": "req_shutdown_type", - "crs_id": "none", - "category": "attack_attempt" - }, - "conditions": [ - { - "parameters": { - "inputs": [ - { - "address": "server.request.headers.no_cookies" - } - ], - "list": [ - "Arachni" - ] - }, - "operator": "phrase_match" - }, - { - "parameters": { - "inputs": [ - { - "address": "server.response.code" - } - ], - "regex": 1991, - "options": { - "case_sensitive": "false" - } - }, - "operator": "match_regex" - } - ] - } - ], "processors": [ { "id": "processor-001", @@ -474,7 +269,7 @@ std::string create_sample_rules_ok_with_fingerprint() { "headers": [ { - "address": "server.request.headers.no_cookies" + "address": "server.request.headers.no_cookies_fp" } ], "output": "_dd.appsec.fp.http.header" @@ -510,7 +305,7 @@ std::string create_sample_rules_ok_with_fingerprint() { "headers": [ { - "address": "server.request.headers.no_cookies" + "address": "server.request.headers.no_cookies_fp" } ], "output": "_dd.appsec.fp.http.network" From fcd4b25b1963f0d2d0ed090aa1c99c639f353a73 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Wed, 20 Nov 2024 18:40:01 +0100 Subject: [PATCH 13/16] fix(helper): fix processing on fingerprint derivatives Signed-off-by: Alexandre Rulleau --- appsec/src/helper/subscriber/waf.cpp | 10 +++++++--- .../datadog/appsec/php/integration/CommonTests.groovy | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/appsec/src/helper/subscriber/waf.cpp b/appsec/src/helper/subscriber/waf.cpp index f258ea548c..8ef4bb2949 100644 --- a/appsec/src/helper/subscriber/waf.cpp +++ b/appsec/src/helper/subscriber/waf.cpp @@ -235,8 +235,12 @@ void instance::listener::call(dds::parameter_view &data, event &event) const parameter_view derivatives{res.derivatives}; for (const auto &derivative : derivatives) { - derivatives_.emplace( - derivative.key(), std::move(parameter_to_json(derivative))); + if (derivative.key().starts_with("_dd.appsec.s.")) { + derivatives_.emplace( + derivative.key(), std::move(parameter_to_json(derivative))); + } else { + derivatives_.emplace(derivative.key(), std::move(derivative)); + } } switch (code) { @@ -268,7 +272,7 @@ void instance::listener::get_meta_and_metrics( for (const auto &[key, value] : derivatives_) { std::string derivative = value; if (value.length() > max_plain_schema_allowed && - key.starts_with("_dd.appsec.s")) { + key.starts_with("_dd.appsec.s.")) { auto encoded = compress(derivative); if (encoded) { diff --git a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy index a7562bc190..2e6f52bebf 100644 --- a/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy +++ b/appsec/tests/integration/src/test/groovy/com/datadog/appsec/php/integration/CommonTests.groovy @@ -246,10 +246,10 @@ trait CommonTests { } Span span = trace.first() - assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^"http-get(-[a-zA-Z0-9]*){3}"$/ - assert span.meta."_dd.appsec.fp.http.header" ==~ /^"hdr(-[0-9]*-[a-zA-Z0-9]*){2}"$/ - assert span.meta."_dd.appsec.fp.http.network" ==~ /^"net-[0-9]*-[a-zA-Z0-9]*"$/ - assert span.meta."_dd.appsec.fp.session" ==~ /^"ssn(-[a-zA-Z0-9]*){4}"$/ + assert span.meta."_dd.appsec.fp.http.endpoint" ==~ /^http-get(-[a-zA-Z0-9]*){3}$/ + assert span.meta."_dd.appsec.fp.http.header" ==~ /^hdr(-[0-9]*-[a-zA-Z0-9]*){2}$/ + assert span.meta."_dd.appsec.fp.http.network" ==~ /^net-[0-9]*-[a-zA-Z0-9]*$/ + assert span.meta."_dd.appsec.fp.session" ==~ /^ssn(-[a-zA-Z0-9]*){4}$/ } @Test From 54ead726459c102ff785b48cd02ebecf6104b6cd Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Fri, 22 Nov 2024 15:20:37 +0100 Subject: [PATCH 14/16] fix(tests: helper): remove alternative configuration and fix parameter type Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 94 ++++++++++++++++++----------- appsec/tests/helper/main.cpp | 4 +- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index 2709806930..d151635c19 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -5,6 +5,7 @@ // (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc. #include "common.hpp" #include "parameter.hpp" +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include namespace dds { @@ -491,8 +493,11 @@ TEST(ClientTest, RequestInit) { network::request_init::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("acunetix-product"sv)); + + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -529,8 +534,11 @@ TEST(ClientTest, RequestInitLimiter) { network::request_init::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("acunetix-product"sv)); + + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -785,9 +793,12 @@ TEST(ClientTest, RequestShutdown) { network::request_shutdown::request msg; msg.data = parameter::map(); + + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("Arachni"sv)); + msg.data.add("server.response.code", parameter::string("1991"sv)); - msg.data.add("server.request.headers.no_cookies", - parameter::string("Arachni"sv)); + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -806,7 +817,7 @@ TEST(ClientTest, RequestShutdown) EXPECT_EQ(msg_res->metrics.size(), 1); EXPECT_GT(msg_res->metrics[tag::waf_duration], 0.0); - EXPECT_EQ(msg_res->meta.size(), 1); + EXPECT_EQ(msg_res->meta.size(), 3); EXPECT_STREQ( msg_res->meta[std::string(tag::event_rules_version)].c_str(), "1.2.3"); @@ -1789,8 +1800,10 @@ TEST(ClientTest, RequestInitWithFingerprint) msg.data.add("server.request.query", std::move(query)); // Network and Headers Fingerprint inputs - msg.data.add( - "server.request.headers.no_cookies_fp", parameter::string(""sv)); + auto headers = parameter::map(); + headers.add("X-Forwarded-For", parameter::string("192.168.72.0"sv)); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + msg.data.add("server.request.headers.no_cookies", std::move(headers)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); @@ -1834,19 +1847,19 @@ TEST(ClientTest, RequestInitWithFingerprint) EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + std::regex("http-get(-[A-Za-z0-9]*){3}"))); EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); + std::regex("ssn(-[a-zA-Z0-9]*){4}"))); } } @@ -1874,8 +1887,10 @@ TEST(ClientTest, RequestExecWithFingerprint) msg.data.add("server.request.query", std::move(query)); // Network and Headers Fingerprint inputs - msg.data.add( - "server.request.headers.no_cookies_fp", parameter::string(""sv)); + auto headers = parameter::map(); + headers.add("X-Forwarded-For", parameter::string("192.168.72.0"sv)); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + msg.data.add("server.request.headers.no_cookies", std::move(headers)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); @@ -1918,19 +1933,19 @@ TEST(ClientTest, RequestExecWithFingerprint) EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + std::regex("http-get(-[A-Za-z0-9]*){3}"))); EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); + std::regex("ssn(-[a-zA-Z0-9]*){4}"))); } } @@ -1959,8 +1974,10 @@ TEST(ClientTest, RequestShutdownWithFingerprint) msg.data.add("server.request.query", std::move(query)); // Network and Headers Fingerprint inputs - msg.data.add( - "server.request.headers.no_cookies_fp", parameter::string(""sv)); + auto headers = parameter::map(); + headers.add("X-Forwarded-For", parameter::string("192.168.72.0"sv)); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + msg.data.add("server.request.headers.no_cookies", std::move(headers)); // Session Fingerprint inputs msg.data.add("server.request.cookies", parameter::string("asdfds"sv)); @@ -1983,19 +2000,19 @@ TEST(ClientTest, RequestShutdownWithFingerprint) EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("\"http-get(-[A-Za-z0-9]*){3}\""))); + std::regex("http-get(-[A-Za-z0-9]*){3}"))); EXPECT_TRUE(std::regex_match( msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("\"net-[0-9]*-[a-zA-Z0-9]*\""))); + std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("\"hdr(-[0-9]*-[a-zA-Z0-9]*){2}\""))); + std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); EXPECT_TRUE( std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("\"ssn(-[a-zA-Z0-9]*){4}\""))); + std::regex("ssn(-[a-zA-Z0-9]*){4}"))); } } @@ -2341,8 +2358,10 @@ TEST(ClientTest, RequestShutdownLimiter) { network::request_init::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("Arachni"sv)); + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("Arachni"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -2446,8 +2465,10 @@ TEST(ClientTest, RequestExecLimiter) { network::request_init::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("Arachni"sv)); + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("Arachni"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -2551,8 +2572,11 @@ TEST(ClientTest, SchemasAreAddedOnRequestShutdownWhenEnabled) { network::request_shutdown::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("acunetix-product"sv)); + + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); network::request req(std::move(msg)); @@ -2570,7 +2594,7 @@ TEST(ClientTest, SchemasAreAddedOnRequestShutdownWhenEnabled) EXPECT_GT(count_schemas(msg_res->meta), 0); EXPECT_STREQ( msg_res->meta["_dd.appsec.s.req.headers.no_cookies"].c_str(), - "[8]"); + "[{\"user-agent\":[8]}]"); } } @@ -2629,8 +2653,10 @@ TEST(ClientTest, SchemasOverTheLimitAreCompressed) { network::request_shutdown::request msg; msg.data = parameter::map(); - msg.data.add("server.request.headers.no_cookies", - parameter::string("acunetix-product"sv)); + auto headers = parameter::map(); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + + msg.data.add("server.request.headers.no_cookies", std::move(headers)); auto body = parameter::map(); auto expected_schemas = parameter::map(); diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 96571ecae5..3bc5ba5eb6 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -269,7 +269,7 @@ std::string create_sample_rules_ok() { "headers": [ { - "address": "server.request.headers.no_cookies_fp" + "address": "server.request.headers.no_cookies" } ], "output": "_dd.appsec.fp.http.header" @@ -305,7 +305,7 @@ std::string create_sample_rules_ok() { "headers": [ { - "address": "server.request.headers.no_cookies_fp" + "address": "server.request.headers.no_cookies" } ], "output": "_dd.appsec.fp.http.network" From 9675504357388a5577ad661a8b8f9222c6d288a3 Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Fri, 22 Nov 2024 15:21:08 +0100 Subject: [PATCH 15/16] fix(tests: helper): add tests to ensure fingerprint are stored and retrieved through the correct API Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/waf_test.cpp | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/appsec/tests/helper/waf_test.cpp b/appsec/tests/helper/waf_test.cpp index a78f5476a7..102991dbd8 100644 --- a/appsec/tests/helper/waf_test.cpp +++ b/appsec/tests/helper/waf_test.cpp @@ -6,7 +6,9 @@ #include "common.hpp" #include "engine_settings.hpp" #include "json_helper.hpp" +#include #include +#include #include #include #include @@ -336,6 +338,85 @@ TEST(WafTest, SchemasAreAdded) EXPECT_STREQ(meta["_dd.appsec.s.arg2"].c_str(), "[8]"); } +TEST(WafTest, FingerprintAreNotAdded) +{ + std::map meta; + std::map metrics; + + engine_settings settings; + settings.rules_file = create_sample_rules_ok(); + auto ruleset = engine_ruleset::from_path(settings.rules_file); + + std::shared_ptr wi{ + waf::instance::from_settings(settings, ruleset, meta, metrics)}; + auto ctx = wi->get_listener(); + + auto p = parameter::map(); + + parameter_view pv(p); + dds::event e; + ctx->call(pv, e); + + ctx->get_meta_and_metrics(meta, metrics); + EXPECT_FALSE(meta.empty()); + EXPECT_STREQ(meta["_dd.appsec.fp.http.endpoint"].c_str(), ""); + EXPECT_STREQ(meta["_dd.appsec.fp.http.network"].c_str(), ""); + EXPECT_STREQ(meta["_dd.appsec.fp.http.header"].c_str(), ""); + EXPECT_STREQ(meta["_dd.appsec.fp.fp.session"].c_str(), ""); +} + +TEST(WafTest, FingerprintAreAdded) +{ + std::map meta; + std::map metrics; + + engine_settings settings; + settings.rules_file = create_sample_rules_ok(); + auto ruleset = engine_ruleset::from_path(settings.rules_file); + + std::shared_ptr wi{ + waf::instance::from_settings(settings, ruleset, meta, metrics)}; + auto ctx = wi->get_listener(); + + auto p = parameter::map(); + + // Endpoint Fingerprint inputs + auto query = parameter::map(); + query.add("query", parameter::string("asdfds"sv)); + p.add("server.request.uri.raw", parameter::string("asdfds"sv)); + p.add("server.request.method", parameter::string("GET"sv)); + p.add("server.request.query", std::move(query)); + + // Network and Headers Fingerprint inputs + auto headers = parameter::map(); + headers.add("X-Forwarded-For", parameter::string("192.168.72.0"sv)); + headers.add("user-agent", parameter::string("acunetix-product"sv)); + p.add("server.request.headers.no_cookies", std::move(headers)); + + // Session Fingerprint inputs + p.add("server.request.cookies", parameter::string("asdfds"sv)); + p.add("usr.session_id", parameter::string("asdfds"sv)); + p.add("usr.id", parameter::string("asdfds"sv)); + + parameter_view pv(p); + dds::event e; + ctx->call(pv, e); + + ctx->get_meta_and_metrics(meta, metrics); + EXPECT_FALSE(meta.empty()); + EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.endpoint"].c_str(), + std::regex("http-get(-[A-Za-z0-9]*){3}"))); + + EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.network"].c_str(), + std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); + + EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.header"].c_str(), + std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); + + EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.session"].c_str(), + std::regex("ssn(-[a-zA-Z0-9]*){4}"))); +} + TEST(WafTest, ActionsAreSentAndParsed) { std::map meta; From d9cfc574cd1e97d14c93b889a76eecc60515373f Mon Sep 17 00:00:00 2001 From: Alexandre Rulleau Date: Fri, 22 Nov 2024 15:26:23 +0100 Subject: [PATCH 16/16] chore(tests: helper): change regex assert Signed-off-by: Alexandre Rulleau --- appsec/tests/helper/client_test.cpp | 69 +++++++++++------------------ appsec/tests/helper/common.hpp | 1 + appsec/tests/helper/main.cpp | 11 +++-- appsec/tests/helper/waf_test.cpp | 16 +++---- 4 files changed, 41 insertions(+), 56 deletions(-) diff --git a/appsec/tests/helper/client_test.cpp b/appsec/tests/helper/client_test.cpp index d151635c19..ec83974b27 100644 --- a/appsec/tests/helper/client_test.cpp +++ b/appsec/tests/helper/client_test.cpp @@ -1790,7 +1790,6 @@ TEST(ClientTest, RequestInitWithFingerprint) network::request_init::request msg; msg.data = parameter::map(); - msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); // Endpoint Fingerprint inputs auto query = parameter::map(); @@ -1822,7 +1821,7 @@ TEST(ClientTest, RequestInitWithFingerprint) EXPECT_TRUE(c.run_request()); auto msg_res = dynamic_cast(res.get()); - EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "record"); } // Request Shutdown @@ -1845,21 +1844,17 @@ TEST(ClientTest, RequestInitWithFingerprint) EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "ok"); EXPECT_EQ(msg_res->triggers.size(), 0); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("http-get(-[A-Za-z0-9]*){3}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + MatchesRegex("http-get(-[A-Za-z0-9]*){3}")); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + MatchesRegex("net-[0-9]*-[a-zA-Z0-9]*")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + MatchesRegex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("ssn(-[a-zA-Z0-9]*){4}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.session"].c_str(), + MatchesRegex("ssn(-[a-zA-Z0-9]*){4}")); } } @@ -1877,7 +1872,6 @@ TEST(ClientTest, RequestExecWithFingerprint) { network::request_exec::request msg; msg.data = parameter::map(); - msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); // Endpoint Fingerprint inputs auto query = parameter::map(); @@ -1909,7 +1903,7 @@ TEST(ClientTest, RequestExecWithFingerprint) EXPECT_TRUE(c.run_request()); auto msg_res = dynamic_cast(res.get()); - EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "record"); } // Request Shutdown @@ -1931,21 +1925,17 @@ TEST(ClientTest, RequestExecWithFingerprint) dynamic_cast(res.get()); EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "ok"); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("http-get(-[A-Za-z0-9]*){3}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + MatchesRegex("http-get(-[A-Za-z0-9]*){3}")); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + MatchesRegex("net-[0-9]*-[a-zA-Z0-9]*")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + MatchesRegex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("ssn(-[a-zA-Z0-9]*){4}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.session"].c_str(), + MatchesRegex("ssn(-[a-zA-Z0-9]*){4}")); } } @@ -1964,7 +1954,6 @@ TEST(ClientTest, RequestShutdownWithFingerprint) network::request_shutdown::request msg; msg.data = parameter::map(); - msg.data.add("http.client_ip", parameter::string("192.168.1.1"sv)); // Endpoint Fingerprint inputs auto query = parameter::map(); @@ -1996,23 +1985,19 @@ TEST(ClientTest, RequestShutdownWithFingerprint) EXPECT_TRUE(c.run_request()); auto msg_res = dynamic_cast(res.get()); - EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "block"); + EXPECT_STREQ(msg_res->actions[0].verdict.c_str(), "record"); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("http-get(-[A-Za-z0-9]*){3}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.endpoint"].c_str(), + MatchesRegex("http-get(-[A-Za-z0-9]*){3}")); - EXPECT_TRUE(std::regex_match( - msg_res->meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.network"].c_str(), + MatchesRegex("net-[0-9]*-[a-zA-Z0-9]*")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.http.header"].c_str(), + MatchesRegex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}")); - EXPECT_TRUE( - std::regex_match(msg_res->meta["_dd.appsec.fp.session"].c_str(), - std::regex("ssn(-[a-zA-Z0-9]*){4}"))); + EXPECT_THAT(msg_res->meta["_dd.appsec.fp.session"].c_str(), + MatchesRegex("ssn(-[a-zA-Z0-9]*){4}")); } } diff --git a/appsec/tests/helper/common.hpp b/appsec/tests/helper/common.hpp index 0a27bc7269..6fbde24eab 100644 --- a/appsec/tests/helper/common.hpp +++ b/appsec/tests/helper/common.hpp @@ -21,6 +21,7 @@ using ::testing::ByRef; using ::testing::DoAll; using ::testing::ElementsAre; using ::testing::Invoke; +using ::testing::MatchesRegex; using ::testing::Return; using ::testing::SaveArg; using ::testing::SetArgPointee; diff --git a/appsec/tests/helper/main.cpp b/appsec/tests/helper/main.cpp index 3bc5ba5eb6..1129f6b782 100644 --- a/appsec/tests/helper/main.cpp +++ b/appsec/tests/helper/main.cpp @@ -11,8 +11,7 @@ std::string create_sample_rules_ok() { - const static char data[] = - R"({ + const static char data[] = R"({ "version": "2.1", "metadata": { "rules_version": "1.2.3" @@ -20,7 +19,7 @@ std::string create_sample_rules_ok() "rules": [ { "id": "blk-001-001", - "name": "BlockIPAddresses", + "name": "Block IP Addresses", "tags": { "type": "block_ip", "category": "security_response" @@ -47,7 +46,7 @@ std::string create_sample_rules_ok() }, { "id": "blk-001-002", - "name": "BlockIPAddresseswithallactions", + "name": "Block IP Addresses with all actions", "tags": { "type": "block_ip", "category": "security_response" @@ -77,7 +76,7 @@ std::string create_sample_rules_ok() }, { "id": "crs-913-110", - "name": "FoundrequestheaderassociatedwithAcunetixsecurityscanner", + "name": "Found request header associated with Acunetix security scanner", "tags": { "type": "security_scanner", "crs_id": "913110", @@ -104,7 +103,7 @@ std::string create_sample_rules_ok() }, { "id": "req_shutdown_rule", - "name": "Rulematchonresponsecode", + "name": "Rule match on response code", "tags": { "type": "req_shutdown_type", "crs_id": "none", diff --git a/appsec/tests/helper/waf_test.cpp b/appsec/tests/helper/waf_test.cpp index 102991dbd8..8be992ecf0 100644 --- a/appsec/tests/helper/waf_test.cpp +++ b/appsec/tests/helper/waf_test.cpp @@ -404,17 +404,17 @@ TEST(WafTest, FingerprintAreAdded) ctx->get_meta_and_metrics(meta, metrics); EXPECT_FALSE(meta.empty()); - EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.endpoint"].c_str(), - std::regex("http-get(-[A-Za-z0-9]*){3}"))); + EXPECT_THAT(meta["_dd.appsec.fp.http.endpoint"].c_str(), + MatchesRegex("http-get(-[A-Za-z0-9]*){3}")); - EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.network"].c_str(), - std::regex("net-[0-9]*-[a-zA-Z0-9]*"))); + EXPECT_THAT(meta["_dd.appsec.fp.http.network"].c_str(), + MatchesRegex("net-[0-9]*-[a-zA-Z0-9]*")); - EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.http.header"].c_str(), - std::regex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}"))); + EXPECT_THAT(meta["_dd.appsec.fp.http.header"].c_str(), + MatchesRegex("hdr(-[0-9]*-[a-zA-Z0-9]*){2}")); - EXPECT_TRUE(std::regex_match(meta["_dd.appsec.fp.session"].c_str(), - std::regex("ssn(-[a-zA-Z0-9]*){4}"))); + EXPECT_THAT(meta["_dd.appsec.fp.session"].c_str(), + MatchesRegex("ssn(-[a-zA-Z0-9]*){4}")); } TEST(WafTest, ActionsAreSentAndParsed)