Skip to content

Commit

Permalink
Report span metrics for Exploit Prevention (#7273)
Browse files Browse the repository at this point in the history
* Report RASP span metrics

* Fixed test

* Separated waf and rasp metrics

* Fixed test
  • Loading branch information
ValentinZakharov committed Jul 8, 2024
1 parent 3daca96 commit 5809b1d
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ public void onDataAvailable(
ChangeableFlow flow,
AppSecRequestContext context,
DataBundle dataBundle,
boolean isTransient) {}
boolean isTransient,
boolean isRasp) {}

@Override
public Priority getPriority() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public BlockingDetails shouldBlockUser(@Nonnull String userId) {
}
SingletonDataBundle<String> db = new SingletonDataBundle<>(KnownAddresses.USER_ID, userId);
try {
flow = eventProducer.publishDataEvent(subInfo, reqCtx, db, true);
flow = eventProducer.publishDataEvent(subInfo, reqCtx, db, true, false);
break;
} catch (ExpiredSubscriberInfoException e) {
subInfo = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ void onDataAvailable(
ChangeableFlow flow,
AppSecRequestContext context,
DataBundle dataBundle,
boolean isTransient);
boolean isTransient,
boolean isRasp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ public Flow publishDataEvent(
DataSubscriberInfo subscribers,
AppSecRequestContext ctx,
DataBundle newData,
boolean isTransient)
boolean isTransient,
boolean isRasp)
throws ExpiredSubscriberInfoException {
if (!((DataSubscriberInfoImpl) subscribers).isEventDispatcher(this)) {
throw new ExpiredSubscriberInfoException();
Expand All @@ -144,7 +145,7 @@ public Flow publishDataEvent(
ChangeableFlow flow = new ChangeableFlow();
for (int idx : ((DataSubscriberInfoImpl) subscribers).listenerIndices) {
try {
dataListenersIdx.get(idx).onDataAvailable(flow, ctx, newData, isTransient);
dataListenersIdx.get(idx).onDataAvailable(flow, ctx, newData, isTransient, isRasp);
} catch (RuntimeException rte) {
log.warn("AppSec callback exception", rte);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface EventProducerService {
* set of addresses is identical.
*
* <p>The return value is to be passed to {@link #publishDataEvent(DataSubscriberInfo,
* AppSecRequestContext, DataBundle, boolean)}.
* AppSecRequestContext, DataBundle, boolean, boolean)}.
*
* @param newAddresses the addresses contained in the {@link DataBundle} that is to be passed to
* <code>publishDataEvent()</code>.
Expand All @@ -35,7 +35,8 @@ Flow<Void> publishDataEvent(
DataSubscriberInfo subscribers,
AppSecRequestContext ctx,
DataBundle newData,
boolean isTransient)
boolean isTransient,
boolean isRasp)
throws ExpiredSubscriberInfoException;

interface DataSubscriberInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ public Flow<Void> publishDataEvent(
DataSubscriberInfo subscribers,
AppSecRequestContext ctx,
DataBundle newData,
boolean isTransient)
boolean isTransient,
boolean isRasp)
throws ExpiredSubscriberInfoException {
return cur.publishDataEvent(subscribers, ctx, newData, isTransient);
return cur.publishDataEvent(subscribers, ctx, newData, isTransient, isRasp);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -112,6 +113,8 @@ public class AppSecRequestContext implements DataBundle, Closeable {
private Additive additive;
// set after additive is set
private volatile PowerwafMetrics wafMetrics;
private volatile PowerwafMetrics raspMetrics;
private AtomicInteger raspMetricsCounter;
private volatile boolean blocked;
private volatile int timeouts;

Expand Down Expand Up @@ -143,6 +146,14 @@ public PowerwafMetrics getWafMetrics() {
return wafMetrics;
}

public PowerwafMetrics getRaspMetrics() {
return raspMetrics;
}

public AtomicInteger getRaspMetricsCounter() {
return raspMetricsCounter;
}

public void setBlocked() {
this.blocked = true;
}
Expand All @@ -159,7 +170,18 @@ public int getTimeouts() {
return timeouts;
}

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

if (createMetrics) {
if (wafMetrics == null) {
this.wafMetrics = ctx.createMetrics();
}
if (isRasp && raspMetrics == null) {
this.raspMetrics = ctx.createMetrics();
this.raspMetricsCounter = new AtomicInteger(0);
}
}

Additive curAdditive;
synchronized (this) {
curAdditive = this.additive;
Expand All @@ -169,11 +191,6 @@ public Additive getOrCreateAdditive(PowerwafContext ctx, boolean createMetrics)
curAdditive = ctx.openAdditive();
this.additive = curAdditive;
}

// new additive was created
if (createMetrics) {
this.wafMetrics = ctx.createMetrics();
}
return curAdditive;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public void init() {
DataBundle bundle =
new SingletonDataBundle<>(KnownAddresses.REQUEST_PATH_PARAMS, data);
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
} catch (ExpiredSubscriberInfoException e) {
pathParamsSubInfo = null;
}
Expand Down Expand Up @@ -269,7 +269,7 @@ public void init() {
DataBundle bundle =
new SingletonDataBundle<>(KnownAddresses.REQUEST_BODY_RAW, bodyContent);
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
} catch (ExpiredSubscriberInfoException e) {
rawRequestBodySubInfo = null;
}
Expand Down Expand Up @@ -306,7 +306,7 @@ public void init() {
new SingletonDataBundle<>(
KnownAddresses.REQUEST_BODY_OBJECT, ObjectIntrospection.convert(obj));
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
} catch (ExpiredSubscriberInfoException e) {
requestBodySubInfo = null;
}
Expand Down Expand Up @@ -385,7 +385,7 @@ public void init() {
DataBundle bundle =
new SingletonDataBundle<>(KnownAddresses.GRPC_SERVER_METHOD, method);
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, true);
return producerService.publishDataEvent(subInfo, ctx, bundle, true, false);
} catch (ExpiredSubscriberInfoException e) {
grpcServerMethodSubInfo = null;
}
Expand Down Expand Up @@ -413,7 +413,7 @@ public void init() {
DataBundle bundle =
new SingletonDataBundle<>(KnownAddresses.GRPC_SERVER_REQUEST_MESSAGE, convObj);
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, true);
return producerService.publishDataEvent(subInfo, ctx, bundle, true, false);
} catch (ExpiredSubscriberInfoException e) {
grpcServerRequestMsgSubInfo = null;
}
Expand All @@ -440,7 +440,7 @@ public void init() {
DataBundle bundle =
new SingletonDataBundle<>(KnownAddresses.GRAPHQL_SERVER_ALL_RESOLVERS, data);
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, true);
return producerService.publishDataEvent(subInfo, ctx, bundle, true, false);
} catch (ExpiredSubscriberInfoException e) {
graphqlServerRequestMsgSubInfo = null;
}
Expand Down Expand Up @@ -481,7 +481,7 @@ public void init() {
.add(KnownAddresses.DB_SQL_QUERY, sql)
.build();
try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, true);
} catch (ExpiredSubscriberInfoException e) {
dbSqlQuerySubInfo = null;
}
Expand Down Expand Up @@ -678,7 +678,7 @@ private Flow<Void> maybePublishRequestData(AppSecRequestContext ctx) {
}

try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
} catch (ExpiredSubscriberInfoException e) {
this.initialReqDataSubInfo = null;
}
Expand Down Expand Up @@ -710,7 +710,7 @@ private Flow<Void> maybePublishResponseData(AppSecRequestContext ctx) {
}

try {
return producerService.publishDataEvent(subInfo, ctx, bundle, false);
return producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
} catch (ExpiredSubscriberInfoException e) {
respDataSubInfo = null;
}
Expand Down Expand Up @@ -742,7 +742,7 @@ private void maybeExtractSchemas(AppSecRequestContext ctx) {
KnownAddresses.WAF_CONTEXT_PROCESSOR,
Collections.singletonMap("extract-schema", true));
try {
producerService.publishDataEvent(subInfo, ctx, bundle, false);
producerService.publishDataEvent(subInfo, ctx, bundle, false, false);
return;
} catch (ExpiredSubscriberInfoException e) {
requestEndSubInfo = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,11 @@ public PowerWAFDataCallback() {

@Override
public void onDataAvailable(
ChangeableFlow flow, AppSecRequestContext reqCtx, DataBundle newData, boolean isTransient) {
ChangeableFlow flow,
AppSecRequestContext reqCtx,
DataBundle newData,
boolean isTransient,
boolean isRasp) {
Powerwaf.ResultWithData resultWithData;
CtxAndAddresses ctxAndAddr = ctxAndAddresses.get();
if (ctxAndAddr == null) {
Expand All @@ -429,7 +433,7 @@ public void onDataAvailable(
}

try {
resultWithData = doRunPowerwaf(reqCtx, newData, ctxAndAddr, isTransient);
resultWithData = doRunPowerwaf(reqCtx, newData, ctxAndAddr, isTransient, isRasp);
} catch (TimeoutPowerwafException tpe) {
reqCtx.increaseTimeouts();
log.debug(LogCollector.EXCLUDE_TELEMETRY, "Timeout calling the WAF", tpe);
Expand Down Expand Up @@ -583,11 +587,18 @@ private Powerwaf.ResultWithData doRunPowerwaf(
AppSecRequestContext reqCtx,
DataBundle newData,
CtxAndAddresses ctxAndAddr,
boolean isTransient)
boolean isTransient,
boolean isRasp)
throws AbstractPowerwafException {

Additive additive = reqCtx.getOrCreateAdditive(ctxAndAddr.ctx, wafMetricsEnabled);
PowerwafMetrics metrics = reqCtx.getWafMetrics();
Additive additive = reqCtx.getOrCreateAdditive(ctxAndAddr.ctx, wafMetricsEnabled, isRasp);
PowerwafMetrics metrics;
if (isRasp) {
metrics = reqCtx.getRaspMetrics();
reqCtx.getRaspMetricsCounter().incrementAndGet();
} else {
metrics = reqCtx.getWafMetrics();
}

if (isTransient) {
return runPowerwafTransient(additive, metrics, newData, ctxAndAddr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import java.util.Collection;

public class PowerWAFStatsReporter implements TraceSegmentPostProcessor {
private static final String TOTAL_DURATION_US_TAG = "_dd.appsec.waf.duration_ext";
private static final String TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.waf.duration";
private static final String WAF_TOTAL_DURATION_US_TAG = "_dd.appsec.waf.duration_ext";
private static final String WAF_TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.waf.duration";
private static final String RASP_TOTAL_DURATION_US_TAG = "_dd.appsec.rasp.duration_ext";
private static final String RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.rasp.duration";
private static final String RASP_RULE_EVAL = "_dd.appsec.rasp.rule.eval";
private static final String RULE_FILE_VERSION = "_dd.appsec.event_rules.version";
public static final String TIMEOUTS_TAG = "_dd.appsec.waf.timeouts";

Expand All @@ -20,16 +23,26 @@ public class PowerWAFStatsReporter implements TraceSegmentPostProcessor {
@Override
public void processTraceSegment(
TraceSegment segment, AppSecRequestContext ctx, Collection<AppSecEvent> collectedEvents) {
PowerwafMetrics metrics = ctx.getWafMetrics();
if (metrics != null) {
segment.setTagTop(TOTAL_DURATION_US_TAG, metrics.getTotalRunTimeNs() / 1000L);
segment.setTagTop(TOTAL_DDWAF_RUN_DURATION_US_TAG, metrics.getTotalDdwafRunTimeNs() / 1000L);
PowerwafMetrics wafMetrics = ctx.getWafMetrics();
if (wafMetrics != null) {
segment.setTagTop(WAF_TOTAL_DURATION_US_TAG, wafMetrics.getTotalRunTimeNs() / 1000L);
segment.setTagTop(
WAF_TOTAL_DDWAF_RUN_DURATION_US_TAG, wafMetrics.getTotalDdwafRunTimeNs() / 1000L);
}

PowerwafMetrics raspMetrics = ctx.getRaspMetrics();
if (raspMetrics != null) {
segment.setTagTop(RASP_TOTAL_DURATION_US_TAG, raspMetrics.getTotalRunTimeNs() / 1000L);
segment.setTagTop(
RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG, raspMetrics.getTotalDdwafRunTimeNs() / 1000L);
segment.setTagTop(RASP_RULE_EVAL, ctx.getRaspMetricsCounter().get());
}

String rulesVersion = this.rulesVersion;
if (rulesVersion != null) {
segment.setTagTop(RULE_FILE_VERSION, rulesVersion);
}
String rulesVersion = this.rulesVersion;
if (rulesVersion != null) {
segment.setTagTop(RULE_FILE_VERSION, rulesVersion);
}

if (ctx.getTimeouts() > 0) {
segment.setTagTop(TIMEOUTS_TAG, ctx.getTimeouts());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class AppSecModuleSpecification extends DDSpecification {
}

@Override
void onDataAvailable(ChangeableFlow flow, AppSecRequestContext context, DataBundle dataBundle, boolean isTransient) {
void onDataAvailable(ChangeableFlow flow, AppSecRequestContext context, DataBundle dataBundle, boolean isTransient, boolean isRasp) {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class BlockingServiceImplSpecification extends DDSpecification {
final OrderedCallback.Priority priority = OrderedCallback.Priority.DEFAULT

@Override
void onDataAvailable(ChangeableFlow flow, AppSecRequestContext context, DataBundle dataBundle, boolean isTransient) {
void onDataAvailable(ChangeableFlow flow, AppSecRequestContext context, DataBundle dataBundle, boolean isTransient, boolean isRasp) {
if (dataBundle.get(KnownAddresses.USER_ID) == 'blocked.user') {
flow.action = new Flow.Action.RequestBlockingAction(405, BlockingContentType.HTML)
}
Expand Down
Loading

0 comments on commit 5809b1d

Please sign in to comment.