Skip to content

Create metric: appsec.waf.error #8381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ public class AppSecRequestContext implements DataBundle, Closeable {
private volatile int raspInternalErrors;
private volatile int raspInvalidObjectErrors;
private volatile int raspInvalidArgumentErrors;
private volatile int wafInternalErrors;
private volatile int wafInvalidObjectErrors;
private volatile int wafInvalidArgumentErrors;

// keep a reference to the last published usr.id
private volatile String userId;
Expand Down Expand Up @@ -157,6 +160,17 @@ public class AppSecRequestContext implements DataBundle, Closeable {
AtomicIntegerFieldUpdater.newUpdater(
AppSecRequestContext.class, "raspInvalidArgumentErrors");

private static final AtomicIntegerFieldUpdater<AppSecRequestContext> WAF_INTERNAL_ERRORS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafInternalErrors");
private static final AtomicIntegerFieldUpdater<AppSecRequestContext>
WAF_INVALID_OBJECT_ERRORS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(
AppSecRequestContext.class, "wafInvalidObjectErrors");
private static final AtomicIntegerFieldUpdater<AppSecRequestContext>
WAF_INVALID_ARGUMENT_ERRORS_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(
AppSecRequestContext.class, "wafInvalidArgumentErrors");

// to be called by the Event Dispatcher
public void addAll(DataBundle newData) {
for (Map.Entry<Address<?>, Object> entry : newData) {
Expand Down Expand Up @@ -222,6 +236,22 @@ public void increaseRaspErrorCode(int code) {
}
}

public void increaseWafErrorCode(int code) {
switch (code) {
case DD_WAF_RUN_INTERNAL_ERROR:
WAF_INTERNAL_ERRORS_UPDATER.incrementAndGet(this);
break;
case DD_WAF_RUN_INVALID_OBJECT_ERROR:
WAF_INVALID_OBJECT_ERRORS_UPDATER.incrementAndGet(this);
break;
case DD_WAF_RUN_INVALID_ARGUMENT_ERROR:
WAF_INVALID_ARGUMENT_ERRORS_UPDATER.incrementAndGet(this);
break;
default:
break;
}
}

public int getWafTimeouts() {
return wafTimeouts;
}
Expand All @@ -243,6 +273,19 @@ public int getRaspError(int code) {
}
}

public int getWafError(int code) {
switch (code) {
case DD_WAF_RUN_INTERNAL_ERROR:
return wafInternalErrors;
case DD_WAF_RUN_INVALID_OBJECT_ERROR:
return wafInvalidObjectErrors;
case DD_WAF_RUN_INVALID_ARGUMENT_ERROR:
return wafInvalidArgumentErrors;
default:
return 0;
}
}

public Additive getOrCreateAdditive(PowerwafContext ctx, boolean createMetrics, boolean isRasp) {

if (createMetrics) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,8 @@ public void onDataAvailable(
reqCtx.increaseRaspErrorCode(e.code);
WafMetricCollector.get().raspErrorCode(gwCtx.raspRuleType, e.code);
} else {
// TODO APPSEC-56703
// reqCtx.increaseWafErrorCode(e.code);
// WafMetricCollector.get().wafErrorCode(e.code);
reqCtx.increaseWafErrorCode(e.code);
WafMetricCollector.get().wafErrorCode(gwCtx.raspRuleType, e.code);
}
return;
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,17 @@ class AppSecRequestContextSpecification extends DDSpecification {
ctx.getRaspError(AppSecRequestContext.DD_WAF_RUN_INVALID_ARGUMENT_ERROR) == 0
ctx.getRaspError(0) == 0
}

def "test increase and get WafErrors"() {
when:
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR)
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR)
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INVALID_OBJECT_ERROR)

then:
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR) == 2
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INVALID_OBJECT_ERROR) == 1
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INVALID_ARGUMENT_ERROR) == 0
ctx.getWafError(0) == 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ private WafMetricCollector() {
new AtomicLongArray(RuleType.getNumValues());
private static final ConcurrentMap<Integer, AtomicLongArray> raspErrorCodeCounter =
new ConcurrentSkipListMap<>();
private static final ConcurrentMap<Integer, AtomicLongArray> wafErrorCodeCounter =
new ConcurrentSkipListMap<>();

static {
for (int i = -1 * ABSTRACT_POWERWAF_EXCEPTION_NUMBER; i < 0; i++) {
raspErrorCodeCounter.put(i, new AtomicLongArray(RuleType.getNumValues()));
wafErrorCodeCounter.put(i, new AtomicLongArray(RuleType.getNumValues()));
}
}

Expand Down Expand Up @@ -121,6 +124,10 @@ public void raspErrorCode(final RuleType ruleType, final int ddwafRunErrorCode)
raspErrorCodeCounter.get(ddwafRunErrorCode).incrementAndGet(ruleType.ordinal());
}

public void wafErrorCode(final RuleType ruleType, final int ddwafRunErrorCode) {
wafErrorCodeCounter.get(ddwafRunErrorCode).incrementAndGet(ruleType.ordinal());
}

public void missingUserLogin(final LoginFramework framework, final LoginEvent eventType) {
missingUserLoginQueue.incrementAndGet(
framework.ordinal() * LoginEvent.getNumValues() + eventType.ordinal());
Expand Down Expand Up @@ -242,6 +249,10 @@ public void prepareMetrics() {
new RaspError(counter, ruleType, WafMetricCollector.wafVersion, i))) {
return;
}
if (!rawMetricsQueue.offer(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a comment at the beginning of the code block what could lead to a misunderstanding

RASP rule type for each possible error code

Could you change it?

new WafError(counter, ruleType, WafMetricCollector.wafVersion, i))) {
return;
}
}
}
}
Expand Down Expand Up @@ -422,6 +433,31 @@ public RaspError(
}
}

public static class WafError extends WafMetric {
public WafError(
final long counter,
final RuleType ruleType,
final String wafVersion,
final Integer ddwafRunError) {
super(
"waf.error",
counter,
ruleType.variant != null
? new String[] {
"rule_type:" + ruleType.type,
"rule_variant:" + ruleType.variant,
"waf_version:" + wafVersion,
"event_rules_version:" + rulesVersion,
"waf_error:" + ddwafRunError
}
: new String[] {
"rule_type:" + ruleType.type,
"waf_version:" + wafVersion,
"waf_error:" + ddwafRunError
});
}
}

public static class AtomicRequestCounter {

private final AtomicLong atomicLong = new AtomicLong();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class WafMetricCollectorTest extends DDSpecification {
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
WafMetricCollector.get().raspTimeout(RuleType.SQL_INJECTION)
WafMetricCollector.get().raspErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().wafErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().raspErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
WafMetricCollector.get().wafErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)

WafMetricCollector.get().prepareMetrics()

Expand Down Expand Up @@ -150,7 +152,20 @@ class WafMetricCollectorTest extends DDSpecification {
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
].toSet()

def raspInvalidObjectCode = (WafMetricCollector.RaspError)metrics[11]
def wafInvalidCode = (WafMetricCollector.WafError)metrics[11]
wafInvalidCode.type == 'count'
wafInvalidCode.value == 1
wafInvalidCode.namespace == 'appsec'
wafInvalidCode.metricName == 'waf.error'
wafInvalidCode.tags.toSet() == [
'waf_version:waf_ver1',
'rule_type:command_injection',
'rule_variant:shell',
'event_rules_version:rules.3',
'waf_error:' +DD_WAF_RUN_INTERNAL_ERROR
].toSet()

def raspInvalidObjectCode = (WafMetricCollector.RaspError)metrics[12]
raspInvalidObjectCode.type == 'count'
raspInvalidObjectCode.value == 1
raspInvalidObjectCode.namespace == 'appsec'
Expand All @@ -161,6 +176,17 @@ class WafMetricCollectorTest extends DDSpecification {
'waf_error:' + DD_WAF_RUN_INVALID_OBJECT_ERROR
]
.toSet()

def wafInvalidObjectCode = (WafMetricCollector.WafError)metrics[13]
wafInvalidObjectCode.type == 'count'
wafInvalidObjectCode.value == 1
wafInvalidObjectCode.namespace == 'appsec'
wafInvalidObjectCode.metricName == 'waf.error'
wafInvalidObjectCode.tags.toSet() == [
'rule_type:sql_injection',
'waf_version:waf_ver1',
'waf_error:'+DD_WAF_RUN_INVALID_OBJECT_ERROR
].toSet()
}

def "overflowing WafMetricCollector does not crash"() {
Expand Down Expand Up @@ -335,6 +361,7 @@ class WafMetricCollectorTest extends DDSpecification {
WafMetricCollector.get().raspRuleEval(ruleType)
WafMetricCollector.get().raspTimeout(ruleType)
WafMetricCollector.get().raspErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().wafErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
WafMetricCollector.get().prepareMetrics()

then:
Expand Down Expand Up @@ -389,6 +416,19 @@ class WafMetricCollectorTest extends DDSpecification {
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
].toSet()

def wafInvalidCode = (WafMetricCollector.WafError)metrics[5]
wafInvalidCode.type == 'count'
wafInvalidCode.value == 1
wafInvalidCode.namespace == 'appsec'
wafInvalidCode.metricName == 'waf.error'
wafInvalidCode.tags.toSet() == [
'waf_version:waf_ver1',
'rule_type:command_injection',
'rule_variant:' + ruleType.variant,
'event_rules_version:rules.1',
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
].toSet()

where:
ruleType << [RuleType.COMMAND_INJECTION, RuleType.SHELL_INJECTION]
}
Expand Down
Loading