Skip to content
Open
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
1 change: 1 addition & 0 deletions dd-java-agent/appsec/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
implementation project(':communication')
implementation project(':products:metrics:metrics-api')
implementation project(':telemetry')
implementation project(':dd-trace-core')
implementation group: 'io.sqreen', name: 'libsqreen', version: '17.3.0'
implementation libs.moshi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,26 @@ public ApiSecuritySamplerImpl(

@Override
public boolean preSampleRequest(final @Nonnull AppSecRequestContext ctx) {
final String route = ctx.getRoute();
String route = ctx.getRoute();

// If route is absent, use http.endpoint as fallback (RFC-1076)
if (route == null) {
return false;
// Don't sample blocked requests - they represent attacks, not valid API endpoints
if (ctx.isWafBlocked()) {
return false;
}
final int statusCode = ctx.getResponseStatus();
// Don't use endpoint for 404 responses as a failsafe
if (statusCode == 404) {
return false;
}
// Try to get or compute the endpoint
route = ctx.getOrComputeEndpoint();
if (route == null) {
return false;
}
}

final String method = ctx.getMethod();
if (method == null) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import datadog.trace.api.Config;
import datadog.trace.api.http.StoredBodySupplier;
import datadog.trace.api.internal.TraceSegment;
import datadog.trace.core.endpoint.EndpointResolver;
import datadog.trace.util.Numbers;
import datadog.trace.util.stacktrace.StackTraceEvent;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
Expand Down Expand Up @@ -121,6 +122,9 @@ public class AppSecRequestContext implements DataBundle, Closeable {
private String method;
private String savedRawURI;
private String route;
private String httpUrl;
private String endpoint;
private boolean endpointComputed = false;
private final Map<String, List<String>> requestHeaders = new LinkedHashMap<>();
private final Map<String, List<String>> responseHeaders = new LinkedHashMap<>();
private volatile Map<String, List<String>> collectedCookies;
Expand Down Expand Up @@ -424,6 +428,45 @@ public void setRoute(String route) {
this.route = route;
}

public String getHttpUrl() {
return httpUrl;
}

public void setHttpUrl(String httpUrl) {
this.httpUrl = httpUrl;
}

/**
* Gets or computes the http.endpoint for this request. The endpoint is computed lazily on first
* access and cached to avoid recomputation.
*
* @return the http.endpoint value, or null if it cannot be computed
*/
public String getOrComputeEndpoint() {
if (!endpointComputed) {
if (httpUrl != null && !httpUrl.isEmpty()) {
try {
endpoint = EndpointResolver.computeEndpoint(httpUrl);
} catch (Exception e) {
endpoint = null;
}
}
endpointComputed = true;
}
return endpoint;
}

/**
* Sets the endpoint directly without computing it. This is useful when the endpoint has already
* been computed elsewhere.
*
* @param endpoint the endpoint value to set
*/
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
this.endpointComputed = true;
}

public void setKeepOpenForApiSecurityPostProcessing(final boolean flag) {
this.keepOpenForApiSecurityPostProcessing = flag;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -949,11 +949,16 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) {
private boolean maybeSampleForApiSecurity(
AppSecRequestContext ctx, IGSpanInfo spanInfo, Map<String, Object> tags) {
log.debug("Checking API Security for end of request handler on span: {}", spanInfo.getSpanId());
// API Security sampling requires http.route tag.
// API Security sampling requires http.route tag or http.url for endpoint inference.
final Object route = tags.get(Tags.HTTP_ROUTE);
if (route != null) {
ctx.setRoute(route.toString());
}
// Pass http.url to enable endpoint inference when route is absent
final Object url = tags.get(Tags.HTTP_URL);
if (url != null) {
ctx.setHttpUrl(url.toString());
}
ApiSecuritySampler requestSampler = requestSamplerSupplier.get();
return requestSampler.preSampleRequest(ctx);
}
Expand Down
Loading