From 9e49fbe65fc15112c7476b5a9ad678072603d8af Mon Sep 17 00:00:00 2001 From: Eliott Bouhana <47679741+eliottness@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:29:22 +0200 Subject: [PATCH] appsec: Attacker Fingerprinting (#2899) Signed-off-by: Eliott Bouhana --- appsec/appsec.go | 51 +++-- go.mod | 2 +- go.sum | 4 +- internal/apps/go.mod | 2 +- internal/apps/go.sum | 4 +- internal/appsec/emitter/usersec/user.go | 49 ++--- .../appsec/emitter/waf/addresses/addresses.go | 6 +- .../appsec/emitter/waf/addresses/builder.go | 31 ++- internal/appsec/listener/usersec/usec.go | 26 ++- internal/appsec/remoteconfig.go | 4 + internal/appsec/testdata/fp.json | 207 ++++++++++++++++++ internal/appsec/waf_test.go | 42 ++++ internal/exectracetest/go.mod | 2 +- internal/exectracetest/go.sum | 4 +- internal/remoteconfig/remoteconfig.go | 30 ++- 15 files changed, 386 insertions(+), 78 deletions(-) create mode 100644 internal/appsec/testdata/fp.json diff --git a/appsec/appsec.go b/appsec/appsec.go index f57389de0c..33286cdc17 100644 --- a/appsec/appsec.go +++ b/appsec/appsec.go @@ -33,7 +33,7 @@ var appsecDisabledLog sync.Once // Note that passing the raw bytes of the HTTP request body is not expected and would // result in inaccurate attack detection. // This function always returns nil when appsec is disabled. -func MonitorParsedHTTPBody(ctx context.Context, body interface{}) error { +func MonitorParsedHTTPBody(ctx context.Context, body any) error { if !appsec.Enabled() { appsecDisabledLog.Do(func() { log.Warn("appsec: not enabled. Body blocking checks won't be performed.") }) return nil @@ -60,7 +60,15 @@ func SetUser(ctx context.Context, id string, opts ...tracer.UserMonitoringOption appsecDisabledLog.Do(func() { log.Warn("appsec: not enabled. User blocking checks won't be performed.") }) return nil } - return usersec.MonitorUser(ctx, id) + + op, errPtr := usersec.StartUserLoginOperation(ctx, usersec.UserLoginOperationArgs{}) + op.Finish(usersec.UserLoginOperationRes{ + UserID: id, + SessionID: getSessionID(opts...), + Success: true, + }) + + return *errPtr } // TrackUserLoginSuccessEvent sets a successful user login event, with the given @@ -76,17 +84,7 @@ func SetUser(ctx context.Context, id string, opts ...tracer.UserMonitoringOption // Take-Over (ATO) monitoring, ultimately blocking the IP address and/or user id // associated to them. func TrackUserLoginSuccessEvent(ctx context.Context, uid string, md map[string]string, opts ...tracer.UserMonitoringOption) error { - span := getRootSpan(ctx) - if span == nil { - return nil - } - - const tagPrefix = "appsec.events.users.login.success." - span.SetTag(tagPrefix+"track", true) - for k, v := range md { - span.SetTag(tagPrefix+k, v) - } - span.SetTag(ext.SamplingPriority, ext.PriorityUserKeep) + TrackCustomEvent(ctx, "users.login.success", md) return SetUser(ctx, uid, opts...) } @@ -106,14 +104,15 @@ func TrackUserLoginFailureEvent(ctx context.Context, uid string, exists bool, md return } - const tagPrefix = "appsec.events.users.login.failure." - span.SetTag(tagPrefix+"track", true) - span.SetTag(tagPrefix+"usr.id", uid) - span.SetTag(tagPrefix+"usr.exists", exists) - for k, v := range md { - span.SetTag(tagPrefix+k, v) - } - span.SetTag(ext.SamplingPriority, ext.PriorityUserKeep) + // We need to do the first call to SetTag ourselves because the map taken by TrackCustomEvent is map[string]string + // and not map [string]any, so the `exists` boolean variable does not fit int + span.SetTag("appsec.events.users.login.failure.usr.exists", exists) + span.SetTag("appsec.events.users.login.failure.usr.id", uid) + + TrackCustomEvent(ctx, "users.login.failure", md) + + op, _ := usersec.StartUserLoginOperation(ctx, usersec.UserLoginOperationArgs{}) + op.Finish(usersec.UserLoginOperationRes{UserID: uid, Success: false}) } // TrackCustomEvent sets a custom event as service entry span tags. This span is @@ -153,3 +152,13 @@ func getRootSpan(ctx context.Context) tracer.Span { log.Error("appsec: could not access the root span") return nil } + +func getSessionID(opts ...tracer.UserMonitoringOption) string { + cfg := &tracer.UserMonitoringConfig{ + Metadata: make(map[string]string), + } + for _, opt := range opts { + opt(cfg) + } + return cfg.SessionID +} diff --git a/go.mod b/go.mod index bea4752810..dd79838aea 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 require ( cloud.google.com/go/pubsub v1.33.0 github.com/99designs/gqlgen v0.17.36 - github.com/DataDog/appsec-internal-go v1.7.0 + github.com/DataDog/appsec-internal-go v1.8.0 github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 github.com/DataDog/datadog-go/v5 v5.3.0 diff --git a/go.sum b/go.sum index 427525a587..2f810fce66 100644 --- a/go.sum +++ b/go.sum @@ -625,8 +625,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9s github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFor3D/HDsvBME35Xy9rwW9DecL+M2sNw1ybjPtwA0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/appsec-internal-go v1.7.0 h1:iKRNLih83dJeVya3IoUfK+6HLD/hQsIbyBlfvLmAeb0= -github.com/DataDog/appsec-internal-go v1.7.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= +github.com/DataDog/appsec-internal-go v1.8.0 h1:1Tfn3LEogntRqZtf88twSApOCAAO3V+NILYhuQIo4J4= +github.com/DataDog/appsec-internal-go v1.8.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 h1:LplNAmMgZvGU7kKA0+4c1xWOjz828xweW5TCi8Mw9Q0= diff --git a/internal/apps/go.mod b/internal/apps/go.mod index 72b14e8123..95996c44a0 100644 --- a/internal/apps/go.mod +++ b/internal/apps/go.mod @@ -8,7 +8,7 @@ require ( ) require ( - github.com/DataDog/appsec-internal-go v1.7.0 // indirect + github.com/DataDog/appsec-internal-go v1.8.0 // indirect github.com/DataDog/go-libddwaf/v3 v3.4.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect diff --git a/internal/apps/go.sum b/internal/apps/go.sum index b5c314d6e7..50cbaff7fe 100644 --- a/internal/apps/go.sum +++ b/internal/apps/go.sum @@ -1,5 +1,5 @@ -github.com/DataDog/appsec-internal-go v1.7.0 h1:iKRNLih83dJeVya3IoUfK+6HLD/hQsIbyBlfvLmAeb0= -github.com/DataDog/appsec-internal-go v1.7.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= +github.com/DataDog/appsec-internal-go v1.8.0 h1:1Tfn3LEogntRqZtf88twSApOCAAO3V+NILYhuQIo4J4= +github.com/DataDog/appsec-internal-go v1.8.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 h1:LplNAmMgZvGU7kKA0+4c1xWOjz828xweW5TCi8Mw9Q0= diff --git a/internal/appsec/emitter/usersec/user.go b/internal/appsec/emitter/usersec/user.go index c2b09e627d..50a4352e6d 100644 --- a/internal/appsec/emitter/usersec/user.go +++ b/internal/appsec/emitter/usersec/user.go @@ -10,45 +10,42 @@ import ( "gopkg.in/DataDog/dd-trace-go.v1/appsec/events" "gopkg.in/DataDog/dd-trace-go.v1/internal/appsec/dyngo" - "gopkg.in/DataDog/dd-trace-go.v1/internal/log" ) +const errorLog = ` +appsec: user login monitoring ignored: could not find the http handler instrumentation metadata in the request context: + the request handler is not being monitored by a middleware function or the provided context is not the expected request context +` + type ( - // UserIDOperation type representing a call to appsec.SetUser(). It gets both created and destroyed in a single + // UserLoginOperation type representing a call to appsec.SetUser(). It gets both created and destroyed in a single // call to ExecuteUserIDOperation - UserIDOperation struct { + UserLoginOperation struct { dyngo.Operation } - // UserIDOperationArgs is the user ID operation arguments. - UserIDOperationArgs struct { - UserID string + // UserLoginOperationArgs is the user ID operation arguments. + UserLoginOperationArgs struct{} + + // UserLoginOperationRes is the user ID operation results. + UserLoginOperationRes struct { + UserID string + SessionID string + Success bool } - // UserIDOperationRes is the user ID operation results. - UserIDOperationRes struct{} ) -// ExecuteUserIDOperation starts and finishes the UserID operation by emitting a dyngo start and finish events -// An error is returned if the user associated to that operation must be blocked -func ExecuteUserIDOperation(parent dyngo.Operation, args UserIDOperationArgs) error { +func StartUserLoginOperation(ctx context.Context, args UserLoginOperationArgs) (*UserLoginOperation, *error) { + parent, _ := dyngo.FromContext(ctx) + op := &UserLoginOperation{Operation: dyngo.NewOperation(parent)} var err error - op := &UserIDOperation{Operation: dyngo.NewOperation(parent)} dyngo.OnData(op, func(e *events.BlockingSecurityEvent) { err = e }) dyngo.StartOperation(op, args) - dyngo.FinishOperation(op, UserIDOperationRes{}) - return err + return op, &err } -// MonitorUser starts and finishes a UserID operation. -// A call to the WAF is made to check the user ID and an error is returned if the -// user should be blocked. The return value is nil otherwise. -func MonitorUser(ctx context.Context, userID string) error { - if parent, ok := dyngo.FromContext(ctx); ok { - return ExecuteUserIDOperation(parent, UserIDOperationArgs{UserID: userID}) - } - log.Error("appsec: user ID monitoring ignored: could not find the http handler instrumentation metadata in the request context: the request handler is not being monitored by a middleware function or the provided context is not the expected request context") - return nil - +func (op *UserLoginOperation) Finish(args UserLoginOperationRes) { + dyngo.FinishOperation(op, args) } -func (UserIDOperationArgs) IsArgOf(*UserIDOperation) {} -func (UserIDOperationRes) IsResultOf(*UserIDOperation) {} +func (UserLoginOperationArgs) IsArgOf(*UserLoginOperation) {} +func (UserLoginOperationRes) IsResultOf(*UserLoginOperation) {} diff --git a/internal/appsec/emitter/waf/addresses/addresses.go b/internal/appsec/emitter/waf/addresses/addresses.go index 9b32514b1a..03163df23a 100644 --- a/internal/appsec/emitter/waf/addresses/addresses.go +++ b/internal/appsec/emitter/waf/addresses/addresses.go @@ -17,7 +17,11 @@ const ( ServerResponseHeadersNoCookiesAddr = "server.response.headers.no_cookies" ClientIPAddr = "http.client_ip" - UserIDAddr = "usr.id" + + UserIDAddr = "usr.id" + UserSessionIDAddr = "usr.session_id" + UserLoginSuccessAddr = "server.business_logic.users.login.success" + UserLoginFailureAddr = "server.business_logic.users.login.failure" ServerIoNetURLAddr = "server.io.net.url" ServerIOFSFileAddr = "server.io.fs.file" diff --git a/internal/appsec/emitter/waf/addresses/builder.go b/internal/appsec/emitter/waf/addresses/builder.go index ea641d2add..946a62bcf9 100644 --- a/internal/appsec/emitter/waf/addresses/builder.go +++ b/internal/appsec/emitter/waf/addresses/builder.go @@ -28,24 +28,18 @@ func NewAddressesBuilder() *RunAddressDataBuilder { } func (b *RunAddressDataBuilder) WithMethod(method string) *RunAddressDataBuilder { - if method == "" { - return b - } b.Persistent[ServerRequestMethodAddr] = method return b } func (b *RunAddressDataBuilder) WithRawURI(uri string) *RunAddressDataBuilder { - if uri == "" { - return b - } b.Persistent[ServerRequestRawURIAddr] = uri return b } func (b *RunAddressDataBuilder) WithHeadersNoCookies(headers map[string][]string) *RunAddressDataBuilder { if len(headers) == 0 { - return b + headers = nil } b.Persistent[ServerRequestHeadersNoCookiesAddr] = headers return b @@ -53,7 +47,7 @@ func (b *RunAddressDataBuilder) WithHeadersNoCookies(headers map[string][]string func (b *RunAddressDataBuilder) WithCookies(cookies map[string][]string) *RunAddressDataBuilder { if len(cookies) == 0 { - return b + cookies = nil } b.Persistent[ServerRequestCookiesAddr] = cookies return b @@ -61,7 +55,7 @@ func (b *RunAddressDataBuilder) WithCookies(cookies map[string][]string) *RunAdd func (b *RunAddressDataBuilder) WithQuery(query map[string][]string) *RunAddressDataBuilder { if len(query) == 0 { - return b + query = nil } b.Persistent[ServerRequestQueryAddr] = query return b @@ -115,6 +109,25 @@ func (b *RunAddressDataBuilder) WithUserID(id string) *RunAddressDataBuilder { return b } +func (b *RunAddressDataBuilder) WithUserSessionID(id string) *RunAddressDataBuilder { + if id == "" { + return b + } + b.Persistent[UserSessionIDAddr] = id + return b + +} + +func (b *RunAddressDataBuilder) WithUserLoginSuccess() *RunAddressDataBuilder { + b.Persistent[UserLoginSuccessAddr] = nil + return b +} + +func (b *RunAddressDataBuilder) WithUserLoginFailure() *RunAddressDataBuilder { + b.Persistent[UserLoginFailureAddr] = nil + return b +} + func (b *RunAddressDataBuilder) WithFilePath(file string) *RunAddressDataBuilder { if file == "" { return b diff --git a/internal/appsec/listener/usersec/usec.go b/internal/appsec/listener/usersec/usec.go index 3a813033af..c8a6458019 100644 --- a/internal/appsec/listener/usersec/usec.go +++ b/internal/appsec/listener/usersec/usec.go @@ -23,20 +23,32 @@ func (*Feature) String() string { func (*Feature) Stop() {} func NewUserSecFeature(cfg *config.Config, rootOp dyngo.Operation) (listener.Feature, error) { - if !cfg.RASP || !cfg.SupportedAddresses.AnyOf(addresses.UserIDAddr) { + if !cfg.SupportedAddresses.AnyOf( + addresses.UserIDAddr, + addresses.UserSessionIDAddr, + addresses.UserLoginSuccessAddr, + addresses.UserLoginFailureAddr) { return nil, nil } feature := &Feature{} - dyngo.On(rootOp, feature.OnStart) + dyngo.OnFinish(rootOp, feature.OnFinish) return feature, nil } -func (*Feature) OnStart(op *usersec.UserIDOperation, args usersec.UserIDOperationArgs) { +func (*Feature) OnFinish(op *usersec.UserLoginOperation, res usersec.UserLoginOperationRes) { + builder := addresses.NewAddressesBuilder(). + WithUserID(res.UserID). + WithUserSessionID(res.SessionID) + + if res.Success { + builder = builder.WithUserLoginSuccess() + } else { + builder = builder.WithUserLoginFailure() + } + dyngo.EmitData(op, waf.RunEvent{ - Operation: op, - RunAddressData: addresses.NewAddressesBuilder(). - WithUserID(args.UserID). - Build(), + Operation: op, + RunAddressData: builder.Build(), }) } diff --git a/internal/appsec/remoteconfig.go b/internal/appsec/remoteconfig.go index 667016475c..ccf6fe7631 100644 --- a/internal/appsec/remoteconfig.go +++ b/internal/appsec/remoteconfig.go @@ -392,6 +392,10 @@ var blockingCapabilities = [...]remoteconfig.Capability{ remoteconfig.ASMCustomBlockingResponse, remoteconfig.ASMTrustedIPs, remoteconfig.ASMExclusionData, + remoteconfig.ASMEndpointFingerprinting, + remoteconfig.ASMSessionFingerprinting, + remoteconfig.ASMNetworkFingerprinting, + remoteconfig.ASMHeaderFingerprinting, } func (a *appsec) enableRCBlocking() { diff --git a/internal/appsec/testdata/fp.json b/internal/appsec/testdata/fp.json new file mode 100644 index 0000000000..52af47f36c --- /dev/null +++ b/internal/appsec/testdata/fp.json @@ -0,0 +1,207 @@ +{ + "version": "2.2", + "metadata": { + "rules_version": "1.4.2" + }, + "rules": [ + { + "id": "crs-933-130-block", + "name": "PHP Injection Attack: Global Variables Found", + "tags": { + "type": "php_code_injection", + "crs_id": "933130", + "category": "attack_attempt", + "confidence": "1" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.query" + } + ], + "list": [ + "$globals" + ] + }, + "operator": "phrase_match" + } + ], + "transformers": [ + "lowercase" + ] + } + ], + "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 + } + ] +} diff --git a/internal/appsec/waf_test.go b/internal/appsec/waf_test.go index 19afa15a4f..8045b86831 100644 --- a/internal/appsec/waf_test.go +++ b/internal/appsec/waf_test.go @@ -30,6 +30,7 @@ import ( sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql" httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "gopkg.in/DataDog/dd-trace-go.v1/internal/appsec" "gopkg.in/DataDog/dd-trace-go.v1/internal/appsec/config" "gopkg.in/DataDog/dd-trace-go.v1/internal/appsec/dyngo" @@ -934,6 +935,47 @@ func BenchmarkSampleWAFContext(b *testing.B) { } } +func TestAttackerFingerprinting(t *testing.T) { + t.Setenv("DD_APPSEC_RULES", "testdata/fp.json") + appsec.Start() + defer appsec.Stop() + if !appsec.Enabled() { + t.Skip("AppSec needs to be enabled for this test") + } + + // Start and trace an HTTP server + mux := httptrace.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + pAppsec.TrackUserLoginSuccessEvent( + r.Context(), + "toto", + map[string]string{}, + tracer.WithUserSessionID("sessionID")) + + pAppsec.MonitorParsedHTTPBody(r.Context(), map[string]string{"key": "value"}) + + w.Write([]byte("Hello World!\n")) + }) + srv := httptest.NewServer(mux) + defer srv.Close() + + mt := mocktracer.Start() + defer mt.Stop() + req, err := http.NewRequest("POST", srv.URL+"/test?x=1", nil) + require.NoError(t, err) + req.AddCookie(&http.Cookie{Name: "cookie", Value: "value"}) + resp, err := srv.Client().Do(req) + require.NoError(t, err) + defer resp.Body.Close() + spans := mt.FinishedSpans() + + require.Len(t, spans, 1) + require.Contains(t, spans[0].Tags(), "_dd.appsec.fp.http.header") + require.Contains(t, spans[0].Tags(), "_dd.appsec.fp.http.endpoint") + require.Contains(t, spans[0].Tags(), "_dd.appsec.fp.http.network") + require.Contains(t, spans[0].Tags(), "_dd.appsec.fp.session") +} + func init() { // This permits running the tests locally without defining the env var manually // We do this because the default go-libddwaf timeout value is too small and makes the tests timeout for no reason diff --git a/internal/exectracetest/go.mod b/internal/exectracetest/go.mod index 2fe010a84d..3de8625361 100644 --- a/internal/exectracetest/go.mod +++ b/internal/exectracetest/go.mod @@ -10,7 +10,7 @@ require ( ) require ( - github.com/DataDog/appsec-internal-go v1.7.0 // indirect + github.com/DataDog/appsec-internal-go v1.8.0 // indirect github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 // indirect github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 // indirect github.com/DataDog/datadog-go/v5 v5.3.0 // indirect diff --git a/internal/exectracetest/go.sum b/internal/exectracetest/go.sum index 2914c590d2..6554dc855a 100644 --- a/internal/exectracetest/go.sum +++ b/internal/exectracetest/go.sum @@ -1,5 +1,5 @@ -github.com/DataDog/appsec-internal-go v1.7.0 h1:iKRNLih83dJeVya3IoUfK+6HLD/hQsIbyBlfvLmAeb0= -github.com/DataDog/appsec-internal-go v1.7.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= +github.com/DataDog/appsec-internal-go v1.8.0 h1:1Tfn3LEogntRqZtf88twSApOCAAO3V+NILYhuQIo4J4= +github.com/DataDog/appsec-internal-go v1.8.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.57.0 h1:LplNAmMgZvGU7kKA0+4c1xWOjz828xweW5TCi8Mw9Q0= diff --git a/internal/remoteconfig/remoteconfig.go b/internal/remoteconfig/remoteconfig.go index 1e67a28f78..4076c2ad34 100644 --- a/internal/remoteconfig/remoteconfig.go +++ b/internal/remoteconfig/remoteconfig.go @@ -86,12 +86,32 @@ const ( ASMRASPLFI // ASMRASPSSRF enables ASM support for runtime protection against SSRF attacks ASMRASPSSRF -) - -// Additional capability bit index values that are non-consecutive from above. -const ( + // ASMRASPSHI enables ASM support for runtime protection against XSS attacks + ASMRASPSHI + // ASMRASPXXE enables ASM support for runtime protection against XXE attacks + ASMRASPXXE + // ASMRASPRCE enables ASM support for runtime protection against Remote Code Execution + ASMRASPRCE + // ASMRASPNOSQLI enables ASM support for runtime protection against NoSQL Injection attacks + ASMRASPNOSQLI + // ASMRASPXSS enables ASM support for runtime protection against Cross Site Scripting attacks + ASMRASPXSS // APMTracingSampleRules represents the sampling rate using matching rules from APM client libraries - APMTracingSampleRules = 29 + APMTracingSampleRules + // CSMActivation represents the capability to activate CSM through remote configuration + CSMActivation + // ASMAutoUserInstrumMode represents the capability to enable the automatic user instrumentation mode + ASMAutoUserInstrumMode + // ASMEndpointFingerprinting represents the capability to enable endpoint fingerprinting + ASMEndpointFingerprinting + // ASMSessionFingerprinting represents the capability to enable session fingerprinting + ASMSessionFingerprinting + // ASMNetworkFingerprinting represents the capability to enable network fingerprinting + ASMNetworkFingerprinting + // ASMHeaderFingerprinting represents the capability to enable header fingerprinting + ASMHeaderFingerprinting + // ASMTruncationRules is the support for truncation payload rules + ASMTruncationRules ) // ErrClientNotStarted is returned when the remote config client is not started.