diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java index 860f3119ae4..905024180fc 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java @@ -168,6 +168,7 @@ public class AppSecRequestContext implements DataBundle, Closeable { private volatile boolean wafTruncated; private volatile boolean wafRequestBlockFailure; private volatile boolean wafRateLimited; + private volatile boolean wafRequestExcluded; private volatile int wafTimeouts; private volatile int raspTimeouts; @@ -287,6 +288,15 @@ public boolean isWafRateLimited() { return wafRateLimited; } + // placeholder: libddwaf does not yet expose exclusion filter results + public void setWafRequestExcluded() { + wafRequestExcluded = true; + } + + public boolean isWafRequestExcluded() { + return wafRequestExcluded; + } + public void increaseWafTimeouts() { WAF_TIMEOUTS_UPDATER.incrementAndGet(this); } diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 22b1b09d1db..a7b04c017e2 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -1057,7 +1057,8 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { ctx.getWafTimeouts() > 0, // wafTimeout, ctx.isWafRequestBlockFailure(), // blockFailure, ctx.isWafRateLimited(), // rateLimited, - ctx.isWafTruncated() // inputTruncated + ctx.isWafTruncated(), // inputTruncated + ctx.isWafRequestExcluded() // requestExcluded ); } diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy index 36a8ebc861d..7f519c3d76e 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy @@ -210,7 +210,7 @@ class GatewayBridgeSpecification extends DDSpecification { 1 * mockAppSecCtx.isWafRequestBlockFailure() 1 * mockAppSecCtx.isWafRateLimited() 1 * mockAppSecCtx.isWafTruncated() - 1 * wafMetricCollector.wafRequest(_, _, _, _, _, _, _) // call waf request metric + 1 * wafMetricCollector.wafRequest(_, _, _, _, _, _, _, _) // call waf request metric flow.result == null flow.action == Flow.Action.Noop.INSTANCE } diff --git a/internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java b/internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java index 96797ebae6f..d4792a5bd69 100644 --- a/internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java +++ b/internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java @@ -33,7 +33,7 @@ private WafMetricCollector() { private static final BlockingQueue rawMetricsQueue = new ArrayBlockingQueue<>(RAW_QUEUE_SIZE); - private static final int WAF_REQUEST_COMBINATIONS = 128; // 2^7 + private static final int WAF_REQUEST_COMBINATIONS = 256; // 2^8 private final AtomicLongArray wafRequestCounter = new AtomicLongArray(WAF_REQUEST_COMBINATIONS); private static final AtomicLongArray wafInputTruncatedCounter = @@ -99,7 +99,8 @@ public void wafRequest( final boolean wafTimeout, final boolean blockFailure, final boolean rateLimited, - final boolean inputTruncated) { + final boolean inputTruncated, + final boolean requestExcluded) { int index = computeWafRequestIndex( ruleTriggered, @@ -108,7 +109,8 @@ public void wafRequest( wafTimeout, blockFailure, rateLimited, - inputTruncated); + inputTruncated, + requestExcluded); wafRequestCounter.incrementAndGet(index); } @@ -125,7 +127,8 @@ static int computeWafRequestIndex( boolean wafTimeout, boolean blockFailure, boolean rateLimited, - boolean inputTruncated) { + boolean inputTruncated, + boolean requestExcluded) { int index = 0; if (ruleTriggered) index |= 1; if (requestBlocked) index |= 1 << 1; @@ -134,6 +137,7 @@ static int computeWafRequestIndex( if (blockFailure) index |= 1 << 4; if (rateLimited) index |= 1 << 5; if (inputTruncated) index |= 1 << 6; + if (requestExcluded) index |= 1 << 7; return index; } @@ -233,6 +237,7 @@ public void prepareMetrics() { boolean blockFailure = (i & (1 << 4)) != 0; boolean rateLimited = (i & (1 << 5)) != 0; boolean inputTruncated = (i & (1 << 6)) != 0; + boolean requestExcluded = (i & (1 << 7)) != 0; if (!rawMetricsQueue.offer( new WafRequestsRawMetric( @@ -245,7 +250,8 @@ public void prepareMetrics() { wafTimeout, blockFailure, rateLimited, - inputTruncated))) { + inputTruncated, + requestExcluded))) { return; } } @@ -497,7 +503,8 @@ public WafRequestsRawMetric( final boolean wafTimeout, final boolean blockFailure, final boolean rateLimited, - final boolean inputTruncated) { + final boolean inputTruncated, + final boolean requestExcluded) { super( "waf.requests", counter, @@ -509,7 +516,8 @@ public WafRequestsRawMetric( "waf_timeout:" + wafTimeout, "block_failure:" + blockFailure, "rate_limited:" + rateLimited, - "input_truncated:" + inputTruncated); + "input_truncated:" + inputTruncated, + "request_excluded:" + (requestExcluded ? "full" : "none")); } } diff --git a/internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy index 5f5663d1e3b..a05887d6668 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy @@ -432,6 +432,7 @@ class WafMetricCollectorTest extends DDSpecification { void 'test waf request metrics'() { given: def collector = WafMetricCollector.get() + collector.wafInit('waf_ver1', 'rules.1', true) when: collector.wafRequest( @@ -441,7 +442,8 @@ class WafMetricCollectorTest extends DDSpecification { wafTimeout, blockFailure, rateLimited, - inputTruncated + inputTruncated, + requestExcluded ) then: @@ -449,10 +451,12 @@ class WafMetricCollectorTest extends DDSpecification { def metrics = collector.drain() def requestMetrics = metrics.findAll { it.metricName == 'waf.requests' } + requestMetrics.size() == 1 final metric = requestMetrics[0] metric.type == 'count' metric.metricName == 'waf.requests' metric.namespace == 'appsec' + metric.value == 1 metric.tags == [ "waf_version:waf_ver1", "event_rules_version:rules.1", @@ -462,11 +466,21 @@ class WafMetricCollectorTest extends DDSpecification { "waf_timeout:${wafTimeout}", "block_failure:${blockFailure}", "rate_limited:${rateLimited}", - "input_truncated:${inputTruncated}" + "input_truncated:${inputTruncated}", + "request_excluded:${requestExcluded ? 'full' : 'none'}" ] where: - [triggered, blocked, wafError, wafTimeout, blockFailure, rateLimited, inputTruncated] << allBooleanCombinations(7) + [ + triggered, + blocked, + wafError, + wafTimeout, + blockFailure, + rateLimited, + inputTruncated, + requestExcluded + ] << allBooleanCombinations(8) } void 'test waf input truncated metrics'() { diff --git a/telemetry/src/test/groovy/datadog/telemetry/metric/WafMetricPeriodicActionSpecification.groovy b/telemetry/src/test/groovy/datadog/telemetry/metric/WafMetricPeriodicActionSpecification.groovy index b14a10e431f..9486fc432aa 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/metric/WafMetricPeriodicActionSpecification.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/metric/WafMetricPeriodicActionSpecification.groovy @@ -43,16 +43,16 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { void 'push waf request metrics and push into the telemetry'() { when: WafMetricCollector.get().wafInit('0.0.0', 'rules_ver_1', true) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(true, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, true, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, true, false, false, false) - WafMetricCollector.get().wafRequest(false, false, true, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, true, false) - WafMetricCollector.get().wafRequest(false, false, false, false, true, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, true) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(true, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, true, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, true, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, true, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, true, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, true, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, true, false) WafMetricCollector.get().prepareMetrics() periodicAction.doIteration(telemetryService) @@ -75,6 +75,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -91,6 +92,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -107,6 +109,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -123,6 +126,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -139,6 +143,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -155,6 +160,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:true', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -171,6 +177,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:true', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -187,20 +194,21 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:true', + 'request_excluded:none', ] } ) 0 * _._ when: 'waf.updates happens' WafMetricCollector.get().wafUpdates('rules_ver_2', true) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(true, false, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, true, false, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, true, false, false, false) - WafMetricCollector.get().wafRequest(false, false, true, false, false, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, true, false) - WafMetricCollector.get().wafRequest(false, false, false, false, true, false, false) - WafMetricCollector.get().wafRequest(false, false, false, false, false, false, true) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(true, false, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, true, false, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, true, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, true, false, false, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, true, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, true, false, false, false) + WafMetricCollector.get().wafRequest(false, false, false, false, false, false, true, false) WafMetricCollector.get().prepareMetrics() periodicAction.doIteration(telemetryService) @@ -223,6 +231,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -239,6 +248,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -255,6 +265,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -271,6 +282,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -287,6 +299,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -303,6 +316,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:true', 'rate_limited:false', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -319,6 +333,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:true', 'input_truncated:false', + 'request_excluded:none', ] } ) 1 * telemetryService.addMetric( { Metric metric -> @@ -335,6 +350,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification { 'block_failure:false', 'rate_limited:false', 'input_truncated:true', + 'request_excluded:none', ] } ) 0 * _._