1
0
mirror of https://github.com/prometheus-community/postgres_exporter.git synced 2025-08-08 04:42:07 +03:00

Refactor repository layout and convert build system to Mage.

This commit implements a massive refactor of the repository, and
moves the build system over to use Mage (magefile.org) which should
allow seamless building across multiple platforms.
This commit is contained in:
Will Rouesnel
2018-02-23 01:55:49 +11:00
parent 3e6cf08dc5
commit 989489096e
269 changed files with 35309 additions and 2017 deletions

View File

@@ -15,24 +15,27 @@
package rules
import (
gas "github.com/GoASTScanner/gas/core"
"go/ast"
"github.com/GoASTScanner/gas"
)
type UsingBigExp struct {
type usingBigExp struct {
gas.MetaData
pkg string
calls []string
}
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 {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
func NewUsingBigExp(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &UsingBigExp{
// NewUsingBigExp detects issues with modulus == 0 for Bignum
func NewUsingBigExp(conf gas.Config) (gas.Rule, []ast.Node) {
return &usingBigExp{
pkg: "*math/big.Int",
calls: []string{"Exp"},
MetaData: gas.MetaData{

View File

@@ -18,30 +18,37 @@ import (
"go/ast"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
type BindsToAllNetworkInterfaces struct {
type bindsToAllNetworkInterfaces struct {
gas.MetaData
call *regexp.Regexp
calls gas.CallList
pattern *regexp.Regexp
}
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 arg, err := gas.GetString(node.Args[1]); err == nil {
if r.pattern.MatchString(arg) {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
callExpr := r.calls.ContainsCallExpr(n, c)
if callExpr == nil {
return nil, nil
}
if arg, err := gas.GetString(callExpr.Args[1]); err == nil {
if r.pattern.MatchString(arg) {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
}
return
return nil, nil
}
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BindsToAllNetworkInterfaces{
call: regexp.MustCompile(`^(net|tls)\.Listen$`),
// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
// listen on all network interfaces.
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
calls := gas.NewCallList()
calls.Add("net", "Listen")
calls.Add("crypto/tls", "Listen")
return &bindsToAllNetworkInterfaces{
calls: calls,
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
MetaData: gas.MetaData{
Severity: gas.Medium,

View File

@@ -16,64 +16,67 @@ package rules
import (
"go/ast"
"strings"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type BlacklistImport struct {
type blacklistedImport struct {
gas.MetaData
Path string
Blacklisted map[string]string
}
func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
func unquote(original string) string {
copy := strings.TrimSpace(original)
copy = strings.TrimLeft(copy, `"`)
return strings.TrimRight(copy, `"`)
}
func (r *blacklistedImport) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node, ok := n.(*ast.ImportSpec); ok {
if r.Path == node.Path.Value && node.Name.String() != "_" {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
if description, ok := r.Blacklisted[unquote(node.Path.Value)]; ok {
return gas.NewIssue(c, node, description, r.Severity, r.Confidence), nil
}
}
return nil, nil
}
func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BlacklistImport{
// NewBlacklistedImports reports when a blacklisted import is being used.
// Typically when a deprecated technology is being used.
func NewBlacklistedImports(conf gas.Config, blacklist map[string]string) (gas.Rule, []ast.Node) {
return &blacklistedImport{
MetaData: gas.MetaData{
Severity: gas.High,
Severity: gas.Medium,
Confidence: gas.High,
What: "Use of weak cryptographic primitive",
},
Path: `"crypto/md5"`,
Blacklisted: blacklist,
}, []ast.Node{(*ast.ImportSpec)(nil)}
}
func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BlacklistImport{
MetaData: gas.MetaData{
Severity: gas.High,
Confidence: gas.High,
What: "Use of weak cryptographic primitive",
},
Path: `"crypto/des"`,
}, []ast.Node{(*ast.ImportSpec)(nil)}
// NewBlacklistedImportMD5 fails if MD5 is imported
func NewBlacklistedImportMD5(conf gas.Config) (gas.Rule, []ast.Node) {
return NewBlacklistedImports(conf, map[string]string{
"crypto/md5": "Blacklisted import crypto/md5: weak cryptographic primitive",
})
}
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BlacklistImport{
MetaData: gas.MetaData{
Severity: gas.High,
Confidence: gas.High,
What: "Use of weak cryptographic primitive",
},
Path: `"crypto/rc4"`,
}, []ast.Node{(*ast.ImportSpec)(nil)}
// NewBlacklistedImportDES fails if DES is imported
func NewBlacklistedImportDES(conf gas.Config) (gas.Rule, []ast.Node) {
return NewBlacklistedImports(conf, map[string]string{
"crypto/des": "Blacklisted import crypto/des: weak cryptographic primitive",
})
}
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BlacklistImport{
MetaData: gas.MetaData{
Severity: gas.High,
Confidence: gas.High,
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
},
Path: `"net/http/cgi"`,
}, []ast.Node{(*ast.ImportSpec)(nil)}
// NewBlacklistedImportRC4 fails if DES is imported
func NewBlacklistedImportRC4(conf gas.Config) (gas.Rule, []ast.Node) {
return NewBlacklistedImports(conf, map[string]string{
"crypto/rc4": "Blacklisted import crypto/rc4: weak cryptographic primitive",
})
}
// NewBlacklistedImportCGI fails if CGI is imported
func NewBlacklistedImportCGI(conf gas.Config) (gas.Rule, []ast.Node) {
return NewBlacklistedImports(conf, map[string]string{
"net/http/cgi": "Blacklisted import net/http/cgi: Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
})
}

View File

@@ -15,12 +15,13 @@
package rules
import (
gas "github.com/GoASTScanner/gas/core"
"go/ast"
"go/types"
"github.com/GoASTScanner/gas"
)
type NoErrorCheck struct {
type noErrorCheck struct {
gas.MetaData
whitelist gas.CallList
}
@@ -29,7 +30,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
if tv := ctx.Info.TypeOf(callExpr); tv != nil {
switch t := tv.(type) {
case *types.Tuple:
for pos := 0; pos < t.Len(); pos += 1 {
for pos := 0; pos < t.Len(); pos++ {
variable := t.At(pos)
if variable != nil && variable.Type().String() == "error" {
return pos
@@ -44,11 +45,11 @@ func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
return -1
}
func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
switch stmt := n.(type) {
case *ast.AssignStmt:
for _, expr := range stmt.Rhs {
if callExpr, ok := expr.(*ast.CallExpr); ok && !r.whitelist.ContainsCallExpr(callExpr, ctx) {
if callExpr, ok := expr.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(expr, ctx) == nil {
pos := returnsError(callExpr, ctx)
if pos < 0 || pos >= len(stmt.Lhs) {
return nil, nil
@@ -59,7 +60,7 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
}
}
case *ast.ExprStmt:
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && !r.whitelist.ContainsCallExpr(callExpr, ctx) {
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
pos := returnsError(callExpr, ctx)
if pos >= 0 {
return gas.NewIssue(ctx, n, r.What, r.Severity, r.Confidence), nil
@@ -69,13 +70,14 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
return nil, nil
}
func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// NewNoErrorCheck detects if the returned error is unchecked
func NewNoErrorCheck(conf gas.Config) (gas.Rule, []ast.Node) {
// TODO(gm) Come up with sensible defaults here. Or flip it to use a
// black list instead.
whitelist := gas.NewCallList()
whitelist.AddAll("bytes.Buffer", "Write", "WriteByte", "WriteRune", "WriteString")
whitelist.AddAll("fmt", "Print", "Printf", "Println")
whitelist.AddAll("fmt", "Print", "Printf", "Println", "Fprint", "Fprintf", "Fprintln")
whitelist.Add("io.PipeWriter", "CloseWithError")
if configured, ok := conf["G104"]; ok {
@@ -85,7 +87,7 @@ func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
}
}
}
return &NoErrorCheck{
return &noErrorCheck{
MetaData: gas.MetaData{
Severity: gas.Low,
Confidence: gas.High,

View File

@@ -19,10 +19,10 @@ import (
"go/ast"
"strconv"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type FilePermissions struct {
type filePermissions struct {
gas.MetaData
mode int64
pkg string
@@ -30,7 +30,7 @@ type FilePermissions struct {
}
func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
var mode int64 = defaultMode
var mode = defaultMode
if value, ok := conf[configKey]; ok {
switch value.(type) {
case int64:
@@ -46,7 +46,7 @@ func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMod
return mode
}
func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
func (r *filePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if callexpr, matched := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matched {
modeArg := callexpr.Args[len(callexpr.Args)-1]
if mode, err := gas.GetInt(modeArg); err == nil && mode > r.mode {
@@ -56,9 +56,11 @@ func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
return nil, nil
}
func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// NewFilePerms creates a rule to detect file creation with a more permissive than configured
// permission mask.
func NewFilePerms(conf gas.Config) (gas.Rule, []ast.Node) {
mode := getConfiguredMode(conf, "G302", 0600)
return &FilePermissions{
return &filePermissions{
mode: mode,
pkg: "os",
calls: []string{"OpenFile", "Chmod"},
@@ -70,9 +72,11 @@ func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
}, []ast.Node{(*ast.CallExpr)(nil)}
}
func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
mode := getConfiguredMode(conf, "G301", 0700)
return &FilePermissions{
// NewMkdirPerms creates a rule to detect directory creation with more permissive than
// configured permission mask.
func NewMkdirPerms(conf gas.Config) (gas.Rule, []ast.Node) {
mode := getConfiguredMode(conf, "G301", 0750)
return &filePermissions{
mode: mode,
pkg: "os",
calls: []string{"Mkdir", "MkdirAll"},

View File

@@ -15,16 +15,16 @@
package rules
import (
gas "github.com/GoASTScanner/gas/core"
"go/ast"
"go/token"
"regexp"
"github.com/nbutton23/zxcvbn-go"
"strconv"
"github.com/GoASTScanner/gas"
"github.com/nbutton23/zxcvbn-go"
)
type Credentials struct {
type credentials struct {
gas.MetaData
pattern *regexp.Regexp
entropyThreshold float64
@@ -40,7 +40,7 @@ func truncate(s string, n int) string {
return s[:n]
}
func (r *Credentials) isHighEntropyString(str string) bool {
func (r *credentials) isHighEntropyString(str string) bool {
s := truncate(str, r.truncate)
info := zxcvbn.PasswordStrength(s, []string{})
entropyPerChar := info.Entropy / float64(len(s))
@@ -49,7 +49,7 @@ func (r *Credentials) isHighEntropyString(str string) bool {
entropyPerChar >= r.perCharThreshold))
}
func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
func (r *credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
switch node := n.(type) {
case *ast.AssignStmt:
return r.matchAssign(node, ctx)
@@ -59,7 +59,7 @@ func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
return nil, nil
}
func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
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) {
@@ -76,7 +76,7 @@ func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*ga
return nil, nil
}
func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
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
}
@@ -100,12 +100,14 @@ func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Is
return nil, nil
}
func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// NewHardcodedCredentials attempts to find high entropy string constants being
// assigned to variables that appear to be related to credentials.
func NewHardcodedCredentials(conf gas.Config) (gas.Rule, []ast.Node) {
pattern := `(?i)passwd|pass|password|pwd|secret|token`
entropyThreshold := 80.0
perCharThreshold := 3.0
ignoreEntropy := false
var truncateString int = 16
var truncateString = 16
if val, ok := conf["G101"]; ok {
conf := val.(map[string]string)
if configPattern, ok := conf["pattern"]; ok {
@@ -133,7 +135,7 @@ func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node)
}
}
return &Credentials{
return &credentials{
pattern: regexp.MustCompile(pattern),
entropyThreshold: entropyThreshold,
perCharThreshold: perCharThreshold,

View File

@@ -17,16 +17,16 @@ package rules
import (
"go/ast"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type WeakRand struct {
type weakRand struct {
gas.MetaData
funcNames []string
packagePath string
}
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 {
if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
@@ -36,8 +36,9 @@ func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
return nil, nil
}
func NewWeakRandCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &WeakRand{
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
func NewWeakRandCheck(conf gas.Config) (gas.Rule, []ast.Node) {
return &weakRand{
funcNames: []string{"Read", "Int"},
packagePath: "math/rand",
MetaData: gas.MetaData{

View File

@@ -17,31 +17,33 @@ package rules
import (
"fmt"
"go/ast"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type WeakKeyStrength struct {
type weakKeyStrength struct {
gas.MetaData
pattern *regexp.Regexp
bits int
calls gas.CallList
bits int
}
func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node := gas.MatchCall(n, w.pattern); node != nil {
if bits, err := gas.GetInt(node.Args[1]); err == nil && bits < (int64)(w.bits) {
func (w *weakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if callExpr := w.calls.ContainsCallExpr(n, c); callExpr != nil {
if bits, err := gas.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
}
}
return nil, nil
}
func NewWeakKeyStrength(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
calls := gas.NewCallList()
calls.Add("crypto/rsa", "GenerateKey")
bits := 2048
return &WeakKeyStrength{
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
bits: bits,
return &weakKeyStrength{
calls: calls,
bits: bits,
MetaData: gas.MetaData{
Severity: gas.Medium,
Confidence: gas.High,

View File

@@ -0,0 +1,102 @@
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rules
import (
"github.com/GoASTScanner/gas"
)
// RuleDefinition contains the description of a rule and a mechanism to
// create it.
type RuleDefinition struct {
Description string
Create gas.RuleBuilder
}
// RuleList is a mapping of rule ID's to rule definitions
type RuleList map[string]RuleDefinition
// Builders returns all the create methods for a given rule list
func (rl RuleList) Builders() []gas.RuleBuilder {
builders := make([]gas.RuleBuilder, 0, len(rl))
for _, def := range rl {
builders = append(builders, def.Create)
}
return builders
}
// RuleFilter can be used to include or exclude a rule depending on the return
// value of the function
type RuleFilter func(string) bool
// NewRuleFilter is a closure that will include/exclude the rule ID's based on
// the supplied boolean value.
func NewRuleFilter(action bool, ruleIDs ...string) RuleFilter {
rulelist := make(map[string]bool)
for _, rule := range ruleIDs {
rulelist[rule] = true
}
return func(rule string) bool {
if _, found := rulelist[rule]; found {
return action
}
return !action
}
}
// Generate the list of rules to use
func Generate(filters ...RuleFilter) RuleList {
rules := map[string]RuleDefinition{
// misc
"G101": {"Look for hardcoded credentials", NewHardcodedCredentials},
"G102": {"Bind to all interfaces", NewBindsToAllNetworkInterfaces},
"G103": {"Audit the use of unsafe block", NewUsingUnsafe},
"G104": {"Audit errors not checked", NewNoErrorCheck},
"G105": {"Audit the use of big.Exp function", NewUsingBigExp},
"G106": {"Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey},
// injection
"G201": {"SQL query construction using format string", NewSQLStrFormat},
"G202": {"SQL query construction using string concatenation", NewSQLStrConcat},
"G203": {"Use of unescaped data in HTML templates", NewTemplateCheck},
"G204": {"Audit use of command execution", NewSubproc},
// filesystem
"G301": {"Poor file permissions used when creating a directory", NewMkdirPerms},
"G302": {"Poor file permisions used when creation file or using chmod", NewFilePerms},
"G303": {"Creating tempfile using a predictable path", NewBadTempFile},
// crypto
"G401": {"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
"G402": {"Look for bad TLS connection settings", NewIntermediateTLSCheck},
"G403": {"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
"G404": {"Insecure random number source (rand)", NewWeakRandCheck},
// blacklist
"G501": {"Import blacklist: crypto/md5", NewBlacklistedImportMD5},
"G502": {"Import blacklist: crypto/des", NewBlacklistedImportDES},
"G503": {"Import blacklist: crypto/rc4", NewBlacklistedImportRC4},
"G504": {"Import blacklist: net/http/cgi", NewBlacklistedImportCGI},
}
for rule := range rules {
for _, filter := range filters {
if filter(rule) {
delete(rules, rule)
}
}
}
return rules
}

View File

@@ -18,20 +18,32 @@ import (
"go/ast"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type SqlStatement struct {
type sqlStatement struct {
gas.MetaData
pattern *regexp.Regexp
// Contains a list of patterns which must all match for the rule to match.
patterns []*regexp.Regexp
}
type SqlStrConcat struct {
SqlStatement
// See if the string matches the patterns for the statement.
func (s sqlStatement) MatchPatterns(str string) bool {
for _, pattern := range s.patterns {
if !pattern.MatchString(str) {
return false
}
}
return true
}
type sqlStrConcat struct {
sqlStatement
}
// 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 {
return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
}
@@ -39,10 +51,13 @@ func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
}
// Look for "SELECT * FROM table WHERE " + " ' OR 1=1"
func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
func (s *sqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node, ok := n.(*ast.BinaryExpr); ok {
if start, ok := node.X.(*ast.BasicLit); ok {
if str, e := gas.GetString(start); s.pattern.MatchString(str) && e == nil {
if str, e := gas.GetString(start); e == nil {
if !s.MatchPatterns(str) {
return nil, nil
}
if _, ok := node.Y.(*ast.BasicLit); ok {
return nil, nil // string cat OK
}
@@ -56,10 +71,13 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
return nil, nil
}
func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &SqlStrConcat{
SqlStatement: SqlStatement{
pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
func NewSQLStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
return &sqlStrConcat{
sqlStatement: sqlStatement{
patterns: []*regexp.Regexp{
regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
},
MetaData: gas.MetaData{
Severity: gas.Medium,
Confidence: gas.High,
@@ -69,31 +87,39 @@ func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
}, []ast.Node{(*ast.BinaryExpr)(nil)}
}
type SqlStrFormat struct {
SqlStatement
call *regexp.Regexp
type sqlStrFormat struct {
sqlStatement
calls gas.CallList
}
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if node := gas.MatchCall(n, s.call); node != nil {
if arg, e := gas.GetString(node.Args[0]); s.pattern.MatchString(arg) && e == nil {
func (s *sqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
// TODO(gm) improve confidence if database/sql is being used
if node := s.calls.ContainsCallExpr(n, c); node != nil {
if arg, e := gas.GetString(node.Args[0]); s.MatchPatterns(arg) && e == nil {
return gas.NewIssue(c, n, s.What, s.Severity, s.Confidence), nil
}
}
return nil, nil
}
func NewSqlStrFormat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &SqlStrFormat{
call: regexp.MustCompile(`^fmt\.Sprintf$`),
SqlStatement: SqlStatement{
pattern: regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
func NewSQLStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
rule := &sqlStrFormat{
calls: gas.NewCallList(),
sqlStatement: sqlStatement{
patterns: []*regexp.Regexp{
regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
regexp.MustCompile("%[^bdoxXfFp]"),
},
MetaData: gas.MetaData{
Severity: gas.Medium,
Confidence: gas.High,
What: "SQL string formatting",
},
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}
rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln")
return rule, []ast.Node{(*ast.CallExpr)(nil)}
}

33
tools/vendor/github.com/GoASTScanner/gas/rules/ssh.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package rules
import (
"go/ast"
"github.com/GoASTScanner/gas"
)
type sshHostKey struct {
gas.MetaData
pkg string
calls []string
}
func (r *sshHostKey) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
// NewSSHHostKey rule detects the use of insecure ssh HostKeyCallback.
func NewSSHHostKey(conf gas.Config) (gas.Rule, []ast.Node) {
return &sshHostKey{
pkg: "golang.org/x/crypto/ssh",
calls: []string{"InsecureIgnoreHostKey"},
MetaData: gas.MetaData{
What: "Use of ssh InsecureIgnoreHostKey should be audited",
Severity: gas.Medium,
Confidence: gas.High,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -16,41 +16,43 @@ package rules
import (
"go/ast"
"regexp"
"strings"
"go/types"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type Subprocess struct {
pattern *regexp.Regexp
type subprocess struct {
gas.CallList
}
func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node := gas.MatchCall(n, r.pattern); node != nil {
// TODO(gm) The only real potential for command injection with a Go project
// is something like this:
//
// syscall.Exec("/bin/sh", []string{"-c", tainted})
//
// E.g. Input is correctly escaped but the execution context being used
// is unsafe. For example:
//
// syscall.Exec("echo", "foobar" + tainted)
func (r *subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node := r.ContainsCallExpr(n, c); node != nil {
for _, arg := range node.Args {
if !gas.TryResolve(arg, c) {
what := "Subprocess launching with variable."
return gas.NewIssue(c, n, what, gas.High, gas.High), nil
if ident, ok := arg.(*ast.Ident); ok {
obj := c.Info.ObjectOf(ident)
if _, ok := obj.(*types.Var); ok && !gas.TryResolve(ident, c) {
return gas.NewIssue(c, n, "Subprocess launched with variable", gas.Medium, gas.High), nil
}
}
}
// call with partially qualified command
if str, err := gas.GetString(node.Args[0]); err == nil {
if !strings.HasPrefix(str, "/") {
what := "Subprocess launching with partial path."
return gas.NewIssue(c, n, what, gas.Medium, gas.High), nil
}
}
what := "Subprocess launching should be audited."
return gas.NewIssue(c, n, what, gas.Low, gas.High), nil
return gas.NewIssue(c, n, "Subprocess launching should be audited", gas.Low, gas.High), nil
}
return nil, nil
}
func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &Subprocess{
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
}, []ast.Node{(*ast.CallExpr)(nil)}
// NewSubproc detects cases where we are forking out to an external process
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
rule := &subprocess{gas.NewCallList()}
rule.Add("os/exec", "Command")
rule.Add("syscall", "Exec")
return rule, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -18,17 +18,17 @@ import (
"go/ast"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type BadTempFile struct {
type badTempFile struct {
gas.MetaData
args *regexp.Regexp
call *regexp.Regexp
calls gas.CallList
args *regexp.Regexp
}
func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if node := gas.MatchCall(n, t.call); node != nil {
func (t *badTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if node := t.calls.ContainsCallExpr(n, c); node != nil {
if arg, e := gas.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil {
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
}
@@ -36,10 +36,14 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
return nil, nil
}
func NewBadTempFile(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &BadTempFile{
call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`),
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
// NewBadTempFile detects direct writes to predictable path in temporary directory
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
calls := gas.NewCallList()
calls.Add("io/ioutil", "WriteFile")
calls.Add("os", "Create")
return &badTempFile{
calls: calls,
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
MetaData: gas.MetaData{
Severity: gas.Medium,
Confidence: gas.High,

View File

@@ -16,18 +16,17 @@ package rules
import (
"go/ast"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type TemplateCheck struct {
type templateCheck struct {
gas.MetaData
call *regexp.Regexp
calls gas.CallList
}
func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if node := gas.MatchCall(n, t.call); node != nil {
func (t *templateCheck) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if node := t.calls.ContainsCallExpr(n, c); node != nil {
for _, arg := range node.Args {
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
@@ -37,9 +36,17 @@ func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err er
return nil, nil
}
func NewTemplateCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &TemplateCheck{
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
// NewTemplateCheck constructs the template check rule. This rule is used to
// find use of tempaltes where HTML/JS escaping is not being used
func NewTemplateCheck(conf gas.Config) (gas.Rule, []ast.Node) {
calls := gas.NewCallList()
calls.Add("html/template", "HTML")
calls.Add("html/template", "HTMLAttr")
calls.Add("html/template", "JS")
calls.Add("html/template", "URL")
return &templateCheck{
calls: calls,
MetaData: gas.MetaData{
Severity: gas.Medium,
Confidence: gas.Low,

View File

@@ -12,22 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate tlsconfig
package rules
import (
"fmt"
"go/ast"
"reflect"
"regexp"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type InsecureConfigTLS struct {
MinVersion int16
MaxVersion int16
pattern *regexp.Regexp
goodCiphers []string
type insecureConfigTLS struct {
MinVersion int16
MaxVersion int16
requiredType string
goodCiphers []string
}
func stringInSlice(a string, list []string) bool {
@@ -39,15 +39,14 @@ func stringInSlice(a string, list []string) bool {
return false
}
func (t *InsecureConfigTLS) processTlsCipherSuites(n ast.Node, c *gas.Context) *gas.Issue {
a := reflect.TypeOf(&ast.KeyValueExpr{})
b := reflect.TypeOf(&ast.CompositeLit{})
if node, ok := gas.SimpleSelect(n, a, b).(*ast.CompositeLit); ok {
for _, elt := range node.Elts {
if ident, ok := elt.(*ast.SelectorExpr); ok {
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gas.Context) *gas.Issue {
if ciphers, ok := n.(*ast.CompositeLit); ok {
for _, cipher := range ciphers.Elts {
if ident, ok := cipher.(*ast.SelectorExpr); ok {
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
str := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
return gas.NewIssue(c, n, str, gas.High, gas.High)
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
return gas.NewIssue(c, ident, err, gas.High, gas.High)
}
}
}
@@ -55,9 +54,10 @@ func (t *InsecureConfigTLS) processTlsCipherSuites(n ast.Node, c *gas.Context) *
return nil
}
func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Context) *gas.Issue {
func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gas.Context) *gas.Issue {
if ident, ok := n.Key.(*ast.Ident); ok {
switch ident.Name {
case "InsecureSkipVerify":
if node, ok := n.Value.(*ast.Ident); ok {
if node.Name != "false" {
@@ -97,7 +97,7 @@ func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Contex
}
case "CipherSuites":
if ret := t.processTlsCipherSuites(n, c); ret != nil {
if ret := t.processTLSCipherSuites(n.Value, c); ret != nil {
return ret
}
@@ -107,85 +107,19 @@ func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Contex
return nil
}
func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
if node := gas.MatchCompLit(n, t.pattern); node != nil {
for _, elt := range node.Elts {
if kve, ok := elt.(*ast.KeyValueExpr); ok {
gi = t.processTlsConfVal(kve, c)
if gi != nil {
break
func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
actualType := c.Info.TypeOf(complit.Type)
if actualType != nil && actualType.String() == t.requiredType {
for _, elt := range complit.Elts {
if kve, ok := elt.(*ast.KeyValueExpr); ok {
issue := t.processTLSConfVal(kve, c)
if issue != nil {
return issue, nil
}
}
}
}
}
return
}
func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
return &InsecureConfigTLS{
pattern: regexp.MustCompile(`^tls\.Config$`),
MinVersion: 0x0303, // TLS 1.2 only
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}
func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
return &InsecureConfigTLS{
pattern: regexp.MustCompile(`^tls\.Config$`),
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}
func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
return &InsecureConfigTLS{
pattern: regexp.MustCompile(`^tls\.Config$`),
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
return nil, nil
}

View File

@@ -0,0 +1,132 @@
package rules
import (
"go/ast"
"github.com/GoASTScanner/gas"
)
// NewModernTLSCheck creates a check for Modern TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewModernTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
return &insecureConfigTLS{
requiredType: "crypto/tls.Config",
MinVersion: 0x0303,
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}
// NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewIntermediateTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
return &insecureConfigTLS{
requiredType: "crypto/tls.Config",
MinVersion: 0x0301,
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}
// NewOldTLSCheck creates a check for Old TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewOldTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
return &insecureConfigTLS{
requiredType: "crypto/tls.Config",
MinVersion: 0x0300,
MaxVersion: 0x0303,
goodCiphers: []string{
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
"TLS_RSA_WITH_SEED_CBC_SHA",
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}

View File

@@ -15,25 +15,28 @@
package rules
import (
gas "github.com/GoASTScanner/gas/core"
"go/ast"
"github.com/GoASTScanner/gas"
)
type UsingUnsafe struct {
type usingUnsafe struct {
gas.MetaData
pkg string
calls []string
}
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 {
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
func NewUsingUnsafe(conf map[string]interface{}) (gas.Rule, []ast.Node) {
return &UsingUnsafe{
// NewUsingUnsafe rule detects the use of the unsafe package. This is only
// really useful for auditing purposes.
func NewUsingUnsafe(conf gas.Config) (gas.Rule, []ast.Node) {
return &usingUnsafe{
pkg: "unsafe",
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
MetaData: gas.MetaData{

View File

@@ -17,15 +17,15 @@ package rules
import (
"go/ast"
gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas"
)
type UsesWeakCryptography struct {
type usesWeakCryptography struct {
gas.MetaData
blacklist map[string][]string
}
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 {
if _, matched := gas.MatchCallByPackage(n, c, pkg, funcs...); matched {
@@ -35,13 +35,13 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er
return nil, nil
}
// Uses des.* md5.* or rc4.*
func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node) {
// NewUsesWeakCryptography detects uses of des.* md5.* or rc4.*
func NewUsesWeakCryptography(conf gas.Config) (gas.Rule, []ast.Node) {
calls := make(map[string][]string)
calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"}
calls["crypto/md5"] = []string{"New", "Sum"}
calls["crypto/rc4"] = []string{"NewCipher"}
rule := &UsesWeakCryptography{
rule := &usesWeakCryptography{
blacklist: calls,
MetaData: gas.MetaData{
Severity: gas.Medium,