Update hardcoded credentials rule for GenDecls

The hardcoded credentials rule will now also examine GenDecls so will
work with global vars and constants.

Fixes #74
This commit is contained in:
Grant Murphy 2016-11-13 12:57:59 -08:00
parent bf103da519
commit a3fcd96f57
2 changed files with 88 additions and 20 deletions

View file

@ -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
}
}
}
}
return
} }
func NewHardcodedCredentials(conf map[string]interface{}) (r gas.Rule, n ast.Node) { func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
r = &CredsAssign{ for _, i := range assign.Lhs {
pattern: regexp.MustCompile(`(?i)passwd|pass|password|pwd|secret|token`), 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 nil, nil
}
func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
if decl.Tok != token.CONST && decl.Tok != token.VAR {
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
} }

View file

@ -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")
}