diff --git a/v3/integrations/nrsecurityagent/go.mod b/v3/integrations/nrsecurityagent/go.mod index b85d8cea1..9d7e8b9f9 100644 --- a/v3/integrations/nrsecurityagent/go.mod +++ b/v3/integrations/nrsecurityagent/go.mod @@ -3,7 +3,7 @@ module github.com/newrelic/go-agent/v3/integrations/nrsecurityagent go 1.21 require ( - github.com/newrelic/csec-go-agent v1.4.0 + github.com/newrelic/csec-go-agent v1.5.0 github.com/newrelic/go-agent/v3 v3.35.0 github.com/newrelic/go-agent/v3/integrations/nrsqlite3 v1.2.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/v3/integrations/nrsecurityagent/nrsecurityagent.go b/v3/integrations/nrsecurityagent/nrsecurityagent.go index 224d1fe7f..79269f9be 100644 --- a/v3/integrations/nrsecurityagent/nrsecurityagent.go +++ b/v3/integrations/nrsecurityagent/nrsecurityagent.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "strconv" + "strings" securityAgent "github.com/newrelic/csec-go-agent" "github.com/newrelic/go-agent/v3/internal" @@ -31,6 +32,11 @@ func defaultSecurityConfig() SecurityConfig { cfg.Security.Agent.Enabled = true cfg.Security.Detection.Rxss.Enabled = true cfg.Security.Request.BodyLimit = 300 + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Header = make([]string, 0) + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Body = make([]string, 0) + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Query = make([]string, 0) + cfg.Security.ExcludeFromIastScan.API = make([]string, 0) + cfg.Security.ScanControllers.IastScanRequestRateLimit = 3600 return cfg } @@ -63,7 +69,7 @@ func InitSecurityAgent(app *newrelic.Application, opts ...ConfigOption) error { appConfig, isValid := app.Config() if !isValid { - return fmt.Errorf("Newrelic application value cannot be read; did you call newrelic.NewApplication?") + return fmt.Errorf("Newrelic application value cannot be read; did you call newrelic.NewApplication?") } app.UpdateSecurityConfig(c.Security) if !appConfig.HighSecurity && isSecurityAgentEnabled() { @@ -109,8 +115,24 @@ func ConfigSecurityFromYaml() ConfigOption { // NEW_RELIC_SECURITY_VALIDATOR_SERVICE_URL provides URL for the security validator service // NEW_RELIC_SECURITY_MODE scanning mode: "IAST" for now // NEW_RELIC_SECURITY_AGENT_ENABLED (boolean) -// NEW_RELIC_SECURITY_DETECTION_RXSS_ENABLED (boolean) // NEW_RELIC_SECURITY_REQUEST_BODY_LIMIT (integer) set limit on read request body in kb. By default, this is "300" +// +// NEW_RELIC_SECURITY_SCAN_SCHEDULE_DELAY (integer) The delay field indicated time in minutes before the IAST scan starts after the application starts. By default is 0 min. +// NEW_RELIC_SECURITY_SCAN_SCHEDULE_DURATION (integer) The duration field specifies the duration of the IAST scan in minutes. This determines how long the scan will run. By default is forever. +// NEW_RELIC_SECURITY_SCAN_SCHEDULE_SCHEDULE (string) The schedule field specifies a cron expression that defines when the IAST scan should run. +// NEW_RELIC_SECURITY_SCAN_SCHEDULE_ALWAYS_SAMPLE_TRACES (boolean) always_sample_traces permits IAST to actively gather trace data in the background, and the collected data will be used by Security Agent to perform an IAST Scan at the scheduled time. +// NEW_RELIC_SECURITY_SCAN_CONTROLLERS_IAST_SCAN_REQUEST_RATE_LIMIT (integer) The IAST Scan Rate Limit settings limit the maximum number of analysis probes or requests that can be sent to the application in a minute, By default is 3600. +// +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_INSECURE_SETTINGS (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_INVALID_FILE_ACCESS (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_SQL_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_NOSQL_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_LDAP_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_JAVASCRIPT_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_COMMAND_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_XPATH_INJECTION (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_SSRF (boolean) +// NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_RXSS (boolean) func ConfigSecurityFromEnvironment() ConfigOption { return func(cfg *SecurityConfig) { @@ -145,6 +167,37 @@ func ConfigSecurityFromEnvironment() ConfigOption { assignBool(&cfg.Security.Agent.Enabled, "NEW_RELIC_SECURITY_AGENT_ENABLED") assignBool(&cfg.Security.Detection.Rxss.Enabled, "NEW_RELIC_SECURITY_DETECTION_RXSS_ENABLED") assignInt(&cfg.Security.Request.BodyLimit, "NEW_RELIC_SECURITY_REQUEST_BODY_LIMIT") + + assignInt(&cfg.Security.ScanSchedule.Delay, "NEW_RELIC_SECURITY_SCAN_SCHEDULE_DELAY") + assignInt(&cfg.Security.ScanSchedule.Duration, "NEW_RELIC_SECURITY_SCAN_SCHEDULE_DURATION") + assignString(&cfg.Security.ScanSchedule.Schedule, "NEW_RELIC_SECURITY_SCAN_SCHEDULE_SCHEDULE") + assignBool(&cfg.Security.ScanSchedule.AllowIastSampleCollection, "NEW_RELIC_SECURITY_SCAN_SCHEDULE_ALWAYS_SAMPLE_TRACES") + assignInt(&cfg.Security.ScanControllers.IastScanRequestRateLimit, "NEW_RELIC_SECURITY_SCAN_CONTROLLERS_IAST_SCAN_REQUEST_RATE_LIMIT") + + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.InsecureSettings, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_INSECURE_SETTINGS") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.InvalidFileAccess, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_INVALID_FILE_ACCESS") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.SQLInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_SQL_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.NosqlInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_NOSQL_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.LdapInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_LDAP_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.JavascriptInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_JAVASCRIPT_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.CommandInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_COMMAND_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.XpathInjection, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_XPATH_INJECTION") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.Ssrf, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_SSRF") + assignBool(&cfg.Security.ExcludeFromIastScan.IastDetectionCategory.Rxss, "NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_IAST_DETECTION_CATEGORY_RXSS") + + if env := os.Getenv("NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_API"); env != "" { + cfg.Security.ExcludeFromIastScan.API = strings.Split(env, ",") + } + if env := os.Getenv("NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_HTTP_REQUEST_PARAMETERS_HEADER"); env != "" { + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Header = strings.Split(env, ",") + } + if env := os.Getenv("NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_HTTP_REQUEST_PARAMETERS_QUERY"); env != "" { + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Query = strings.Split(env, ",") + } + if env := os.Getenv("NEW_RELIC_SECURITY_EXCLUDE_FROM_IAST_SCAN_HTTP_REQUEST_PARAMETERS_BODY"); env != "" { + cfg.Security.ExcludeFromIastScan.HttpRequestParameters.Body = strings.Split(env, ",") + } + } } @@ -182,3 +235,43 @@ func ConfigSecurityRequestBodyLimit(bodyLimit int) ConfigOption { cfg.Security.Request.BodyLimit = bodyLimit } } + +// ConfigScanScheduleDelay is used to set delay for scan schedule. +// The delay field indicated time in minutes before the IAST scan starts after the application starts +func ConfigScanScheduleDelay(delay int) ConfigOption { + return func(cfg *SecurityConfig) { + cfg.Security.ScanSchedule.Delay = delay + } +} + +// ConfigScanScheduleDuration is used to set duration for scan schedule. +// The duration field specifies the duration of the IAST scan in minutes. This determines how long the scan will run. +func ConfigScanScheduleDuration(duration int) ConfigOption { + return func(cfg *SecurityConfig) { + cfg.Security.ScanSchedule.Duration = duration + } +} + +// ConfigScanScheduleSetSchedule is used to set schedule for scan schedule. +// The schedule field specifies a cron expression that defines when the IAST scan should run. +func ConfigScanScheduleSetSchedule(schedule string) ConfigOption { + return func(cfg *SecurityConfig) { + cfg.Security.ScanSchedule.Schedule = schedule + } +} + +// ConfigScanScheduleAllowIastSampleCollection is used to allow or disallow IAST sample collection +// always_sample_traces permits IAST to actively gather trace data in the background, and the collected data will be used by Security Agent to perform an IAST Scan at the scheduled time. +func ConfigScanScheduleAllowIastSampleCollection(isAllowed bool) ConfigOption { + return func(cfg *SecurityConfig) { + cfg.Security.ScanSchedule.AllowIastSampleCollection = isAllowed + } +} + +// ConfigScanControllersIastScanRequestRateLimit is used to set IAST scan request rate limit. +// The IAST Scan Rate Limit settings limit the maximum number of analysis probes or requests that can be sent to the application in a minute +func ConfigIastScanRequestRateLimit(limit int) ConfigOption { + return func(cfg *SecurityConfig) { + cfg.Security.ScanControllers.IastScanRequestRateLimit = limit + } +} diff --git a/v3/newrelic/transaction.go b/v3/newrelic/transaction.go index 8a17c985b..c432f0f32 100644 --- a/v3/newrelic/transaction.go +++ b/v3/newrelic/transaction.go @@ -269,7 +269,7 @@ func (txn *Transaction) SetWebRequest(r WebRequest) { return } if IsSecurityAgentPresent() { - secureAgent.SendEvent("INBOUND", r, txn.GetCsecAttributes()) + secureAgent.SendEvent("INBOUND", r, txn.GetCsecAttributes(), txn.GetLinkingMetadata().TraceID) } txn.thread.logAPIError(txn.thread.SetWebRequest(r), "set web request", nil) }