mirror of
https://github.com/securego/gosec.git
synced 2024-12-26 04:25:52 +00:00
Merge pull request #83 from GoASTScanner/experimental
Adjust rule interface to allow interest in multiple ast node types
This commit is contained in:
commit
93016846d2
18 changed files with 157 additions and 122 deletions
|
@ -142,12 +142,14 @@ func (gas *Analyzer) process(filename string, source interface{}) error {
|
||||||
|
|
||||||
// AddRule adds a rule into a rule set list mapped to the given AST node's type.
|
// AddRule adds a rule into a rule set list mapped to the given AST node's type.
|
||||||
// The node is only needed for its type and is not otherwise used.
|
// The node is only needed for its type and is not otherwise used.
|
||||||
func (gas *Analyzer) AddRule(r Rule, n ast.Node) {
|
func (gas *Analyzer) AddRule(r Rule, nodes []ast.Node) {
|
||||||
t := reflect.TypeOf(n)
|
for _, n := range nodes {
|
||||||
if val, ok := gas.ruleset[t]; ok {
|
t := reflect.TypeOf(n)
|
||||||
gas.ruleset[t] = append(val, r)
|
if val, ok := gas.ruleset[t]; ok {
|
||||||
} else {
|
gas.ruleset[t] = append(val, r)
|
||||||
gas.ruleset[t] = []Rule{r}
|
} else {
|
||||||
|
gas.ruleset[t] = []Rule{r}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
type RuleInfo struct {
|
type RuleInfo struct {
|
||||||
description string
|
description string
|
||||||
build func(map[string]interface{}) (gas.Rule, ast.Node)
|
build func(map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFullRuleList get the full list of all rules available to GAS
|
// GetFullRuleList get the full list of all rules available to GAS
|
||||||
|
|
|
@ -39,8 +39,8 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BindsToAllNetworkInterfaces{
|
return &BindsToAllNetworkInterfaces{
|
||||||
call: regexp.MustCompile(`^net\.Listen$`),
|
call: regexp.MustCompile(`^net\.Listen$`),
|
||||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
@ -48,7 +48,5 @@ func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (r gas.Rule, n
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Binds to all network interfaces",
|
What: "Binds to all network interfaces",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,54 +34,46 @@ func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_md5(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
},
|
},
|
||||||
Path: `"crypto/md5"`,
|
Path: `"crypto/md5"`,
|
||||||
}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
n = (*ast.ImportSpec)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_des(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
},
|
},
|
||||||
Path: `"crypto/des"`,
|
Path: `"crypto/des"`,
|
||||||
}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
n = (*ast.ImportSpec)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
},
|
},
|
||||||
Path: `"crypto/rc4"`,
|
Path: `"crypto/rc4"`,
|
||||||
}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
n = (*ast.ImportSpec)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Go code running under CGI is vulnerable to Httpoxy attack. (CVE-2016-5386)",
|
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||||
},
|
},
|
||||||
Path: `"net/http/cgi"`,
|
Path: `"net/http/cgi"`,
|
||||||
}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
n = (*ast.ImportSpec)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,14 +50,12 @@ func (r *NoErrorCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNoErrorCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &NoErrorCheck{
|
return &NoErrorCheck{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.Low,
|
Severity: gas.Low,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Errors unhandled.",
|
What: "Errors unhandled.",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.AssignStmt)(nil)}
|
||||||
n = (*ast.AssignStmt)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFilePerms(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
mode := getConfiguredMode(conf, "G302", 0600)
|
mode := getConfiguredMode(conf, "G302", 0600)
|
||||||
return &FilePermissions{
|
return &FilePermissions{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
@ -63,10 +63,10 @@ func NewFilePerms(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
||||||
},
|
},
|
||||||
}, (*ast.CallExpr)(nil)
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
mode := getConfiguredMode(conf, "G301", 0700)
|
mode := getConfiguredMode(conf, "G301", 0700)
|
||||||
return &FilePermissions{
|
return &FilePermissions{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
@ -77,5 +77,5 @@ func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
||||||
},
|
},
|
||||||
}, (*ast.CallExpr)(nil)
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,43 +15,71 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CredsAssign struct {
|
type Credentials struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *CredsAssign) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||||
if node, ok := n.(*ast.AssignStmt); ok {
|
switch node := n.(type) {
|
||||||
for _, i := range node.Lhs {
|
case *ast.AssignStmt:
|
||||||
if ident, ok := i.(*ast.Ident); ok {
|
return r.matchAssign(node, ctx)
|
||||||
if r.pattern.MatchString(ident.Name) {
|
case *ast.GenDecl:
|
||||||
for _, e := range node.Rhs {
|
return r.matchGenDecl(node, ctx)
|
||||||
if _, ok := e.(*ast.BasicLit); ok {
|
}
|
||||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
|
||||||
|
for _, i := range assign.Lhs {
|
||||||
|
if ident, ok := i.(*ast.Ident); ok {
|
||||||
|
if r.pattern.MatchString(ident.Name) {
|
||||||
|
for _, e := range assign.Rhs {
|
||||||
|
if _, ok := e.(*ast.BasicLit); ok {
|
||||||
|
return gas.NewIssue(ctx, assign, r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHardcodedCredentials(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
|
||||||
r = &CredsAssign{
|
if decl.Tok != token.CONST && decl.Tok != token.VAR {
|
||||||
pattern: regexp.MustCompile(`(?i)passwd|pass|password|pwd|secret|token`),
|
return nil, nil
|
||||||
|
}
|
||||||
|
for _, spec := range decl.Specs {
|
||||||
|
if valueSpec, ok := spec.(*ast.ValueSpec); ok {
|
||||||
|
for index, ident := range valueSpec.Names {
|
||||||
|
if r.pattern.MatchString(ident.Name) {
|
||||||
|
if _, ok := valueSpec.Values[index].(*ast.BasicLit); ok {
|
||||||
|
return gas.NewIssue(ctx, decl, r.What, r.Severity, r.Confidence), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
|
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
||||||
|
if val, ok := conf["G101"]; ok {
|
||||||
|
pattern = val.(string)
|
||||||
|
}
|
||||||
|
return &Credentials{
|
||||||
|
pattern: regexp.MustCompile(pattern),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
What: "Potential hardcoded credentials",
|
What: "Potential hardcoded credentials",
|
||||||
Confidence: gas.Low,
|
Confidence: gas.Low,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.GenDecl)(nil)}
|
||||||
n = (*ast.AssignStmt)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,3 +39,43 @@ func TestHardcoded(t *testing.T) {
|
||||||
|
|
||||||
checkTestResults(t, issues, 1, "Potential hardcoded credentials")
|
checkTestResults(t, issues, 1, "Potential hardcoded credentials")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHardcodedGlobalVar(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewHardcodedCredentials(config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(`
|
||||||
|
package samples
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var password = "admin"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
username := "admin"
|
||||||
|
fmt.Println("Doing something with: ", username, password)
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Potential hardcoded credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHardcodedConstant(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewHardcodedCredentials(config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(`
|
||||||
|
package samples
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const password = "secret"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
username := "admin"
|
||||||
|
fmt.Println("Doing something with: ", username, password)
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Potential hardcoded credentials")
|
||||||
|
}
|
||||||
|
|
|
@ -32,5 +32,5 @@ func TestHttpoxy(t *testing.T) {
|
||||||
)
|
)
|
||||||
func main() {}`, analyzer)
|
func main() {}`, analyzer)
|
||||||
|
|
||||||
checkTestResults(t, issues, 1, "Go code running under CGI is vulnerable to Httpoxy attack.")
|
checkTestResults(t, issues, 1, "Go versions < 1.6.3 are vulnerable to Httpoxy")
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,8 @@ func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWeakRandCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewWeakRandCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &WeakRand{
|
return &WeakRand{
|
||||||
funcName: "Read",
|
funcName: "Read",
|
||||||
packagePath: "math/rand",
|
packagePath: "math/rand",
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
@ -43,7 +43,5 @@ func NewWeakRandCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
Confidence: gas.Medium,
|
Confidence: gas.Medium,
|
||||||
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWeakKeyStrength(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewWeakKeyStrength(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
bits := 2048
|
bits := 2048
|
||||||
r = &WeakKeyStrength{
|
return &WeakKeyStrength{
|
||||||
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
||||||
bits: bits,
|
bits: bits,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
@ -47,7 +47,5 @@ func NewWeakKeyStrength(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
16
rules/sql.go
16
rules/sql.go
|
@ -56,8 +56,8 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlStrConcat(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &SqlStrConcat{
|
return &SqlStrConcat{
|
||||||
SqlStatement: SqlStatement{
|
SqlStatement: SqlStatement{
|
||||||
pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
@ -66,9 +66,7 @@ func NewSqlStrConcat(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
What: "SQL string concatenation",
|
What: "SQL string concatenation",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.BinaryExpr)(nil)}
|
||||||
n = (*ast.BinaryExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqlStrFormat struct {
|
type SqlStrFormat struct {
|
||||||
|
@ -86,8 +84,8 @@ func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlStrFormat(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewSqlStrFormat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &SqlStrFormat{
|
return &SqlStrFormat{
|
||||||
call: regexp.MustCompile(`^fmt\.Sprintf$`),
|
call: regexp.MustCompile(`^fmt\.Sprintf$`),
|
||||||
SqlStatement: SqlStatement{
|
SqlStatement: SqlStatement{
|
||||||
pattern: regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
|
pattern: regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
|
||||||
|
@ -97,7 +95,5 @@ func NewSqlStrFormat(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
What: "SQL string formatting",
|
What: "SQL string formatting",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,8 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubproc(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &Subprocess{
|
return &Subprocess{
|
||||||
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBadTempFile(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewBadTempFile(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &BadTempFile{
|
return &BadTempFile{
|
||||||
call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`),
|
call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`),
|
||||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
@ -45,7 +45,5 @@ func NewBadTempFile(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,13 @@ func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err er
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTemplateCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewTemplateCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &TemplateCheck{
|
return &TemplateCheck{
|
||||||
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.Low,
|
Confidence: gas.Low,
|
||||||
What: "this method will not auto-escape HTML. Verify data is well formed.",
|
What: "this method will not auto-escape HTML. Verify data is well formed.",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
24
rules/tls.go
24
rules/tls.go
|
@ -109,9 +109,9 @@ func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModernTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
// https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||||
r = &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
MinVersion: 0x0303, // TLS 1.2 only
|
MinVersion: 0x0303, // TLS 1.2 only
|
||||||
MaxVersion: 0x0303,
|
MaxVersion: 0x0303,
|
||||||
|
@ -121,14 +121,12 @@ func NewModernTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
n = (*ast.CompositeLit)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIntermediateTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
// https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
||||||
r = &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||||
MaxVersion: 0x0303,
|
MaxVersion: 0x0303,
|
||||||
|
@ -149,14 +147,12 @@ func NewIntermediateTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Nod
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
n = (*ast.CompositeLit)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompatTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
// https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
||||||
r = &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||||
MaxVersion: 0x0303,
|
MaxVersion: 0x0303,
|
||||||
|
@ -179,7 +175,5 @@ func NewCompatTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
n = (*ast.CompositeLit)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,9 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UsingUnsafe struct {
|
type UsingUnsafe struct {
|
||||||
|
@ -33,15 +32,13 @@ func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUsingUnsafe(conf map[string]interface{}) (r gas.Rule, n ast.Node) {
|
func NewUsingUnsafe(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
r = &UsingUnsafe{
|
return &UsingUnsafe{
|
||||||
pattern: regexp.MustCompile(`unsafe\..*`),
|
pattern: regexp.MustCompile(`unsafe\..*`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
What: "Use of unsafe calls should be audited",
|
What: "Use of unsafe calls should be audited",
|
||||||
Severity: gas.Low,
|
Severity: gas.Low,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
},
|
},
|
||||||
}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
n = (*ast.CallExpr)(nil)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses des.* md5.* or rc4.*
|
// Uses des.* md5.* or rc4.*
|
||||||
func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
calls := make(map[string][]string)
|
calls := make(map[string][]string)
|
||||||
calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"}
|
calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"}
|
||||||
calls["crypto/md5"] = []string{"New", "Sum"}
|
calls["crypto/md5"] = []string{"New", "Sum"}
|
||||||
|
@ -49,5 +49,5 @@ func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, ast.Node) {
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return rule, (*ast.CallExpr)(nil)
|
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue