From 713949fe690dd377517b55b7d04835f9692c5dd4 Mon Sep 17 00:00:00 2001 From: Tim Kelsey Date: Wed, 10 Aug 2016 12:51:03 +0100 Subject: [PATCH] Rule selection rules This makes the following changes: - riles are identified by an ID - include / exclude list now work - rules are selected based on these lists - blacklist rules are broken out into methods - rule constructors now take the config map - config file can be used to select rules - CLI options embelish config selection options --- main.go | 54 ++++++++----- rulelist.go | 116 +++++++++++++--------------- rules/bind.go | 5 +- rules/bind_test.go | 4 +- rules/blacklist.go | 83 ++++++++++++-------- rules/errors.go | 2 +- rules/errors_test.go | 6 +- rules/fileperms.go | 7 +- rules/fileperms_test.go | 4 +- rules/hardcoded_credentials.go | 2 +- rules/hardcoded_credentials_test.go | 2 +- rules/httpoxy_test.go | 2 +- rules/nosec_test.go | 6 +- rules/rand.go | 2 +- rules/rand_test.go | 4 +- rules/rsa.go | 2 +- rules/rsa_test.go | 2 +- rules/sql.go | 4 +- rules/sql_test.go | 20 ++--- rules/subproc.go | 2 +- rules/subproc_test.go | 8 +- rules/tempfiles.go | 5 +- rules/tempfiles_test.go | 2 +- rules/templates.go | 5 +- rules/templates_test.go | 8 +- rules/tls.go | 6 +- rules/tls_test.go | 8 +- rules/unsafe.go | 5 +- rules/unsafe_test.go | 2 +- rules/weakcrypto.go | 2 +- rules/weakcrypto_test.go | 12 +-- 31 files changed, 211 insertions(+), 181 deletions(-) diff --git a/main.go b/main.go index 4b2141a..8dcd411 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( "log" "os" "path/filepath" + "sort" "strings" gas "github.com/HewlettPackard/gas/core" @@ -61,15 +62,20 @@ USAGE: var logger *log.Logger -func extendConfList(conf map[string]interface{}, name string, input []string) { - if val, ok := conf[name]; ok { - if data, ok := val.(*[]string); ok { - conf[name] = append(*data, input...) - } else { - logger.Fatal("Config item must be a string list: ", name) - } - } else { +func extendConfList(conf map[string]interface{}, name string, inputStr string) { + if inputStr == "" { conf[name] = []string{} + } else { + input := strings.Split(inputStr, ",") + if val, ok := conf[name]; ok { + if data, ok := val.(*[]string); ok { + conf[name] = append(*data, input...) + } else { + logger.Fatal("Config item must be a string list: ", name) + } + } else { + conf[name] = input + } } } @@ -86,8 +92,8 @@ func buildConfig(incRules string, excRules string) map[string]interface{} { } // add in CLI include and exclude data - extendConfList(config, "include", strings.Split(incRules, ",")) - extendConfList(config, "exclude", strings.Split(excRules, ",")) + extendConfList(config, "include", incRules) + extendConfList(config, "exclude", excRules) // override ignoreNosec if given on CLI if flagIgnoreNoSec != nil { @@ -108,6 +114,20 @@ func usage() { fmt.Fprintln(os.Stderr, usageText) fmt.Fprint(os.Stderr, "OPTIONS:\n\n") flag.PrintDefaults() + fmt.Fprint(os.Stderr, "\n\nRULES:\n\n") + + // sorted rule list for eas of reading + rl := GetFullRuleList() + keys := make([]string, 0, len(rl)) + for key := range rl { + keys = append(keys, key) + } + sort.Strings(keys) + for _, k := range keys { + v := rl[k] + fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.description) + } + fmt.Fprint(os.Stderr, "\n") } func main() { @@ -119,15 +139,11 @@ func main() { var excluded filelist = []string{"*_test.go"} flag.Var(&excluded, "skip", "File pattern to exclude from scan") - // Rule configuration - rules := newRulelist() - flag.Var(&rules, "rule", "GAS rules enabled when performing a scan") - incRules := "" - flag.StringVar(&incRules, "include", "", "comma sperated list of rules to include") + flag.StringVar(&incRules, "include", "", "comma sperated list of rules IDs to include, see rule list") excRules := "" - flag.StringVar(&excRules, "exclude", "", "comma sperated list of rules to exclude") + flag.StringVar(&excRules, "exclude", "", "comma sperated list of rules IDs to exclude, see rule list") // Custom commands / utilities to run instead of default analyzer tools := newUtils() @@ -155,12 +171,8 @@ func main() { // Setup analyzer config := buildConfig(incRules, excRules) - analyzer := gas.NewAnalyzer(config, logger) - if !rules.overwritten { - rules.useDefaults() - } - rules.apply(&analyzer) + AddRules(&analyzer, config) // Traverse directory structure if './...' if flag.NArg() == 1 && flag.Arg(0) == "./..." { diff --git a/rulelist.go b/rulelist.go index 3aa6f31..2502122 100644 --- a/rulelist.go +++ b/rulelist.go @@ -17,85 +17,77 @@ package main import ( "fmt" "go/ast" - "strings" gas "github.com/HewlettPackard/gas/core" "github.com/HewlettPackard/gas/rules" ) -type ruleMaker func() (gas.Rule, ast.Node) -type ruleConfig struct { - enabled bool - constructors []ruleMaker +type RuleInfo struct { + description string + build func(map[string]interface{}) (gas.Rule, ast.Node) } -type rulelist struct { - rules map[string]*ruleConfig - overwritten bool -} +// GetFullRuleList get the full list of all rules available to GAS +func GetFullRuleList() map[string]RuleInfo { + return map[string]RuleInfo{ + // misc + "G101": RuleInfo{"hardcoded credentials", rules.NewHardcodedCredentials}, + "G102": RuleInfo{"bind to all interfaces", rules.NewBindsToAllNetworkInterfaces}, + "G103": RuleInfo{"use of unsafe block", rules.NewUsingUnsafe}, + "G104": RuleInfo{"errors not checked", rules.NewTemplateCheck}, -func newRulelist() rulelist { - var rs rulelist - rs.rules = make(map[string]*ruleConfig) - rs.overwritten = false - rs.register("sql", rules.NewSqlStrConcat, rules.NewSqlStrFormat) - rs.register("crypto", rules.NewUsesWeakCryptography) - rs.register("hardcoded", rules.NewHardcodedCredentials) - rs.register("perms", rules.NewMkdirPerms, rules.NewChmodPerms) - rs.register("tempfile", rules.NewBadTempFile) - rs.register("tls_good", rules.NewModernTlsCheck) - rs.register("tls_ok", rules.NewIntermediateTlsCheck) - rs.register("tls_old", rules.NewCompatTlsCheck) - rs.register("bind", rules.NewBindsToAllNetworkInterfaces) - rs.register("unsafe", rules.NewUsingUnsafe) - rs.register("rsa", rules.NewWeakKeyStrength) - rs.register("templates", rules.NewTemplateCheck) - rs.register("exec", rules.NewSubproc) - rs.register("errors", rules.NewNoErrorCheck) - rs.register("rand", rules.NewWeakRandCheck) - rs.register("blacklist_imports", rules.NewBlacklistImports) - return rs -} + // injection + "G201": RuleInfo{"sql string format", rules.NewSqlStrFormat}, + "G202": RuleInfo{"sql string concat", rules.NewSqlStrConcat}, + "G203": RuleInfo{"unescaped templates", rules.NewTemplateCheck}, + "G204": RuleInfo{"use of exec", rules.NewSubproc}, -func (r *rulelist) register(name string, cons ...ruleMaker) { - r.rules[name] = &ruleConfig{false, cons} -} + // filesystem + "G301": RuleInfo{"poor mkdir permissions", rules.NewMkdirPerms}, + "G302": RuleInfo{"poor chmod permisions", rules.NewChmodPerms}, + "G303": RuleInfo{"predicatable tempfile", rules.NewBadTempFile}, -func (r *rulelist) useDefaults() { - for k := range r.rules { - r.rules[k].enabled = true + // crypto + "G401": RuleInfo{"weak crypto", rules.NewUsesWeakCryptography}, + "G402": RuleInfo{"bad TLS options", rules.NewIntermediateTlsCheck}, + "G403": RuleInfo{"bad RSA key length", rules.NewWeakKeyStrength}, + "G404": RuleInfo{"poor random source (rand)", rules.NewWeakRandCheck}, + + // blacklist + "G501": RuleInfo{"blacklist: crypto/md5", rules.NewBlacklist_crypto_md5}, + "G502": RuleInfo{"blacklist: crypto/des", rules.NewBlacklist_crypto_des}, + "G503": RuleInfo{"blacklist: crypto/rc4", rules.NewBlacklist_crypto_rc4}, + "G504": RuleInfo{"blacklist: net/http/cgi", rules.NewBlacklist_net_http_cgi}, } } -func (r *rulelist) list() []string { - i := 0 - keys := make([]string, len(r.rules)) - for k := range r.rules { - keys[i] = k - i++ - } - return keys -} +func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) { + var all map[string]RuleInfo -func (r *rulelist) apply(g *gas.Analyzer) { - for _, v := range r.rules { - if v.enabled { - for _, ctor := range v.constructors { - g.AddRule(ctor()) + inc := conf["include"].([]string) + exc := conf["exclude"].([]string) + + fmt.Println(len(inc)) + + // add included rules + if len(inc) == 0 { + all = GetFullRuleList() + } else { + all = map[string]RuleInfo{} + tmp := GetFullRuleList() + for _, v := range inc { + if val, ok := tmp[v]; ok { + all[v] = val } } } -} -func (r *rulelist) String() string { - return strings.Join(r.list(), ", ") -} - -func (r *rulelist) Set(opt string) error { - r.overwritten = true - if x, ok := r.rules[opt]; ok { - x.enabled = true - return nil + // remove excluded rules + for _, v := range exc { + delete(all, v) + } + + for _, v := range all { + analyzer.AddRule(v.build(conf)) } - return fmt.Errorf("Valid rules are: %s", r) } diff --git a/rules/bind.go b/rules/bind.go index 4770608..f46285e 100644 --- a/rules/bind.go +++ b/rules/bind.go @@ -15,9 +15,10 @@ package rules import ( - gas "github.com/HewlettPackard/gas/core" "go/ast" "regexp" + + gas "github.com/HewlettPackard/gas/core" ) // Looks for net.Listen("0.0.0.0") or net.Listen(":8080") @@ -38,7 +39,7 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas return } -func NewBindsToAllNetworkInterfaces() (r gas.Rule, n ast.Node) { +func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &BindsToAllNetworkInterfaces{ call: regexp.MustCompile(`^net\.Listen$`), pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`), diff --git a/rules/bind_test.go b/rules/bind_test.go index 41787e4..a93a73f 100644 --- a/rules/bind_test.go +++ b/rules/bind_test.go @@ -23,7 +23,7 @@ import ( func TestBind0000(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBindsToAllNetworkInterfaces()) + analyzer.AddRule(NewBindsToAllNetworkInterfaces(config)) issues := gasTestRunner(` package main @@ -45,7 +45,7 @@ func TestBind0000(t *testing.T) { func TestBindEmptyHost(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBindsToAllNetworkInterfaces()) + analyzer.AddRule(NewBindsToAllNetworkInterfaces(config)) issues := gasTestRunner(` package main diff --git a/rules/blacklist.go b/rules/blacklist.go index 85505f5..04dc5c3 100644 --- a/rules/blacklist.go +++ b/rules/blacklist.go @@ -20,47 +20,68 @@ import ( gas "github.com/HewlettPackard/gas/core" ) -type BlacklistImports struct { - BlacklistSet map[string]gas.MetaData +type BlacklistImport struct { + gas.MetaData + Path string } -func (r *BlacklistImports) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) { +func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) { if node, ok := n.(*ast.ImportSpec); ok { - if data, ok := r.BlacklistSet[node.Path.Value]; ok { - return gas.NewIssue(c, n, data.What, data.Severity, data.Confidence), nil + if r.Path == node.Path.Value { + return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil } } return nil, nil } -func NewBlacklistImports() (r gas.Rule, n ast.Node) { - // TODO(tkelsey): make this configurable - // TODO(tkelsey): make it so each item can be selected/excluded individually - r = &BlacklistImports{ - BlacklistSet: map[string]gas.MetaData{ - `"crypto/md5"`: gas.MetaData{ - Severity: gas.High, - Confidence: gas.High, - What: "Use of weak cryptographic primitive", - }, - `"crypto/des"`: gas.MetaData{ - Severity: gas.High, - Confidence: gas.High, - What: "Use of weak cryptographic primitive", - }, - `"crypto/rc4"`: gas.MetaData{ - Severity: gas.High, - Confidence: gas.High, - What: "Use of weak cryptographic primitive", - }, - `"net/http/cgi"`: gas.MetaData{ - Severity: gas.High, - Confidence: gas.Low, - What: "Go code running under CGI is vulnerable to Httpoxy attack. (CVE-2016-5386)", - }, +func NewBlacklist_crypto_md5(conf map[string]interface{}) (r gas.Rule, n ast.Node) { + r = &BlacklistImport{ + MetaData: gas.MetaData{ + Severity: gas.High, + Confidence: gas.High, + What: "Use of weak cryptographic primitive", }, + Path: `"crypto/md5"`, + } + n = (*ast.ImportSpec)(nil) + return +} + +func NewBlacklist_crypto_des(conf map[string]interface{}) (r gas.Rule, n ast.Node) { + r = &BlacklistImport{ + MetaData: gas.MetaData{ + Severity: gas.High, + Confidence: gas.High, + What: "Use of weak cryptographic primitive", + }, + Path: `"crypto/des"`, + } + n = (*ast.ImportSpec)(nil) + return +} + +func NewBlacklist_crypto_rc4(conf map[string]interface{}) (r gas.Rule, n ast.Node) { + r = &BlacklistImport{ + MetaData: gas.MetaData{ + Severity: gas.High, + Confidence: gas.High, + What: "Use of weak cryptographic primitive", + }, + Path: `"crypto/rc4"`, + } + n = (*ast.ImportSpec)(nil) + return +} + +func NewBlacklist_net_http_cgi(conf map[string]interface{}) (r gas.Rule, n ast.Node) { + r = &BlacklistImport{ + MetaData: gas.MetaData{ + Severity: gas.High, + Confidence: gas.High, + What: "Go code running under CGI is vulnerable to Httpoxy attack. (CVE-2016-5386)", + }, + Path: `"net/http/cgi"`, } - n = (*ast.ImportSpec)(nil) return } diff --git a/rules/errors.go b/rules/errors.go index 75d6634..2951731 100644 --- a/rules/errors.go +++ b/rules/errors.go @@ -50,7 +50,7 @@ func (r *NoErrorCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err return nil, nil } -func NewNoErrorCheck() (r gas.Rule, n ast.Node) { +func NewNoErrorCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &NoErrorCheck{ MetaData: gas.MetaData{ Severity: gas.Low, diff --git a/rules/errors_test.go b/rules/errors_test.go index c644ad0..70c1861 100644 --- a/rules/errors_test.go +++ b/rules/errors_test.go @@ -23,7 +23,7 @@ import ( func TestErrorsMulti(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewNoErrorCheck()) + analyzer.AddRule(NewNoErrorCheck(config)) issues := gasTestRunner( `package main @@ -46,7 +46,7 @@ func TestErrorsMulti(t *testing.T) { func TestErrorsSingle(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewNoErrorCheck()) + analyzer.AddRule(NewNoErrorCheck(config)) issues := gasTestRunner( `package main @@ -69,7 +69,7 @@ func TestErrorsSingle(t *testing.T) { func TestErrorsGood(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewNoErrorCheck()) + analyzer.AddRule(NewNoErrorCheck(config)) issues := gasTestRunner( `package main diff --git a/rules/fileperms.go b/rules/fileperms.go index 1d7bafe..ea22e8b 100644 --- a/rules/fileperms.go +++ b/rules/fileperms.go @@ -16,9 +16,10 @@ package rules import ( "fmt" - gas "github.com/HewlettPackard/gas/core" "go/ast" "regexp" + + gas "github.com/HewlettPackard/gas/core" ) type FilePermissions struct { @@ -36,7 +37,7 @@ func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) return nil, nil } -func NewChmodPerms() (r gas.Rule, n ast.Node) { +func NewChmodPerms(conf map[string]interface{}) (r gas.Rule, n ast.Node) { mode := 0600 r = &FilePermissions{ pattern: regexp.MustCompile(`^os\.Chmod$`), @@ -51,7 +52,7 @@ func NewChmodPerms() (r gas.Rule, n ast.Node) { return } -func NewMkdirPerms() (r gas.Rule, n ast.Node) { +func NewMkdirPerms(conf map[string]interface{}) (r gas.Rule, n ast.Node) { mode := 0700 r = &FilePermissions{ pattern: regexp.MustCompile(`^(os\.Mkdir|os\.MkdirAll)$`), diff --git a/rules/fileperms_test.go b/rules/fileperms_test.go index 601f570..f70dbef 100644 --- a/rules/fileperms_test.go +++ b/rules/fileperms_test.go @@ -23,7 +23,7 @@ import ( func TestChmod(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewChmodPerms()) + analyzer.AddRule(NewChmodPerms(config)) issues := gasTestRunner(` package main @@ -39,7 +39,7 @@ func TestChmod(t *testing.T) { func TestMkdir(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewMkdirPerms()) + analyzer.AddRule(NewMkdirPerms(config)) issues := gasTestRunner(` package main diff --git a/rules/hardcoded_credentials.go b/rules/hardcoded_credentials.go index eecf85f..47f9f84 100644 --- a/rules/hardcoded_credentials.go +++ b/rules/hardcoded_credentials.go @@ -43,7 +43,7 @@ func (r *CredsAssign) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro return } -func NewHardcodedCredentials() (r gas.Rule, n ast.Node) { +func NewHardcodedCredentials(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &CredsAssign{ pattern: regexp.MustCompile(`(?i)passwd|pass|password|pwd|secret|token`), MetaData: gas.MetaData{ diff --git a/rules/hardcoded_credentials_test.go b/rules/hardcoded_credentials_test.go index 1d512a7..46e2211 100644 --- a/rules/hardcoded_credentials_test.go +++ b/rules/hardcoded_credentials_test.go @@ -23,7 +23,7 @@ import ( func TestHardcoded(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewHardcodedCredentials()) + analyzer.AddRule(NewHardcodedCredentials(config)) issues := gasTestRunner( ` diff --git a/rules/httpoxy_test.go b/rules/httpoxy_test.go index cdaefe8..90f4074 100644 --- a/rules/httpoxy_test.go +++ b/rules/httpoxy_test.go @@ -23,7 +23,7 @@ import ( func TestHttpoxy(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBlacklistImports()) + analyzer.AddRule(NewBlacklist_net_http_cgi(config)) issues := gasTestRunner(` package main diff --git a/rules/nosec_test.go b/rules/nosec_test.go index d0f7103..efbab8e 100644 --- a/rules/nosec_test.go +++ b/rules/nosec_test.go @@ -23,7 +23,7 @@ import ( func TestNosec(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner( `package main @@ -42,7 +42,7 @@ func TestNosec(t *testing.T) { func TestNosecBlock(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner( `package main @@ -64,7 +64,7 @@ func TestNosecBlock(t *testing.T) { func TestNosecIgnore(t *testing.T) { config := map[string]interface{}{"ignoreNosec": true} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner( `package main diff --git a/rules/rand.go b/rules/rand.go index 95c8b47..09cfbf4 100644 --- a/rules/rand.go +++ b/rules/rand.go @@ -39,7 +39,7 @@ func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewWeakRandCheck() (r gas.Rule, n ast.Node) { +func NewWeakRandCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &WeakRand{ pattern: regexp.MustCompile(`^rand\.Read$`), packageName: "rand", diff --git a/rules/rand_test.go b/rules/rand_test.go index 670b22c..93c1352 100644 --- a/rules/rand_test.go +++ b/rules/rand_test.go @@ -23,7 +23,7 @@ import ( func TestRandOk(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewWeakRandCheck()) + analyzer.AddRule(NewWeakRandCheck(config)) issues := gasTestRunner( ` @@ -41,7 +41,7 @@ func TestRandOk(t *testing.T) { func TestRandBad(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewWeakRandCheck()) + analyzer.AddRule(NewWeakRandCheck(config)) issues := gasTestRunner( ` diff --git a/rules/rsa.go b/rules/rsa.go index d2c640c..5a8d1d2 100644 --- a/rules/rsa.go +++ b/rules/rsa.go @@ -37,7 +37,7 @@ func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) return nil, nil } -func NewWeakKeyStrength() (r gas.Rule, n ast.Node) { +func NewWeakKeyStrength(conf map[string]interface{}) (r gas.Rule, n ast.Node) { bits := 2048 r = &WeakKeyStrength{ pattern: regexp.MustCompile(`^rsa\.GenerateKey$`), diff --git a/rules/rsa_test.go b/rules/rsa_test.go index 7988562..9a814d7 100644 --- a/rules/rsa_test.go +++ b/rules/rsa_test.go @@ -23,7 +23,7 @@ import ( func TestRSAKeys(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewWeakKeyStrength()) + analyzer.AddRule(NewWeakKeyStrength(config)) issues := gasTestRunner( `package main diff --git a/rules/sql.go b/rules/sql.go index 737f4e2..8b35317 100644 --- a/rules/sql.go +++ b/rules/sql.go @@ -56,7 +56,7 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewSqlStrConcat() (r gas.Rule, n ast.Node) { +func NewSqlStrConcat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &SqlStrConcat{ SqlStatement: SqlStatement{ pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `), @@ -86,7 +86,7 @@ func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err return nil, nil } -func NewSqlStrFormat() (r gas.Rule, n ast.Node) { +func NewSqlStrFormat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &SqlStrFormat{ call: regexp.MustCompile(`^fmt\.Sprintf$`), SqlStatement: SqlStatement{ diff --git a/rules/sql_test.go b/rules/sql_test.go index 2590230..174b829 100644 --- a/rules/sql_test.go +++ b/rules/sql_test.go @@ -23,7 +23,7 @@ import ( func TestSQLInjectionViaConcatenation(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrConcat()) + analyzer.AddRule(NewSqlStrConcat(config)) source := ` package main @@ -51,7 +51,7 @@ func TestSQLInjectionViaConcatenation(t *testing.T) { func TestSQLInjectionViaIntepolation(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrFormat()) + analyzer.AddRule(NewSqlStrFormat(config)) source := ` package main @@ -81,8 +81,8 @@ func TestSQLInjectionViaIntepolation(t *testing.T) { func TestSQLInjectionFalsePositiveA(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrConcat()) - analyzer.AddRule(NewSqlStrFormat()) + analyzer.AddRule(NewSqlStrConcat(config)) + analyzer.AddRule(NewSqlStrFormat(config)) source := ` @@ -117,8 +117,8 @@ func TestSQLInjectionFalsePositiveA(t *testing.T) { func TestSQLInjectionFalsePositiveB(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrConcat()) - analyzer.AddRule(NewSqlStrFormat()) + analyzer.AddRule(NewSqlStrConcat(config)) + analyzer.AddRule(NewSqlStrFormat(config)) source := ` @@ -153,8 +153,8 @@ func TestSQLInjectionFalsePositiveB(t *testing.T) { func TestSQLInjectionFalsePositiveC(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrConcat()) - analyzer.AddRule(NewSqlStrFormat()) + analyzer.AddRule(NewSqlStrConcat(config)) + analyzer.AddRule(NewSqlStrFormat(config)) source := ` @@ -189,8 +189,8 @@ func TestSQLInjectionFalsePositiveC(t *testing.T) { func TestSQLInjectionFalsePositiveD(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSqlStrConcat()) - analyzer.AddRule(NewSqlStrFormat()) + analyzer.AddRule(NewSqlStrConcat(config)) + analyzer.AddRule(NewSqlStrFormat(config)) source := ` diff --git a/rules/subproc.go b/rules/subproc.go index d47ae26..4ca567b 100644 --- a/rules/subproc.go +++ b/rules/subproc.go @@ -49,7 +49,7 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewSubproc() (r gas.Rule, n ast.Node) { +func NewSubproc(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &Subprocess{ pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`), } diff --git a/rules/subproc_test.go b/rules/subproc_test.go index d8199d4..f701653 100644 --- a/rules/subproc_test.go +++ b/rules/subproc_test.go @@ -23,7 +23,7 @@ import ( func TestSubprocess(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner(` package main @@ -51,7 +51,7 @@ func TestSubprocess(t *testing.T) { func TestSubprocessVar(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner(` package main @@ -79,7 +79,7 @@ func TestSubprocessVar(t *testing.T) { func TestSubprocessPath(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner(` package main @@ -106,7 +106,7 @@ func TestSubprocessPath(t *testing.T) { func TestSubprocessSyscall(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewSubproc()) + analyzer.AddRule(NewSubproc(config)) issues := gasTestRunner(` package main diff --git a/rules/tempfiles.go b/rules/tempfiles.go index c31b556..cd0df25 100644 --- a/rules/tempfiles.go +++ b/rules/tempfiles.go @@ -15,9 +15,10 @@ package rules import ( - gas "github.com/HewlettPackard/gas/core" "go/ast" "regexp" + + gas "github.com/HewlettPackard/gas/core" ) type BadTempFile struct { @@ -35,7 +36,7 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro return nil, nil } -func NewBadTempFile() (r gas.Rule, n ast.Node) { +func NewBadTempFile(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &BadTempFile{ call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`), args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`), diff --git a/rules/tempfiles_test.go b/rules/tempfiles_test.go index d3c019c..25ae3d5 100644 --- a/rules/tempfiles_test.go +++ b/rules/tempfiles_test.go @@ -23,7 +23,7 @@ import ( func TestTempfiles(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBadTempFile()) + analyzer.AddRule(NewBadTempFile(config)) source := ` package samples diff --git a/rules/templates.go b/rules/templates.go index 5b8a28b..ac537f2 100644 --- a/rules/templates.go +++ b/rules/templates.go @@ -15,9 +15,10 @@ package rules import ( - gas "github.com/HewlettPackard/gas/core" "go/ast" "regexp" + + gas "github.com/HewlettPackard/gas/core" ) type TemplateCheck struct { @@ -36,7 +37,7 @@ func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err er return nil, nil } -func NewTemplateCheck() (r gas.Rule, n ast.Node) { +func NewTemplateCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &TemplateCheck{ call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`), MetaData: gas.MetaData{ diff --git a/rules/templates_test.go b/rules/templates_test.go index 0185ef7..5bf788d 100644 --- a/rules/templates_test.go +++ b/rules/templates_test.go @@ -23,7 +23,7 @@ import ( func TestTemplateCheckSafe(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewTemplateCheck()) + analyzer.AddRule(NewTemplateCheck(config)) source := ` package samples @@ -51,7 +51,7 @@ func TestTemplateCheckSafe(t *testing.T) { func TestTemplateCheckBadHTML(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewTemplateCheck()) + analyzer.AddRule(NewTemplateCheck(config)) source := ` package samples @@ -80,7 +80,7 @@ func TestTemplateCheckBadHTML(t *testing.T) { func TestTemplateCheckBadJS(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewTemplateCheck()) + analyzer.AddRule(NewTemplateCheck(config)) source := ` package samples @@ -109,7 +109,7 @@ func TestTemplateCheckBadJS(t *testing.T) { func TestTemplateCheckBadURL(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewTemplateCheck()) + analyzer.AddRule(NewTemplateCheck(config)) source := ` package samples diff --git a/rules/tls.go b/rules/tls.go index 3d8b521..ee398ba 100644 --- a/rules/tls.go +++ b/rules/tls.go @@ -109,7 +109,7 @@ func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er return } -func NewModernTlsCheck() (r gas.Rule, n ast.Node) { +func NewModernTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility r = &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), @@ -126,7 +126,7 @@ func NewModernTlsCheck() (r gas.Rule, n ast.Node) { return } -func NewIntermediateTlsCheck() (r gas.Rule, n ast.Node) { +func NewIntermediateTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 r = &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), @@ -154,7 +154,7 @@ func NewIntermediateTlsCheck() (r gas.Rule, n ast.Node) { return } -func NewCompatTlsCheck() (r gas.Rule, n ast.Node) { +func NewCompatTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29 r = &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), diff --git a/rules/tls_test.go b/rules/tls_test.go index 2f9c797..bf9237e 100644 --- a/rules/tls_test.go +++ b/rules/tls_test.go @@ -23,7 +23,7 @@ import ( func TestInsecureSkipVerify(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewModernTlsCheck()) + analyzer.AddRule(NewModernTlsCheck(config)) issues := gasTestRunner(` package main @@ -52,7 +52,7 @@ func TestInsecureSkipVerify(t *testing.T) { func TestInsecureMinVersion(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewModernTlsCheck()) + analyzer.AddRule(NewModernTlsCheck(config)) issues := gasTestRunner(` package main @@ -81,7 +81,7 @@ func TestInsecureMinVersion(t *testing.T) { func TestInsecureMaxVersion(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewModernTlsCheck()) + analyzer.AddRule(NewModernTlsCheck(config)) issues := gasTestRunner(` package main @@ -110,7 +110,7 @@ func TestInsecureMaxVersion(t *testing.T) { func TestInsecureCipherSuite(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewModernTlsCheck()) + analyzer.AddRule(NewModernTlsCheck(config)) issues := gasTestRunner(` package main diff --git a/rules/unsafe.go b/rules/unsafe.go index 186db9c..1d89ea9 100644 --- a/rules/unsafe.go +++ b/rules/unsafe.go @@ -15,9 +15,10 @@ package rules import ( - gas "github.com/HewlettPackard/gas/core" "go/ast" "regexp" + + gas "github.com/HewlettPackard/gas/core" ) type UsingUnsafe struct { @@ -32,7 +33,7 @@ func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro return nil, nil } -func NewUsingUnsafe() (r gas.Rule, n ast.Node) { +func NewUsingUnsafe(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &UsingUnsafe{ pattern: regexp.MustCompile(`unsafe.*`), MetaData: gas.MetaData{ diff --git a/rules/unsafe_test.go b/rules/unsafe_test.go index 1dcbb3e..7714901 100644 --- a/rules/unsafe_test.go +++ b/rules/unsafe_test.go @@ -23,7 +23,7 @@ import ( func TestUnsafe(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewUsingUnsafe()) + analyzer.AddRule(NewUsingUnsafe(config)) issues := gasTestRunner(` package main diff --git a/rules/weakcrypto.go b/rules/weakcrypto.go index 7115195..c0bc552 100644 --- a/rules/weakcrypto.go +++ b/rules/weakcrypto.go @@ -34,7 +34,7 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er } // Uses des.* md5.* or rc4.* -func NewUsesWeakCryptography() (r gas.Rule, n ast.Node) { +func NewUsesWeakCryptography(conf map[string]interface{}) (r gas.Rule, n ast.Node) { r = &UsesWeakCryptography{ pattern: regexp.MustCompile(`des\.NewCipher|des\.NewTripleDESCipher|md5\.New|md5\.Sum|rc4\.NewCipher`), MetaData: gas.MetaData{ diff --git a/rules/weakcrypto_test.go b/rules/weakcrypto_test.go index 35070c6..8169387 100644 --- a/rules/weakcrypto_test.go +++ b/rules/weakcrypto_test.go @@ -23,8 +23,8 @@ import ( func TestMD5(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBlacklistImports()) - analyzer.AddRule(NewUsesWeakCryptography()) + analyzer.AddRule(NewBlacklist_crypto_md5(config)) + analyzer.AddRule(NewUsesWeakCryptography(config)) issues := gasTestRunner(` package main @@ -45,8 +45,8 @@ func TestMD5(t *testing.T) { func TestDES(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBlacklistImports()) - analyzer.AddRule(NewUsesWeakCryptography()) + analyzer.AddRule(NewBlacklist_crypto_des(config)) + analyzer.AddRule(NewUsesWeakCryptography(config)) issues := gasTestRunner(` package main @@ -85,8 +85,8 @@ func TestDES(t *testing.T) { func TestRC4(t *testing.T) { config := map[string]interface{}{"ignoreNosec": false} analyzer := gas.NewAnalyzer(config, nil) - analyzer.AddRule(NewBlacklistImports()) - analyzer.AddRule(NewUsesWeakCryptography()) + analyzer.AddRule(NewBlacklist_crypto_rc4(config)) + analyzer.AddRule(NewUsesWeakCryptography(config)) issues := gasTestRunner(` package main