diff --git a/README.md b/README.md index 0e638ffe..b0d4146f 100644 --- a/README.md +++ b/README.md @@ -18,64 +18,66 @@ Sqreen provides automatic defense against attacks: - Protect with security modules: RASP (Runtime Application Self-Protection), in-app WAF (Web Application Firewall), Account takeovers and more. -- Sqreen’s modules adapt to your application stack with no need of configuration. +- Sqreen’s modules adapt to your application stack with no need of + configuration. -- Prevent attacks from the OWASP Top 10 (Injections, XSS and more), 0-days, - data Leaks, and more. - -- Create security automation playbooks that automatically react against - your advanced business-logic threats. +- Prevent attacks from the OWASP Top 10 (Injections, XSS and more), 0-days, data + Leaks, and more. + +- Create security automation playbooks that automatically react against your + advanced business-logic threats. For more details, visit [sqreen.com](https://www.sqreen.com/) # Quick start 1. Use the middleware function for the Go web framework you use: - - [net/http](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqhttp) - - [Gin](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqgin) - - [Echo](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqecho/v4) + - [net/http](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqhttp) + - [Gin](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqgin) + - [Echo](https://godoc.org/github.com/sqreen/go-agent/sdk/middleware/sqecho/v4) If your framework is not listed, it is usually possible to use instead the - standard `net/http` middleware. If not, please, let us know by [creating an - issue](http://github.com/sqreen/go-agent/issues/new). + standard `net/http` middleware. If not, please, let us know + by [creating an issue](http://github.com/sqreen/go-agent/issues/new). 1. Compile your program with Sqreen Sqreen's dynamic configuration of your protection is made possible thanks to - Go instrumentation. It is safely performed at compilation time by the following - instrumentation tool. + Go instrumentation. It is safely performed at compilation time by the + following instrumentation tool. Install the following instrumentation tool and compile your program using it in order to enable Sqreen. - 1. Use `go build` to download and compile the instrumentation tool: - - ```console - $ go build github.com/sqreen/go-agent/sdk/sqreen-instrumentation - ``` - - 1. Configure the Go toolchain to use it: - - Use the instrumentation tool using the go options - `-a -toolexec /path/to/sqreen-instrumentation`. - - It can be done either in your Go compilation command lines or by setting the - `GOFLAGS` environment variable. - - For example, the following two commands are equivalent: - ```console - $ go build -a -toolexec $PWD/sqreen-instrumentation-tool my-project - $ env GOFLAGS="-a -toolexec $PWD/sqreen-instrumentation-tool" go build my-project - ``` - -1. [Signup to Sqreen](https://my.sqreen.io/signup) to get a token for your app, - and store it in the agent's configuration file `sqreen.yaml`: - + 1. Use `go install` to compile the instrumentation tool: + ```console + $ go install github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool + ``` + + By default, the resulting `sqreen-instrumentation-tool` tool is installed + in the + `bin` directory of the `GOPATH`. You can find it using `go env GOPATH`. + + 1. Configure the Go toolchain to use it: + + Use the instrumentation tool using the go options + `-a -toolexec /path/to/sqreen-instrumentation-tool`. + + It can be done either in your Go compilation command lines or by setting + the `GOFLAGS` environment variable. + + For example, the following two commands are equivalent: + ```console + $ go build -a -toolexec $(go env GOPATH)/bin/sqreen-instrumentation-tool my-project + $ env GOFLAGS="-a -toolexec $(go env GOPATH)/bin/sqreen-instrumentation-tool" go build my-project + ``` + +1. [Signup to Sqreen](https://my.sqreen.io/signup) to get your app credentials: ```sh app_name: Your Go app name token: your token ``` - + This file can be stored in your current working directory when starting the executable, the same directory as your app's executable file, or in any other path by defining the configuration file location into the environment @@ -87,9 +89,9 @@ Congratulations, your Go web application is now protected by Sqreen! Sqreen for Go

- # Advanced integration -Optionally, use the SDK to perform [user monitoring](https://docs.sqreen.com/go/user-monitoring/) +Optionally, use the SDK to +perform [user monitoring](https://docs.sqreen.com/go/user-monitoring/) or [custom security events](https://docs.sqreen.com/go/custom-events/) you would like to track and possibly block. diff --git a/go.mod b/go.mod index a6174652..e210f98c 100644 --- a/go.mod +++ b/go.mod @@ -30,8 +30,6 @@ require ( github.com/sqreen/go-sdk/signal v1.2.0 github.com/stretchr/testify v1.6.1 golang.org/x/net v0.0.0-20200822124328-c89045814202 - golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect - golang.org/x/text v0.3.2 // indirect golang.org/x/tools v0.0.0-20200914190812-8f9ed77dd8e5 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/go.sum b/go.sum index e39fa3c7..4f10151e 100644 --- a/go.sum +++ b/go.sum @@ -109,9 +109,8 @@ github.com/sqreen/go-libsqreen v0.7.1 h1:wKjpt2+BjDx9Gi8VsQOS9YP3Q43lX0o835LwFPp github.com/sqreen/go-libsqreen v0.7.1/go.mod h1:krFVmXmHM5SaWeED8jDb8KwrViK505KDBpYJ8IY2Ks8= github.com/sqreen/go-sdk/signal v1.2.0 h1:Soa7u9l4gBc+mZzKDWC318fUQPY1akcG5nWjJVVTRL8= github.com/sqreen/go-sdk/signal v1.2.0/go.mod h1:XWJV0TzuoN6PotzRn4YSe6fhTxyw67yRpVYr9NJTzto= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -138,36 +137,23 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90Pveol golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -<<<<<<< HEAD golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -======= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= ->>>>>>> f149b60... go: update go-sdk to v1.2.0 including binning metrics golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -177,9 +163,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -189,11 +172,9 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200914190812-8f9ed77dd8e5 h1:0fRDy3QcHVldF7M1zhimPxxaIexpz0hjod21h92AT30= golang.org/x/tools v0.0.0-20200914190812-8f9ed77dd8e5/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -209,7 +190,6 @@ gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/command.go b/internal/command.go index e3e97d58..ae3347a4 100644 --- a/internal/command.go +++ b/internal/command.go @@ -129,11 +129,15 @@ func (m *CommandManager) SetPerformanceBudget(args []json.RawMessage) (string, e if argc := len(args); argc != 1 { return "", fmt.Errorf("unexpected number of arguments: expected 1 argument but got %d", argc) } - var budget float64 + var v *float64 arg0 := args[0] - if err := json.Unmarshal(arg0, &budget); err != nil { + if err := json.Unmarshal(arg0, &v); err != nil { return "", err } + var budget float64 + if v != nil { + budget = *v + } return "", m.agent.SetPerformanceBudget(budget) } diff --git a/internal/protection/http/http.go b/internal/protection/http/http.go index ecae410b..250b1c46 100644 --- a/internal/protection/http/http.go +++ b/internal/protection/http/http.go @@ -211,6 +211,7 @@ func (p *ProtectionContext) HandleAttack(block bool, attack interface{}) (blocke if attack != nil { p.events.AddAttackEvent(attack) } + return blocked } diff --git a/internal/rule/callback.go b/internal/rule/callback.go index 40c77b90..777cb89b 100644 --- a/internal/rule/callback.go +++ b/internal/rule/callback.go @@ -64,6 +64,7 @@ func newNativeRuleContext(rule *api.Rule, rulepackID string, metricsEngine *metr defaultMetricsStore: defaultMetricsStore, name: rule.Name, testMode: rule.Test, + blockingMode: rule.Block, attackType: rule.AttackType, logger: logger, } @@ -139,6 +140,7 @@ func withCallCount(engine *metrics.Engine, rulepackID, ruleName string) NativeCa if err := store.Add(callCounterID, 1); err != nil { c.Logger().Error(err) } + cb(c) } } } diff --git a/internal/rule/callback/bindingaccessors.go b/internal/rule/callback/bindingaccessors.go index 485ab3c1..9e7236b0 100644 --- a/internal/rule/callback/bindingaccessors.go +++ b/internal/rule/callback/bindingaccessors.go @@ -12,36 +12,37 @@ import ( "strings" http_protection "github.com/sqreen/go-agent/internal/protection/http" - "github.com/sqreen/go-agent/internal/protection/http/types" + http_protection_types "github.com/sqreen/go-agent/internal/protection/http/types" + callback_types "github.com/sqreen/go-agent/internal/rule/callback/types" "github.com/sqreen/go-agent/internal/sqlib/sqerrors" "github.com/sqreen/go-agent/internal/sqlib/sqgo" ) -func NewReflectedCallbackBindingAccessorContext(capabilities []string, req interface{}, args, res []reflect.Value, ruleValues interface{}) (*BindingAccessorContextType, error) { - var c = &BindingAccessorContextType{} +func NewReflectedCallbackBindingAccessorContext(capabilities []string, c CallbackContext, args, res []reflect.Value, ruleValues interface{}) (*BindingAccessorContextType, error) { + var ctx = &BindingAccessorContextType{} for _, cap := range capabilities { switch cap { case "rule": - c.Rule = NewRuleBindingAccessorContext(ruleValues) + ctx.Rule = NewRuleBindingAccessorContext(ruleValues) case "sql": - c.SQL = NewSQLBindingAccessorContext() + ctx.SQL = NewSQLBindingAccessorContext() case "func": - c.Func = NewFunctionBindingAccessorContext(args, res) + ctx.Func = NewFunctionBindingAccessorContext(args, res) case "request": - baCtx, err := NewRequestBindingAccessorContext(req) + baCtx, err := NewRequestBindingAccessorContext(c.ProtectionContext()) if err != nil { return nil, sqerrors.Wrapf(err, "could not create the request binding accessor context") } - c.HTTPRequestBindingAccessorContext = baCtx + ctx.HTTPRequestBindingAccessorContext = baCtx case "lib": - c.Lib = NewLibraryBindingAccessorContext() + ctx.Lib = NewLibraryBindingAccessorContext() case "cache": - c.BindingAccessorResultCache = MakeBindingAccessorResultCache() + ctx.BindingAccessorResultCache = MakeBindingAccessorResultCache() default: return nil, sqerrors.Errorf("unknown binding accessor capability `%s`", cap) } } - return c, nil + return ctx, nil } type RuleBindingAccessorContextType struct { @@ -147,7 +148,7 @@ func MakeWAFCallbackBindingAccessorContext(c CallbackContext) (WAFBindingAccesso } } -func makeHTTPWAFCallbackBindingAccessorContext(request types.RequestReader) WAFBindingAccessorContextType { +func makeHTTPWAFCallbackBindingAccessorContext(request http_protection_types.RequestReader) WAFBindingAccessorContextType { return WAFBindingAccessorContextType{ HTTPRequestBindingAccessorContext: MakeHTTPRequestBindingAccessorContext(request), BindingAccessorResultCache: MakeBindingAccessorResultCache(), @@ -192,22 +193,22 @@ func (b BindingAccessorResultCache) Get(expr string) (value interface{}, exists return } -func NewRequestBindingAccessorContext(req interface{}) (*HTTPRequestBindingAccessorContext, error) { - switch actual := req.(type) { +func NewRequestBindingAccessorContext(p callback_types.ProtectionContext) (*HTTPRequestBindingAccessorContext, error) { + switch actual := p.(type) { default: return nil, sqerrors.Errorf("unexpected request type `%T`", actual) - case types.RequestReader: - return NewHTTPRequestBindingAccessorContext(actual), nil + case *http_protection.ProtectionContext: + return NewHTTPRequestBindingAccessorContext(actual.RequestReader), nil } } -func NewHTTPRequestBindingAccessorContext(req types.RequestReader) *HTTPRequestBindingAccessorContext { +func NewHTTPRequestBindingAccessorContext(req http_protection_types.RequestReader) *HTTPRequestBindingAccessorContext { ctx := MakeHTTPRequestBindingAccessorContext(req) return &ctx } -func MakeHTTPRequestBindingAccessorContext(request types.RequestReader) HTTPRequestBindingAccessorContext { +func MakeHTTPRequestBindingAccessorContext(request http_protection_types.RequestReader) HTTPRequestBindingAccessorContext { return HTTPRequestBindingAccessorContext{ Request: http_protection.NewRequestBindingAccessorContext(request), } diff --git a/internal/rule/callback/monitor-http-status-code.go b/internal/rule/callback/monitor-http-status-code.go index 6202a0b7..621db88e 100644 --- a/internal/rule/callback/monitor-http-status-code.go +++ b/internal/rule/callback/monitor-http-status-code.go @@ -19,6 +19,7 @@ func NewMonitorHTTPStatusCodeCallback(r RuleContext, _ NativeCallbackConfig) (sq func newMonitorHTTPStatusCodePrologCallback(r RuleContext) http_protection.ResponseMonitoringPrologCallbackType { return func(_ **http_protection.ProtectionContext, resp *types.ResponseFace) (http_protection.NonBlockingEpilogCallbackType, error) { r.Pre(func(c CallbackContext) { + // TODO: log once _ = c.PushMetricsValue((*resp).Status(), 1) }) return nil, nil diff --git a/internal/rule/callback/write-custom-error-page.go b/internal/rule/callback/write-blocking-html-page.go similarity index 91% rename from internal/rule/callback/write-custom-error-page.go rename to internal/rule/callback/write-blocking-html-page.go index d8eddf54..892811d8 100644 --- a/internal/rule/callback/write-custom-error-page.go +++ b/internal/rule/callback/write-blocking-html-page.go @@ -13,11 +13,11 @@ import ( "github.com/sqreen/go-agent/internal/sqlib/sqhook" ) -// NewWriteCustomErrorPageCallback returns the native prolog and epilog +// NewWriteBlockingHTMLPageCallback returns the native prolog and epilog // callbacks modifying the arguments of `httphandler.WriteResponse` in order to // modify the http status code and error page that are provided by the rule's // data. -func NewWriteCustomErrorPageCallback(_ RuleContext, cfg NativeCallbackConfig) (sqhook.PrologCallback, error) { +func NewWriteBlockingHTMLPageCallback(_ RuleContext, cfg NativeCallbackConfig) (sqhook.PrologCallback, error) { var statusCode = 500 // default status code if data := cfg.Data(); data != nil { cfg, ok := data.(*api.CustomErrorPageRuleDataEntry) @@ -26,18 +26,19 @@ func NewWriteCustomErrorPageCallback(_ RuleContext, cfg NativeCallbackConfig) (s } statusCode = cfg.StatusCode } - return newWriteCustomErrorPagePrologCallback(statusCode), nil + return newWriteBlockingHTMLPagePrologCallback(statusCode), nil } // The prolog callback modifies the function arguments in order to replace the // written status code and body. -func newWriteCustomErrorPagePrologCallback(statusCode int) httpprotection.NonBlockingPrologCallbackType { +func newWriteBlockingHTMLPagePrologCallback(statusCode int) httpprotection.NonBlockingPrologCallbackType { return func(m **httpprotection.ProtectionContext) (httpprotection.NonBlockingEpilogCallbackType, error) { ctx := *m // Note that the header must be written first since writing the body first // leads to the default OK status. ctx.ResponseWriter.WriteHeader(statusCode) - ctx.ResponseWriter.WriteString(blockedBySqreenPage) + // TODO: log error once + _, _ = ctx.ResponseWriter.WriteString(blockedBySqreenPage) return nil, nil } } diff --git a/internal/rule/callback/write-custom-error-page_test.go b/internal/rule/callback/write-blocking-html-page_test.go similarity index 96% rename from internal/rule/callback/write-custom-error-page_test.go rename to internal/rule/callback/write-blocking-html-page_test.go index 08d19f1e..f60e10c8 100644 --- a/internal/rule/callback/write-custom-error-page_test.go +++ b/internal/rule/callback/write-blocking-html-page_test.go @@ -6,7 +6,7 @@ package callback_test //func TestNewWriteCustomErrorPageCallbacks(t *testing.T) { // RunNativeCallbackTest(t, TestConfig{ -// CallbacksCtor: callback.NewWriteCustomErrorPageCallback, +// CallbacksCtor: callback.NewWriteBlockingHTMLPageCallback, // ExpectProlog: true, // PrologType: reflect.TypeOf(callback.WriteCustomErrorPagePrologCallbackType(nil)), // EpilogType: reflect.TypeOf(callback.WriteCustomErrorPageEpilogCallbackType(nil)), diff --git a/internal/rule/factory.go b/internal/rule/factory.go index a0214711..a8946261 100644 --- a/internal/rule/factory.go +++ b/internal/rule/factory.go @@ -19,8 +19,8 @@ func NewNativeCallback(name string, r callback.RuleContext, cfg callback.NativeC switch name { default: return nil, sqerrors.Errorf("undefined native callback name `%s`", name) - case "WriteCustomErrorPage": - callbackCtor = callback.NewWriteCustomErrorPageCallback + case "WriteCustomErrorPage", "WriteBlockingHTMLPage": + callbackCtor = callback.NewWriteBlockingHTMLPageCallback case "WriteHTTPRedirection": callbackCtor = callback.NewWriteHTTPRedirectionCallbacks case "AddSecurityHeaders": diff --git a/sdk/middleware/sqecho/echo.go b/sdk/middleware/sqecho/echo.go index 0c042f11..f90ced3e 100644 --- a/sdk/middleware/sqecho/echo.go +++ b/sdk/middleware/sqecho/echo.go @@ -92,7 +92,9 @@ func middlewareHandler(next echo.HandlerFunc, c echo.Context) error { return next(c) } - defer p.Close(responseWriter.closeResponseWriter()) + defer func() { + p.Close(responseWriter.closeResponseWriter()) + }() req = p.WrapRequest(req) c.SetRequest(req) diff --git a/sdk/middleware/sqgin/gin.go b/sdk/middleware/sqgin/gin.go index ce9bfc7b..e47d3be7 100644 --- a/sdk/middleware/sqgin/gin.go +++ b/sdk/middleware/sqgin/gin.go @@ -75,7 +75,9 @@ func middlewareHandler(c *gingonic.Context) { c.Next() return } - defer p.Close(responseWriter.closeResponseWriter()) + defer func() { + p.Close(responseWriter.closeResponseWriter()) + }() c.Request = p.WrapRequest(c.Request) c.Set(protection_context.ContextKey.String, p) diff --git a/sdk/middleware/sqhttp/http.go b/sdk/middleware/sqhttp/http.go index 38f22dc1..2c637591 100644 --- a/sdk/middleware/sqhttp/http.go +++ b/sdk/middleware/sqhttp/http.go @@ -65,7 +65,9 @@ func middlewareHandler(next http.Handler, w http.ResponseWriter, r *http.Request next.ServeHTTP(w, r) return } - defer p.Close(responseWriter.closeResponseWriter()) + defer func() { + p.Close(responseWriter.closeResponseWriter()) + }() requestReader.Request = p.WrapRequest(requestReader.Request)