mirror of
https://github.com/securego/gosec.git
synced 2024-12-26 04:25:52 +00:00
Add support for #excluding specific rules
This commit is contained in:
parent
6de76c9261
commit
37cada13f3
37 changed files with 487 additions and 150 deletions
|
@ -25,6 +25,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,10 +55,12 @@ type Context struct {
|
||||||
Root *ast.File
|
Root *ast.File
|
||||||
Config map[string]interface{}
|
Config map[string]interface{}
|
||||||
Imports *ImportInfo
|
Imports *ImportInfo
|
||||||
|
Ignores []map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Rule interface used by all rules supported by GAS.
|
// The Rule interface used by all rules supported by GAS.
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
|
ID() string
|
||||||
Match(ast.Node, *Context) (*Issue, error)
|
Match(ast.Node, *Context) (*Issue, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +96,7 @@ func NewAnalyzer(conf map[string]interface{}, logger *log.Logger) Analyzer {
|
||||||
a := Analyzer{
|
a := Analyzer{
|
||||||
ignoreNosec: conf["ignoreNosec"].(bool),
|
ignoreNosec: conf["ignoreNosec"].(bool),
|
||||||
ruleset: make(RuleSet),
|
ruleset: make(RuleSet),
|
||||||
context: &Context{nil, nil, nil, nil, nil, nil, nil},
|
context: &Context{nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
logger: logger,
|
logger: logger,
|
||||||
Issues: make([]*Issue, 0, 16),
|
Issues: make([]*Issue, 0, 16),
|
||||||
Stats: &Metrics{0, 0, 0, 0},
|
Stats: &Metrics{0, 0, 0, 0},
|
||||||
|
@ -180,22 +183,63 @@ func (gas *Analyzer) ProcessSource(filename string, source string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
|
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
|
||||||
func (gas *Analyzer) ignore(n ast.Node) bool {
|
func (gas *Analyzer) ignore(n ast.Node) ([]string, bool) {
|
||||||
if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec {
|
if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec {
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
if strings.Contains(group.Text(), "#nosec") {
|
if strings.Contains(group.Text(), "#nosec") {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(group.Text(), "#exclude") {
|
||||||
gas.Stats.NumNosec++
|
gas.Stats.NumNosec++
|
||||||
return true
|
|
||||||
|
// Pull out the specific rules that are listed to be ignored.
|
||||||
|
re := regexp.MustCompile("!(G\\d{3})")
|
||||||
|
matches := re.FindAllStringSubmatch(group.Text(), -1)
|
||||||
|
|
||||||
|
// Find the rule IDs to ignore.
|
||||||
|
ignores := make([]string, 0)
|
||||||
|
for _, v := range matches {
|
||||||
|
ignores = append(ignores, v[1])
|
||||||
|
}
|
||||||
|
return ignores, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit runs the GAS visitor logic over an AST created by parsing go code.
|
// Visit runs the GAS visitor logic over an AST created by parsing go code.
|
||||||
// Rule methods added with AddRule will be invoked as necessary.
|
// Rule methods added with AddRule will be invoked as necessary.
|
||||||
func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||||
if !gas.ignore(n) {
|
// If we've reached the end of this branch, pop off the ignores stack.
|
||||||
|
if n == nil {
|
||||||
|
if len(gas.context.Ignores) > 0 {
|
||||||
|
gas.context.Ignores = gas.context.Ignores[1:]
|
||||||
|
}
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any new rule exclusions.
|
||||||
|
ignoredRules, ignoreAll := gas.ignore(n)
|
||||||
|
if ignoreAll {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now create the union of exclusions.
|
||||||
|
ignores := make(map[string]bool, 0)
|
||||||
|
if len(gas.context.Ignores) > 0 {
|
||||||
|
for k, v := range gas.context.Ignores[0] {
|
||||||
|
ignores[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range ignoredRules {
|
||||||
|
ignores[v] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the new set onto the stack.
|
||||||
|
gas.context.Ignores = append([]map[string]bool{ignores}, gas.context.Ignores...)
|
||||||
|
|
||||||
// Track aliased and initialization imports
|
// Track aliased and initialization imports
|
||||||
if imported, ok := n.(*ast.ImportSpec); ok {
|
if imported, ok := n.(*ast.ImportSpec); ok {
|
||||||
|
@ -217,6 +261,9 @@ func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||||
|
|
||||||
if val, ok := gas.ruleset[reflect.TypeOf(n)]; ok {
|
if val, ok := gas.ruleset[reflect.TypeOf(n)]; ok {
|
||||||
for _, rule := range val {
|
for _, rule := range val {
|
||||||
|
if _, ok := ignores[rule.ID()]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
ret, err := rule.Match(n, gas.context)
|
ret, err := rule.Match(n, gas.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
file, line := GetLocation(n, gas.context)
|
file, line := GetLocation(n, gas.context)
|
||||||
|
@ -230,6 +277,4 @@ func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gas
|
return gas
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ type callListRule struct {
|
||||||
matched int
|
matched int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *callListRule) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *callListRule) Match(n ast.Node, c *Context) (gi *Issue, err error) {
|
func (r *callListRule) Match(n ast.Node, c *Context) (gi *Issue, err error) {
|
||||||
if r.callList.ContainsCallExpr(n, c) {
|
if r.callList.ContainsCallExpr(n, c) {
|
||||||
r.matched += 1
|
r.matched += 1
|
||||||
|
@ -25,6 +29,7 @@ func TestCallListContainsCallExpr(t *testing.T) {
|
||||||
calls.AddAll("bytes.Buffer", "Write", "WriteTo")
|
calls.AddAll("bytes.Buffer", "Write", "WriteTo")
|
||||||
rule := &callListRule{
|
rule := &callListRule{
|
||||||
MetaData: MetaData{
|
MetaData: MetaData{
|
||||||
|
ID: "TEST",
|
||||||
Severity: Low,
|
Severity: Low,
|
||||||
Confidence: Low,
|
Confidence: Low,
|
||||||
What: "A dummy rule",
|
What: "A dummy rule",
|
||||||
|
|
|
@ -16,6 +16,10 @@ type dummyRule struct {
|
||||||
matched int
|
matched int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *dummyRule) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *dummyRule) Match(n ast.Node, c *Context) (gi *Issue, err error) {
|
func (r *dummyRule) Match(n ast.Node, c *Context) (gi *Issue, err error) {
|
||||||
if callexpr, matched := r.callback(n, c, r.pkgOrType, r.funcsOrMethods...); matched {
|
if callexpr, matched := r.callback(n, c, r.pkgOrType, r.funcsOrMethods...); matched {
|
||||||
r.matched += 1
|
r.matched += 1
|
||||||
|
|
|
@ -42,6 +42,7 @@ type Issue struct {
|
||||||
// MetaData is embedded in all GAS rules. The Severity, Confidence and What message
|
// MetaData is embedded in all GAS rules. The Severity, Confidence and What message
|
||||||
// will be passed tbhrough to reported issues.
|
// will be passed tbhrough to reported issues.
|
||||||
type MetaData struct {
|
type MetaData struct {
|
||||||
|
ID string
|
||||||
Severity Score
|
Severity Score
|
||||||
Confidence Score
|
Confidence Score
|
||||||
What string
|
What string
|
||||||
|
|
54
rulelist.go
54
rulelist.go
|
@ -22,43 +22,49 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type RuleInfo struct {
|
type RuleInfo struct {
|
||||||
|
id string
|
||||||
description string
|
description string
|
||||||
build func(map[string]interface{}) (gas.Rule, []ast.Node)
|
build func(string, 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
|
||||||
func GetFullRuleList() map[string]RuleInfo {
|
func GetFullRuleList() map[string]RuleInfo {
|
||||||
return map[string]RuleInfo{
|
rules := []RuleInfo{
|
||||||
// misc
|
// misc
|
||||||
"G101": RuleInfo{"Look for hardcoded credentials", rules.NewHardcodedCredentials},
|
RuleInfo{"G101", "Look for hardcoded credentials", rules.NewHardcodedCredentials},
|
||||||
"G102": RuleInfo{"Bind to all interfaces", rules.NewBindsToAllNetworkInterfaces},
|
RuleInfo{"G102", "Bind to all interfaces", rules.NewBindsToAllNetworkInterfaces},
|
||||||
"G103": RuleInfo{"Audit the use of unsafe block", rules.NewUsingUnsafe},
|
RuleInfo{"G103", "Audit the use of unsafe block", rules.NewUsingUnsafe},
|
||||||
"G104": RuleInfo{"Audit errors not checked", rules.NewNoErrorCheck},
|
RuleInfo{"G104", "Audit errors not checked", rules.NewNoErrorCheck},
|
||||||
"G105": RuleInfo{"Audit the use of big.Exp function", rules.NewUsingBigExp},
|
RuleInfo{"G105", "Audit the use of big.Exp function", rules.NewUsingBigExp},
|
||||||
|
|
||||||
// injection
|
// injection
|
||||||
"G201": RuleInfo{"SQL query construction using format string", rules.NewSqlStrFormat},
|
RuleInfo{"G201", "SQL query construction using format string", rules.NewSqlStrFormat},
|
||||||
"G202": RuleInfo{"SQL query construction using string concatenation", rules.NewSqlStrConcat},
|
RuleInfo{"G202", "SQL query construction using string concatenation", rules.NewSqlStrConcat},
|
||||||
"G203": RuleInfo{"Use of unescaped data in HTML templates", rules.NewTemplateCheck},
|
RuleInfo{"G203", "Use of unescaped data in HTML templates", rules.NewTemplateCheck},
|
||||||
"G204": RuleInfo{"Audit use of command execution", rules.NewSubproc},
|
RuleInfo{"G204", "Audit use of command execution", rules.NewSubproc},
|
||||||
|
|
||||||
// filesystem
|
// filesystem
|
||||||
"G301": RuleInfo{"Poor file permissions used when creating a directory", rules.NewMkdirPerms},
|
RuleInfo{"G301", "Poor file permissions used when creating a directory", rules.NewMkdirPerms},
|
||||||
"G302": RuleInfo{"Poor file permisions used when creation file or using chmod", rules.NewFilePerms},
|
RuleInfo{"G302", "Poor file permisions used when creation file or using chmod", rules.NewFilePerms},
|
||||||
"G303": RuleInfo{"Creating tempfile using a predictable path", rules.NewBadTempFile},
|
RuleInfo{"G303", "Creating tempfile using a predictable path", rules.NewBadTempFile},
|
||||||
|
|
||||||
// crypto
|
// crypto
|
||||||
"G401": RuleInfo{"Detect the usage of DES, RC4, or MD5", rules.NewUsesWeakCryptography},
|
RuleInfo{"G401", "Detect the usage of DES, RC4, or MD5", rules.NewUsesWeakCryptography},
|
||||||
"G402": RuleInfo{"Look for bad TLS connection settings", rules.NewIntermediateTlsCheck},
|
RuleInfo{"G402", "Look for bad TLS connection settings", rules.NewIntermediateTlsCheck},
|
||||||
"G403": RuleInfo{"Ensure minimum RSA key length of 2048 bits", rules.NewWeakKeyStrength},
|
RuleInfo{"G403", "Ensure minimum RSA key length of 2048 bits", rules.NewWeakKeyStrength},
|
||||||
"G404": RuleInfo{"Insecure random number source (rand)", rules.NewWeakRandCheck},
|
RuleInfo{"G404", "Insecure random number source (rand)", rules.NewWeakRandCheck},
|
||||||
|
|
||||||
// blacklist
|
// blacklist
|
||||||
"G501": RuleInfo{"Import blacklist: crypto/md5", rules.NewBlacklist_crypto_md5},
|
RuleInfo{"G501", "Import blacklist: crypto/md5", rules.NewBlacklist_crypto_md5},
|
||||||
"G502": RuleInfo{"Import blacklist: crypto/des", rules.NewBlacklist_crypto_des},
|
RuleInfo{"G502", "Import blacklist: crypto/des", rules.NewBlacklist_crypto_des},
|
||||||
"G503": RuleInfo{"Import blacklist: crypto/rc4", rules.NewBlacklist_crypto_rc4},
|
RuleInfo{"G503", "Import blacklist: crypto/rc4", rules.NewBlacklist_crypto_rc4},
|
||||||
"G504": RuleInfo{"Import blacklist: net/http/cgi", rules.NewBlacklist_net_http_cgi},
|
RuleInfo{"G504", "Import blacklist: net/http/cgi", rules.NewBlacklist_net_http_cgi},
|
||||||
}
|
}
|
||||||
|
ruleMap := make(map[string]RuleInfo)
|
||||||
|
for _, v := range rules {
|
||||||
|
ruleMap[v.id] = v
|
||||||
|
}
|
||||||
|
return ruleMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) {
|
func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) {
|
||||||
|
@ -85,7 +91,7 @@ func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) {
|
||||||
delete(all, v)
|
delete(all, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range all {
|
for k, v := range all {
|
||||||
analyzer.AddRule(v.build(conf))
|
analyzer.AddRule(v.build(k, conf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
rules/big.go
10
rules/big.go
|
@ -15,8 +15,9 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UsingBigExp struct {
|
type UsingBigExp struct {
|
||||||
|
@ -25,17 +26,22 @@ type UsingBigExp struct {
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UsingBigExp) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *UsingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (r *UsingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||||
if _, matched := gas.MatchCallByType(n, c, r.pkg, r.calls...); matched {
|
if _, matched := gas.MatchCallByType(n, c, r.pkg, r.calls...); matched {
|
||||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func NewUsingBigExp(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewUsingBigExp(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &UsingBigExp{
|
return &UsingBigExp{
|
||||||
pkg: "*math/big.Int",
|
pkg: "*math/big.Int",
|
||||||
calls: []string{"Exp"},
|
calls: []string{"Exp"},
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
What: "Use of math/big.Int.Exp function should be audited for modulus == 0",
|
What: "Use of math/big.Int.Exp function should be audited for modulus == 0",
|
||||||
Severity: gas.Low,
|
Severity: gas.Low,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestBigExp(t *testing.T) {
|
func TestBigExp(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewUsingBigExp(config))
|
analyzer.AddRule(NewUsingBigExp("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -28,6 +28,10 @@ type BindsToAllNetworkInterfaces struct {
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *BindsToAllNetworkInterfaces) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||||
if node := gas.MatchCall(n, r.call); node != nil {
|
if node := gas.MatchCall(n, r.call); node != nil {
|
||||||
if arg, err := gas.GetString(node.Args[1]); err == nil {
|
if arg, err := gas.GetString(node.Args[1]); err == nil {
|
||||||
|
@ -39,11 +43,12 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewBindsToAllNetworkInterfaces(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &BindsToAllNetworkInterfaces{
|
return &BindsToAllNetworkInterfaces{
|
||||||
call: regexp.MustCompile(`^(net|tls)\.Listen$`),
|
call: regexp.MustCompile(`^(net|tls)\.Listen$`),
|
||||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Binds to all network interfaces",
|
What: "Binds to all network interfaces",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestBind0000(t *testing.T) {
|
func TestBind0000(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBindsToAllNetworkInterfaces(config))
|
analyzer.AddRule(NewBindsToAllNetworkInterfaces("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -45,7 +45,7 @@ func TestBind0000(t *testing.T) {
|
||||||
func TestBindEmptyHost(t *testing.T) {
|
func TestBindEmptyHost(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBindsToAllNetworkInterfaces(config))
|
analyzer.AddRule(NewBindsToAllNetworkInterfaces("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -25,6 +25,10 @@ type BlacklistImport struct {
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *BlacklistImport) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *BlacklistImport) 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 node, ok := n.(*ast.ImportSpec); ok {
|
||||||
if r.Path == node.Path.Value && node.Name.String() != "_" {
|
if r.Path == node.Path.Value && node.Name.String() != "_" {
|
||||||
|
@ -34,9 +38,10 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewBlacklist_crypto_md5(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
|
@ -45,9 +50,10 @@ func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewBlacklist_crypto_des(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
|
@ -56,9 +62,10 @@ func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewBlacklist_crypto_rc4(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
|
@ -67,9 +74,10 @@ func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewBlacklist_net_http_cgi(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &BlacklistImport{
|
return &BlacklistImport{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
const initOnlyImportSrc = `
|
const initOnlyImportSrc = `
|
||||||
|
@ -33,7 +34,7 @@ func main() {
|
||||||
func TestInitOnlyImport(t *testing.T) {
|
func TestInitOnlyImport(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBlacklist_crypto_md5(config))
|
analyzer.AddRule(NewBlacklist_crypto_md5("TEST", config))
|
||||||
issues := gasTestRunner(initOnlyImportSrc, analyzer)
|
issues := gasTestRunner(initOnlyImportSrc, analyzer)
|
||||||
checkTestResults(t, issues, 0, "")
|
checkTestResults(t, issues, 0, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NoErrorCheck struct {
|
type NoErrorCheck struct {
|
||||||
|
@ -25,6 +26,10 @@ type NoErrorCheck struct {
|
||||||
whitelist gas.CallList
|
whitelist gas.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *NoErrorCheck) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
||||||
if tv := ctx.Info.TypeOf(callExpr); tv != nil {
|
if tv := ctx.Info.TypeOf(callExpr); tv != nil {
|
||||||
switch t := tv.(type) {
|
switch t := tv.(type) {
|
||||||
|
@ -69,7 +74,7 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewNoErrorCheck(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
|
|
||||||
// TODO(gm) Come up with sensible defaults here. Or flip it to use a
|
// TODO(gm) Come up with sensible defaults here. Or flip it to use a
|
||||||
// black list instead.
|
// black list instead.
|
||||||
|
@ -87,6 +92,7 @@ func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
}
|
}
|
||||||
return &NoErrorCheck{
|
return &NoErrorCheck{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Low,
|
Severity: gas.Low,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Errors unhandled.",
|
What: "Errors unhandled.",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestErrorsMulti(t *testing.T) {
|
func TestErrorsMulti(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewNoErrorCheck(config))
|
analyzer.AddRule(NewNoErrorCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -47,7 +47,7 @@ func TestErrorsMulti(t *testing.T) {
|
||||||
func TestErrorsSingle(t *testing.T) {
|
func TestErrorsSingle(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewNoErrorCheck(config))
|
analyzer.AddRule(NewNoErrorCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -81,7 +81,7 @@ func TestErrorsSingle(t *testing.T) {
|
||||||
func TestErrorsGood(t *testing.T) {
|
func TestErrorsGood(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewNoErrorCheck(config))
|
analyzer.AddRule(NewNoErrorCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -110,7 +110,7 @@ func TestErrorsWhitelisted(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewNoErrorCheck(config))
|
analyzer.AddRule(NewNoErrorCheck("TEST", config))
|
||||||
source := `package main
|
source := `package main
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
|
@ -29,6 +29,10 @@ type FilePermissions struct {
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *FilePermissions) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
|
func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
|
||||||
var mode int64 = defaultMode
|
var mode int64 = defaultMode
|
||||||
if value, ok := conf[configKey]; ok {
|
if value, ok := conf[configKey]; ok {
|
||||||
|
@ -56,13 +60,14 @@ 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(id string, 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,
|
||||||
pkg: "os",
|
pkg: "os",
|
||||||
calls: []string{"OpenFile", "Chmod"},
|
calls: []string{"OpenFile", "Chmod"},
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
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),
|
||||||
|
@ -70,13 +75,14 @@ func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewMkdirPerms(id string, 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,
|
||||||
pkg: "os",
|
pkg: "os",
|
||||||
calls: []string{"Mkdir", "MkdirAll"},
|
calls: []string{"Mkdir", "MkdirAll"},
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
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),
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestChmod(t *testing.T) {
|
func TestChmod(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewFilePerms(config))
|
analyzer.AddRule(NewFilePerms("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -41,7 +41,7 @@ func TestChmod(t *testing.T) {
|
||||||
func TestMkdir(t *testing.T) {
|
func TestMkdir(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewMkdirPerms(config))
|
analyzer.AddRule(NewMkdirPerms("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/nbutton23/zxcvbn-go"
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
|
zxcvbn "github.com/nbutton23/zxcvbn-go"
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,6 +34,10 @@ type Credentials struct {
|
||||||
ignoreEntropy bool
|
ignoreEntropy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Credentials) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func truncate(s string, n int) string {
|
func truncate(s string, n int) string {
|
||||||
if n > len(s) {
|
if n > len(s) {
|
||||||
return s
|
return s
|
||||||
|
@ -100,7 +105,7 @@ func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Is
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewHardcodedCredentials(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
||||||
entropyThreshold := 80.0
|
entropyThreshold := 80.0
|
||||||
perCharThreshold := 3.0
|
perCharThreshold := 3.0
|
||||||
|
@ -140,6 +145,7 @@ func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
ignoreEntropy: ignoreEntropy,
|
ignoreEntropy: ignoreEntropy,
|
||||||
truncate: truncateString,
|
truncate: truncateString,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
What: "Potential hardcoded credentials",
|
What: "Potential hardcoded credentials",
|
||||||
Confidence: gas.Low,
|
Confidence: gas.Low,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestHardcoded(t *testing.T) {
|
func TestHardcoded(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
@ -43,7 +43,7 @@ func TestHardcoded(t *testing.T) {
|
||||||
func TestHardcodedWithEntropy(t *testing.T) {
|
func TestHardcodedWithEntropy(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
@ -68,7 +68,7 @@ func TestHardcodedIgnoreEntropy(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
@ -88,7 +88,7 @@ func TestHardcodedIgnoreEntropy(t *testing.T) {
|
||||||
func TestHardcodedGlobalVar(t *testing.T) {
|
func TestHardcodedGlobalVar(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package samples
|
package samples
|
||||||
|
@ -108,7 +108,7 @@ func TestHardcodedGlobalVar(t *testing.T) {
|
||||||
func TestHardcodedConstant(t *testing.T) {
|
func TestHardcodedConstant(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package samples
|
package samples
|
||||||
|
@ -128,7 +128,7 @@ func TestHardcodedConstant(t *testing.T) {
|
||||||
func TestHardcodedConstantMulti(t *testing.T) {
|
func TestHardcodedConstantMulti(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package samples
|
package samples
|
||||||
|
@ -150,7 +150,7 @@ func TestHardcodedConstantMulti(t *testing.T) {
|
||||||
func TestHardecodedVarsNotAssigned(t *testing.T) {
|
func TestHardecodedVarsNotAssigned(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
var password string
|
var password string
|
||||||
|
@ -163,7 +163,7 @@ func TestHardecodedVarsNotAssigned(t *testing.T) {
|
||||||
func TestHardcodedConstInteger(t *testing.T) {
|
func TestHardcodedConstInteger(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ func TestHardcodedConstInteger(t *testing.T) {
|
||||||
func TestHardcodedConstString(t *testing.T) {
|
func TestHardcodedConstString(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewHardcodedCredentials(config))
|
analyzer.AddRule(NewHardcodedCredentials("TEST", config))
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestHttpoxy(t *testing.T) {
|
func TestHttpoxy(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBlacklist_net_http_cgi(config))
|
analyzer.AddRule(NewBlacklist_net_http_cgi("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestNosec(t *testing.T) {
|
func TestNosec(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -43,7 +43,7 @@ func TestNosec(t *testing.T) {
|
||||||
func TestNosecBlock(t *testing.T) {
|
func TestNosecBlock(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -66,7 +66,7 @@ func TestNosecBlock(t *testing.T) {
|
||||||
func TestNosecIgnore(t *testing.T) {
|
func TestNosecIgnore(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": true}
|
config := map[string]interface{}{"ignoreNosec": true}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
@ -83,3 +83,176 @@ func TestNosecIgnore(t *testing.T) {
|
||||||
|
|
||||||
checkTestResults(t, issues, 1, "Subprocess launching with variable.")
|
checkTestResults(t, issues, 1, "Subprocess launching with variable.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeOne(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH")) // #exclude !G001
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 0, "None")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeOneNoMatch(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH")) // #exclude !G002
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Subprocess launching with variable.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeOneMatchNextLine(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("FOO")) // #exclude !G001
|
||||||
|
cmd = exec.Command("sh", "-c", os.Getenv("BAR"))
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Subprocess launching with variable.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecBlockExcludeOne(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// #exclude !G001
|
||||||
|
if true {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH"))
|
||||||
|
cmd.Run()
|
||||||
|
}
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 0, "None")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecBlockExcludeOneNoMatch(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// #exclude !G002
|
||||||
|
if true {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH"))
|
||||||
|
cmd.Run()
|
||||||
|
}
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Subprocess launching with variable.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeTwoNoMatch(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
analyzer.AddRule(NewWeakRandCheck("G002", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH"), string(rand.Int())) // #exclude !G003 !G004
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 2, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeTwoOneMatch(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
analyzer.AddRule(NewWeakRandCheck("G002", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH"), string(rand.Int())) // #exclude !G001 !G004
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 1, "Use of weak random number generator")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNosecExcludeTwoBothMatch(t *testing.T) {
|
||||||
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
|
analyzer.AddRule(NewSubproc("G001", config))
|
||||||
|
analyzer.AddRule(NewWeakRandCheck("G002", config))
|
||||||
|
|
||||||
|
issues := gasTestRunner(
|
||||||
|
`package main
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd := exec.Command("sh", "-c", os.Getenv("BLAH"), string(rand.Int())) // #exclude !G001 !G002
|
||||||
|
cmd.Run()
|
||||||
|
}`, analyzer)
|
||||||
|
|
||||||
|
checkTestResults(t, issues, 0, "No issues")
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ type WeakRand struct {
|
||||||
packagePath string
|
packagePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *WeakRand) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
for _, funcName := range w.funcNames {
|
for _, funcName := range w.funcNames {
|
||||||
if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
||||||
|
@ -36,11 +40,12 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewWeakRandCheck(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &WeakRand{
|
return &WeakRand{
|
||||||
funcNames: []string{"Read", "Int"},
|
funcNames: []string{"Read", "Int"},
|
||||||
packagePath: "math/rand",
|
packagePath: "math/rand",
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.High,
|
Severity: gas.High,
|
||||||
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)",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestRandOk(t *testing.T) {
|
func TestRandOk(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewWeakRandCheck(config))
|
analyzer.AddRule(NewWeakRandCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
@ -42,7 +42,7 @@ func TestRandOk(t *testing.T) {
|
||||||
func TestRandBad(t *testing.T) {
|
func TestRandBad(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewWeakRandCheck(config))
|
analyzer.AddRule(NewWeakRandCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
@ -62,7 +62,7 @@ func TestRandBad(t *testing.T) {
|
||||||
func TestRandRenamed(t *testing.T) {
|
func TestRandRenamed(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewWeakRandCheck(config))
|
analyzer.AddRule(NewWeakRandCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`
|
`
|
||||||
|
|
|
@ -28,6 +28,10 @@ type WeakKeyStrength struct {
|
||||||
bits int
|
bits int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *WeakKeyStrength) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
if node := gas.MatchCall(n, w.pattern); node != nil {
|
if node := gas.MatchCall(n, w.pattern); node != nil {
|
||||||
if bits, err := gas.GetInt(node.Args[1]); err == nil && bits < (int64)(w.bits) {
|
if bits, err := gas.GetInt(node.Args[1]); err == nil && bits < (int64)(w.bits) {
|
||||||
|
@ -37,12 +41,13 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewWeakKeyStrength(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
bits := 2048
|
bits := 2048
|
||||||
return &WeakKeyStrength{
|
return &WeakKeyStrength{
|
||||||
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
||||||
bits: bits,
|
bits: bits,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
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),
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestRSAKeys(t *testing.T) {
|
func TestRSAKeys(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewWeakKeyStrength(config))
|
analyzer.AddRule(NewWeakKeyStrength("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(
|
issues := gasTestRunner(
|
||||||
`package main
|
`package main
|
||||||
|
|
14
rules/sql.go
14
rules/sql.go
|
@ -30,6 +30,14 @@ type SqlStrConcat struct {
|
||||||
SqlStatement
|
SqlStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *SqlStatement) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SqlStrConcat) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
// see if we can figure out what it is
|
// see if we can figure out what it is
|
||||||
func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
|
func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||||
if n.Obj != nil {
|
if n.Obj != nil {
|
||||||
|
@ -56,11 +64,12 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewSqlStrConcat(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &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{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "SQL string concatenation",
|
What: "SQL string concatenation",
|
||||||
|
@ -84,12 +93,13 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewSqlStrFormat(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &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) "),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "SQL string formatting",
|
What: "SQL string formatting",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestSQLInjectionViaConcatenation(t *testing.T) {
|
func TestSQLInjectionViaConcatenation(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrConcat(config))
|
analyzer.AddRule(NewSqlStrConcat("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package main
|
package main
|
||||||
|
@ -51,7 +51,7 @@ func TestSQLInjectionViaConcatenation(t *testing.T) {
|
||||||
func TestSQLInjectionViaIntepolation(t *testing.T) {
|
func TestSQLInjectionViaIntepolation(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrFormat(config))
|
analyzer.AddRule(NewSqlStrFormat("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package main
|
package main
|
||||||
|
@ -81,8 +81,8 @@ func TestSQLInjectionViaIntepolation(t *testing.T) {
|
||||||
func TestSQLInjectionFalsePositiveA(t *testing.T) {
|
func TestSQLInjectionFalsePositiveA(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrConcat(config))
|
analyzer.AddRule(NewSqlStrConcat("TEST1", config))
|
||||||
analyzer.AddRule(NewSqlStrFormat(config))
|
analyzer.AddRule(NewSqlStrFormat("TEST2", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
|
|
||||||
|
@ -115,8 +115,8 @@ func TestSQLInjectionFalsePositiveA(t *testing.T) {
|
||||||
func TestSQLInjectionFalsePositiveB(t *testing.T) {
|
func TestSQLInjectionFalsePositiveB(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrConcat(config))
|
analyzer.AddRule(NewSqlStrConcat("TEST1", config))
|
||||||
analyzer.AddRule(NewSqlStrFormat(config))
|
analyzer.AddRule(NewSqlStrFormat("TEST2", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
|
|
||||||
|
@ -149,8 +149,8 @@ func TestSQLInjectionFalsePositiveB(t *testing.T) {
|
||||||
func TestSQLInjectionFalsePositiveC(t *testing.T) {
|
func TestSQLInjectionFalsePositiveC(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrConcat(config))
|
analyzer.AddRule(NewSqlStrConcat("TEST1", config))
|
||||||
analyzer.AddRule(NewSqlStrFormat(config))
|
analyzer.AddRule(NewSqlStrFormat("TEST2", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
|
|
||||||
|
@ -183,8 +183,8 @@ func TestSQLInjectionFalsePositiveC(t *testing.T) {
|
||||||
func TestSQLInjectionFalsePositiveD(t *testing.T) {
|
func TestSQLInjectionFalsePositiveD(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSqlStrConcat(config))
|
analyzer.AddRule(NewSqlStrConcat("TEST1", config))
|
||||||
analyzer.AddRule(NewSqlStrFormat(config))
|
analyzer.AddRule(NewSqlStrFormat("TEST2", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Subprocess struct {
|
type Subprocess struct {
|
||||||
|
gas.MetaData
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Subprocess) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
if node := gas.MatchCall(n, r.pattern); node != nil {
|
if node := gas.MatchCall(n, r.pattern); node != nil {
|
||||||
for _, arg := range node.Args {
|
for _, arg := range node.Args {
|
||||||
|
@ -43,14 +48,19 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
what := "Subprocess launching should be audited."
|
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||||
return gas.NewIssue(c, n, what, gas.Low, gas.High), nil
|
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewSubproc(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &Subprocess{
|
return &Subprocess{
|
||||||
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
||||||
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
|
Severity: gas.Low,
|
||||||
|
Confidence: gas.High,
|
||||||
|
What: "Subprocess launching should be audited.",
|
||||||
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestSubprocess(t *testing.T) {
|
func TestSubprocess(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -51,7 +51,7 @@ func TestSubprocess(t *testing.T) {
|
||||||
func TestSubprocessVar(t *testing.T) {
|
func TestSubprocessVar(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -80,7 +80,7 @@ func TestSubprocessVar(t *testing.T) {
|
||||||
func TestSubprocessPath(t *testing.T) {
|
func TestSubprocessPath(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -107,7 +107,7 @@ func TestSubprocessPath(t *testing.T) {
|
||||||
func TestSubprocessSyscall(t *testing.T) {
|
func TestSubprocessSyscall(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewSubproc(config))
|
analyzer.AddRule(NewSubproc("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -27,6 +27,10 @@ type BadTempFile struct {
|
||||||
call *regexp.Regexp
|
call *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *BadTempFile) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||||
if node := gas.MatchCall(n, t.call); node != nil {
|
if node := gas.MatchCall(n, t.call); node != nil {
|
||||||
if arg, e := gas.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil {
|
if arg, e := gas.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil {
|
||||||
|
@ -36,11 +40,12 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewBadTempFile(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &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{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
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",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestTempfiles(t *testing.T) {
|
func TestTempfiles(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBadTempFile(config))
|
analyzer.AddRule(NewBadTempFile("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package samples
|
package samples
|
||||||
|
|
|
@ -26,6 +26,10 @@ type TemplateCheck struct {
|
||||||
call *regexp.Regexp
|
call *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *TemplateCheck) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||||
if node := gas.MatchCall(n, t.call); node != nil {
|
if node := gas.MatchCall(n, t.call); node != nil {
|
||||||
for _, arg := range node.Args {
|
for _, arg := range node.Args {
|
||||||
|
@ -37,10 +41,11 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewTemplateCheck(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &TemplateCheck{
|
return &TemplateCheck{
|
||||||
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
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.",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestTemplateCheckSafe(t *testing.T) {
|
func TestTemplateCheckSafe(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewTemplateCheck(config))
|
analyzer.AddRule(NewTemplateCheck("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package samples
|
package samples
|
||||||
|
@ -51,7 +51,7 @@ func TestTemplateCheckSafe(t *testing.T) {
|
||||||
func TestTemplateCheckBadHTML(t *testing.T) {
|
func TestTemplateCheckBadHTML(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewTemplateCheck(config))
|
analyzer.AddRule(NewTemplateCheck("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package samples
|
package samples
|
||||||
|
@ -80,7 +80,7 @@ func TestTemplateCheckBadHTML(t *testing.T) {
|
||||||
func TestTemplateCheckBadJS(t *testing.T) {
|
func TestTemplateCheckBadJS(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewTemplateCheck(config))
|
analyzer.AddRule(NewTemplateCheck("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package samples
|
package samples
|
||||||
|
@ -109,7 +109,7 @@ func TestTemplateCheckBadJS(t *testing.T) {
|
||||||
func TestTemplateCheckBadURL(t *testing.T) {
|
func TestTemplateCheckBadURL(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewTemplateCheck(config))
|
analyzer.AddRule(NewTemplateCheck("TEST", config))
|
||||||
|
|
||||||
source := `
|
source := `
|
||||||
package samples
|
package samples
|
||||||
|
|
20
rules/tls.go
20
rules/tls.go
|
@ -24,12 +24,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type InsecureConfigTLS struct {
|
type InsecureConfigTLS struct {
|
||||||
|
gas.MetaData
|
||||||
MinVersion int16
|
MinVersion int16
|
||||||
MaxVersion int16
|
MaxVersion int16
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
goodCiphers []string
|
goodCiphers []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *InsecureConfigTLS) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func stringInSlice(a string, list []string) bool {
|
func stringInSlice(a string, list []string) bool {
|
||||||
for _, b := range list {
|
for _, b := range list {
|
||||||
if b == a {
|
if b == a {
|
||||||
|
@ -121,7 +126,7 @@ func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewModernTlsCheck(id string, 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
|
||||||
return &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
|
@ -135,10 +140,13 @@ func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||||
},
|
},
|
||||||
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
|
},
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewIntermediateTlsCheck(id string, 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
|
||||||
return &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
|
@ -161,10 +169,13 @@ func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []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",
|
||||||
},
|
},
|
||||||
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
|
},
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
func NewCompatTlsCheck(id string, 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
|
||||||
return &InsecureConfigTLS{
|
return &InsecureConfigTLS{
|
||||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||||
|
@ -189,5 +200,8 @@ func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []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",
|
||||||
},
|
},
|
||||||
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
|
},
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestInsecureSkipVerify(t *testing.T) {
|
func TestInsecureSkipVerify(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewModernTlsCheck(config))
|
analyzer.AddRule(NewModernTlsCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -52,7 +52,7 @@ func TestInsecureSkipVerify(t *testing.T) {
|
||||||
func TestInsecureMinVersion(t *testing.T) {
|
func TestInsecureMinVersion(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewModernTlsCheck(config))
|
analyzer.AddRule(NewModernTlsCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -81,7 +81,7 @@ func TestInsecureMinVersion(t *testing.T) {
|
||||||
func TestInsecureMaxVersion(t *testing.T) {
|
func TestInsecureMaxVersion(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewModernTlsCheck(config))
|
analyzer.AddRule(NewModernTlsCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -110,7 +110,7 @@ func TestInsecureMaxVersion(t *testing.T) {
|
||||||
func TestInsecureCipherSuite(t *testing.T) {
|
func TestInsecureCipherSuite(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewModernTlsCheck(config))
|
analyzer.AddRule(NewModernTlsCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -142,7 +142,7 @@ func TestInsecureCipherSuite(t *testing.T) {
|
||||||
func TestPreferServerCipherSuites(t *testing.T) {
|
func TestPreferServerCipherSuites(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewModernTlsCheck(config))
|
analyzer.AddRule(NewModernTlsCheck("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -15,8 +15,9 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gas "github.com/GoASTScanner/gas/core"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
|
gas "github.com/GoASTScanner/gas/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UsingUnsafe struct {
|
type UsingUnsafe struct {
|
||||||
|
@ -25,6 +26,10 @@ type UsingUnsafe struct {
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UsingUnsafe) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||||
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||||
|
@ -32,11 +37,12 @@ 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{}) (gas.Rule, []ast.Node) {
|
func NewUsingUnsafe(id string, conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||||
return &UsingUnsafe{
|
return &UsingUnsafe{
|
||||||
pkg: "unsafe",
|
pkg: "unsafe",
|
||||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
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,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
func TestUnsafe(t *testing.T) {
|
func TestUnsafe(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewUsingUnsafe(config))
|
analyzer.AddRule(NewUsingUnsafe("TEST", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
|
@ -25,6 +25,10 @@ type UsesWeakCryptography struct {
|
||||||
blacklist map[string][]string
|
blacklist map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UsesWeakCryptography) ID() string {
|
||||||
|
return r.MetaData.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
|
|
||||||
for pkg, funcs := range r.blacklist {
|
for pkg, funcs := range r.blacklist {
|
||||||
|
@ -36,7 +40,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(id string, 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"}
|
||||||
|
@ -44,6 +48,7 @@ func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||||
rule := &UsesWeakCryptography{
|
rule := &UsesWeakCryptography{
|
||||||
blacklist: calls,
|
blacklist: calls,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
ID: id,
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
func TestMD5(t *testing.T) {
|
func TestMD5(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBlacklist_crypto_md5(config))
|
analyzer.AddRule(NewBlacklist_crypto_md5("TEST1", config))
|
||||||
analyzer.AddRule(NewUsesWeakCryptography(config))
|
analyzer.AddRule(NewUsesWeakCryptography("TEST2", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -45,8 +45,8 @@ func TestMD5(t *testing.T) {
|
||||||
func TestDES(t *testing.T) {
|
func TestDES(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBlacklist_crypto_des(config))
|
analyzer.AddRule(NewBlacklist_crypto_des("TEST1", config))
|
||||||
analyzer.AddRule(NewUsesWeakCryptography(config))
|
analyzer.AddRule(NewUsesWeakCryptography("TEST2", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
@ -85,8 +85,8 @@ func TestDES(t *testing.T) {
|
||||||
func TestRC4(t *testing.T) {
|
func TestRC4(t *testing.T) {
|
||||||
config := map[string]interface{}{"ignoreNosec": false}
|
config := map[string]interface{}{"ignoreNosec": false}
|
||||||
analyzer := gas.NewAnalyzer(config, nil)
|
analyzer := gas.NewAnalyzer(config, nil)
|
||||||
analyzer.AddRule(NewBlacklist_crypto_rc4(config))
|
analyzer.AddRule(NewBlacklist_crypto_rc4("TEST1", config))
|
||||||
analyzer.AddRule(NewUsesWeakCryptography(config))
|
analyzer.AddRule(NewUsesWeakCryptography("TEST2", config))
|
||||||
|
|
||||||
issues := gasTestRunner(`
|
issues := gasTestRunner(`
|
||||||
package main
|
package main
|
||||||
|
|
Loading…
Reference in a new issue