From c90fa75893fdea1aa7359f17e33a576aac44817a Mon Sep 17 00:00:00 2001 From: Mayank Pande Date: Thu, 18 Apr 2024 06:07:59 +0000 Subject: [PATCH] fix: sanitize headers based on header key --- containers/container.go | 1 - ebpftracer/l7/http.go | 55 +++++++++++------------------------------ flags/flags.go | 10 ++++---- 3 files changed, 20 insertions(+), 46 deletions(-) diff --git a/containers/container.go b/containers/container.go index fc65e849..83252b79 100644 --- a/containers/container.go +++ b/containers/container.go @@ -532,7 +532,6 @@ func ignoreControlPlane(name string) bool { } for _, keyword := range keywords { if strings.Contains(strings.ToLower(name), keyword) { - klog.Warningln("Ignoring control plane ", name) return true } } diff --git a/ebpftracer/l7/http.go b/ebpftracer/l7/http.go index 00ad08c4..14141b29 100644 --- a/ebpftracer/l7/http.go +++ b/ebpftracer/l7/http.go @@ -2,14 +2,12 @@ package l7 import ( "bytes" - "encoding/base64" "encoding/json" "errors" "io" "log" "net/http" "net/url" - "regexp" "strings" "github.com/coroot/coroot-node-agent/flags" @@ -70,7 +68,11 @@ func ParseHTTPRequest(data []byte) (*http.Request, error) { var header = http.Header{} var host = "" headerLines := bytes.Split(headers, []byte("\n")) - + sensitiveHeaders := make(map[string]bool) + sensitiveKeysList := strings.Split(*flags.SensitiveHeader, ",") + for _, key := range sensitiveKeysList { + sensitiveHeaders[strings.TrimSpace(key)] = true + } for _, line := range headerLines { part1, part2, ok := bytes.Cut(line, []byte(":")) if !ok { @@ -79,8 +81,12 @@ func ParseHTTPRequest(data []byte) (*http.Request, error) { if strings.HasPrefix(string(part1), "Host") { host = strings.TrimSpace(string(part2)) } + key := strings.TrimSpace(string(part1)) val := strings.TrimSpace(string(part2)) + if sensitiveHeaders[key] { + val = SanitizeString(val) + } header.Add(key, val) } req := &http.Request{ @@ -125,53 +131,22 @@ func ParseHostFromHttpRequest(input string) (string, error) { func ConvertHeadersToString(headers http.Header) string { headerMap := make(map[string][]string) - for key, values := range headers { - var sanitizedValues []string - for _, value := range values { - sanitizedValues = append(sanitizedValues, SanitizeString(value)) - } - headerMap[key] = sanitizedValues + headerMap[key] = values } - jsonString, err := json.Marshal(headerMap) if err != nil { return "" } - return string(jsonString) } -func SanitizeString(input string) string { +func SanitizeString(value string) string { if !*flags.SanitizeHeaders { - return input - } - patternList := strings.Split(*flags.SensitiveHeaderPattern, ",") - // Compile regex patterns - var sensitivePatterns []*regexp.Regexp - for _, pattern := range patternList { - // Trim leading and trailing whitespace from the pattern - pattern = strings.TrimSpace(pattern) - if len(pattern) > 0 { - // Compile each pattern and append to the list - sensitivePatterns = append(sensitivePatterns, regexp.MustCompile(pattern)) - } + return value } - - // Replace sensitive data with placeholder '*' - sanitized := input - for _, pattern := range sensitivePatterns { - sanitized = pattern.ReplaceAllStringFunc(sanitized, func(match string) string { - // Only replace the sensitive part, keeping the structure intact - sanitized_string := strings.Repeat("*", min(len(match), 5)) - log.Printf("Replacing %s with %s , using pattern %s", match, sanitized_string, pattern) - return sanitized_string - }) + if len(value) <= 10 { + return strings.Repeat("*", len(value)) } - - byteData := []byte(sanitized) - - // Encode byte slice to Base64 - base64String := base64.StdEncoding.EncodeToString(byteData) - return base64String + return strings.Repeat("*", 10) + value[10:] } diff --git a/flags/flags.go b/flags/flags.go index c6028976..ddfdb6d1 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -32,11 +32,11 @@ var ( ApiKey = kingpin.Flag("api-key", "Coroot API key").Envar("API_KEY").String() ScrapeInterval = kingpin.Flag("scrape-interval", "How often to gather metrics from the agent").Default("15s").Envar("SCRAPE_INTERVAL").Duration() - WalDir = kingpin.Flag("wal-dir", "Path to where the agent stores data (e.g. the metrics Write-Ahead Log)").Default("/tmp/coroot-node-agent").Envar("WAL_DIR").String() - ResolveDns = kingpin.Flag("resolve-dns", "should resolve DNS").Default("true").Envar("RESOLVE_DNS").Bool() - IgnoreControlPlane = kingpin.Flag("ignore-control-plane", "ignore control plane like loki").Default("karpenter,loki,prometheus,grafana,kubelet,etcd,apiserver,victoria").Envar("IGNORE_CONTROL_PLANE").String() - SensitiveHeaderPattern = kingpin.Flag("sensitive-header-patterns", "sanitize headers using patterns").Default("(?i)Authorization: (Bearer|Basic)\\s+[a-zA-Z0-9\\-_\\.\\=]+, (?i)ApiKey\\s+[a-zA-Z0-9\\-_\\.\\=]+, (?i)JWT\\s+[a-zA-Z0-9\\-_\\.\\=]+, (?i)OAuth\\s+[a-zA-Z0-9\\-_\\.\\=]+").Envar("SENSITIVE_HEADER_PATTERN").String() - SanitizeHeaders = kingpin.Flag("sanitize-headers", "should sanitize headers").Default("false").Envar("SANITIZE_HEADERS").Bool() + WalDir = kingpin.Flag("wal-dir", "Path to where the agent stores data (e.g. the metrics Write-Ahead Log)").Default("/tmp/coroot-node-agent").Envar("WAL_DIR").String() + ResolveDns = kingpin.Flag("resolve-dns", "should resolve DNS").Default("true").Envar("RESOLVE_DNS").Bool() + IgnoreControlPlane = kingpin.Flag("ignore-control-plane", "ignore control plane like loki").Default("karpenter,loki,prometheus,grafana,kubelet,etcd,apiserver,victoria").Envar("IGNORE_CONTROL_PLANE").String() + SanitizeHeaders = kingpin.Flag("sanitize-headers", "should sanitize headers").Default("true").Envar("SANITIZE_HEADERS").Bool() + SensitiveHeader = kingpin.Flag("sensitive-headers", "sanitize headers using patterns").Default("Authorization, Cookie").Envar("SENSITIVE_HEADERS").String() ) func GetString(fl *string) string {