From 0c8e63ed86f8fc2da42787e0a653114490078d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Tue, 2 Aug 2022 18:16:44 +0300 Subject: [PATCH] Detect use of net/http functions that have no support for setting timeouts (#842) https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/ https://blog.cloudflare.com/exposing-go-on-the-internet/ Closes https://github.com/securego/gosec/issues/833 --- README.md | 1 + rules/http_serve.go | 38 ++++++++++++++++++++++ rules/rulelist.go | 1 + rules/rules_test.go | 4 +++ testutils/source.go | 78 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 rules/http_serve.go diff --git a/README.md b/README.md index d174c19..cc82439 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ directory you can supply `./...` as the input argument. - G111: Potential directory traversal - G112: Potential slowloris attack - G113: Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772) +- G114: Use of net/http serve function that has no support for setting timeouts - G201: SQL query construction using format string - G202: SQL query construction using string concatenation - G203: Use of unescaped data in HTML templates diff --git a/rules/http_serve.go b/rules/http_serve.go new file mode 100644 index 0000000..e460b3a --- /dev/null +++ b/rules/http_serve.go @@ -0,0 +1,38 @@ +package rules + +import ( + "go/ast" + + "github.com/securego/gosec/v2" +) + +type httpServeWithoutTimeouts struct { + gosec.MetaData + pkg string + calls []string +} + +func (r *httpServeWithoutTimeouts) ID() string { + return r.MetaData.ID +} + +func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { + if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + } + return nil, nil +} + +// NewHTTPServeWithoutTimeouts detects use of net/http serve functions that have no support for setting timeouts. +func NewHTTPServeWithoutTimeouts(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + return &httpServeWithoutTimeouts{ + pkg: "net/http", + calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"}, + MetaData: gosec.MetaData{ + ID: id, + What: "Use of net/http serve function that has no support for setting timeouts", + Severity: gosec.Medium, + Confidence: gosec.High, + }, + }, []ast.Node{(*ast.CallExpr)(nil)} +} diff --git a/rules/rulelist.go b/rules/rulelist.go index af8ea0d..b97813e 100644 --- a/rules/rulelist.go +++ b/rules/rulelist.go @@ -76,6 +76,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList { {"G111", "Detect http.Dir('/') as a potential risk", NewDirectoryTraversal}, {"G112", "Detect ReadHeaderTimeout not configured as a potential risk", NewSlowloris}, {"G113", "Usage of Rat.SetString in math/big with an overflow", NewUsingOldMathBig}, + {"G114", "Use of net/http serve function that has no support for setting timeouts", NewHTTPServeWithoutTimeouts}, // injection {"G201", "SQL query construction using format string", NewSQLStrFormat}, diff --git a/rules/rules_test.go b/rules/rules_test.go index abca817..c5a276f 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -102,6 +102,10 @@ var _ = Describe("gosec rules", func() { runner("G113", testutils.SampleCodeG113) }) + It("should detect uses of net/http serve functions that have no support for setting timeouts", func() { + runner("G114", testutils.SampleCodeG114) + }) + It("should detect sql injection via format strings", func() { runner("G201", testutils.SampleCodeG201) }) diff --git a/testutils/source.go b/testutils/source.go index c7688e7..e1124a4 100644 --- a/testutils/source.go +++ b/testutils/source.go @@ -1110,6 +1110,84 @@ func main() { }, 1, gosec.NewConfig()}, } + // SampleCodeG114 - Use of net/http serve functions that have no support for setting timeouts + SampleCodeG114 = []CodeSample{ + {[]string{ + ` +package main + +import ( + "log" + "net/http" +) + +func main() { + err := http.ListenAndServe(":8080", nil) + log.Fatal(err) +}`, + }, 1, gosec.NewConfig()}, + { + []string{ + ` +package main + +import ( + "log" + "net/http" +) + +func main() { + err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", nil) + log.Fatal(err) +}`, + }, 1, gosec.NewConfig(), + }, + { + []string{ + ` +package main + +import ( + "log" + "net" + "net/http" +) + +func main() { + l, err := net.Listen("tcp", ":8080") + if err != nil { + log.Fatal(err) + } + defer l.Close() + err = http.Serve(l, nil) + log.Fatal(err) +}`, + }, 1, gosec.NewConfig(), + }, + { + []string{ + ` +package main + +import ( + "log" + "net" + "net/http" +) + +func main() { + l, err := net.Listen("tcp", ":8443") + if err != nil { + log.Fatal(err) + } + defer l.Close() + err = http.ServeTLS(l, nil, "cert.pem", "key.pem") + log.Fatal(err) +}`, + }, 1, gosec.NewConfig(), + }, + } + // SampleCodeG201 - SQL injection via format string SampleCodeG201 = []CodeSample{ {[]string{`