mirror of
https://github.com/securego/gosec.git
synced 2024-12-24 11:35:52 +00:00
fix golint errors picked up by hound-ci
This commit is contained in:
parent
cfa432729c
commit
af25ac1f6e
19 changed files with 146 additions and 120 deletions
|
@ -51,7 +51,7 @@ type Metrics struct {
|
||||||
NumFound int `json:"found"`
|
NumFound int `json:"found"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Analyzer object is the main object of GAS. It has methods traverse an AST
|
// Analyzer object is the main object of GAS. It has methods traverse an AST
|
||||||
// and invoke the correct checking rules as on each node as required.
|
// and invoke the correct checking rules as on each node as required.
|
||||||
type Analyzer struct {
|
type Analyzer struct {
|
||||||
ignoreNosec bool
|
ignoreNosec bool
|
||||||
|
@ -83,6 +83,8 @@ func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadRules instantiates all the rules to be used when analyzing source
|
||||||
|
// packages
|
||||||
func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
||||||
for _, builder := range ruleDefinitions {
|
for _, builder := range ruleDefinitions {
|
||||||
r, nodes := builder(gas.config)
|
r, nodes := builder(gas.config)
|
||||||
|
@ -90,6 +92,7 @@ func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process kicks off the analysis process for a given package
|
||||||
func (gas *Analyzer) Process(packagePath string) error {
|
func (gas *Analyzer) Process(packagePath string) error {
|
||||||
|
|
||||||
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
||||||
|
|
14
call_list.go
14
call_list.go
|
@ -19,23 +19,23 @@ import (
|
||||||
|
|
||||||
type set map[string]bool
|
type set map[string]bool
|
||||||
|
|
||||||
/// CallList is used to check for usage of specific packages
|
// CallList is used to check for usage of specific packages
|
||||||
/// and functions.
|
// and functions.
|
||||||
type CallList map[string]set
|
type CallList map[string]set
|
||||||
|
|
||||||
/// NewCallList creates a new empty CallList
|
// NewCallList creates a new empty CallList
|
||||||
func NewCallList() CallList {
|
func NewCallList() CallList {
|
||||||
return make(CallList)
|
return make(CallList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AddAll will add several calls to the call list at once
|
// AddAll will add several calls to the call list at once
|
||||||
func (c CallList) AddAll(selector string, idents ...string) {
|
func (c CallList) AddAll(selector string, idents ...string) {
|
||||||
for _, ident := range idents {
|
for _, ident := range idents {
|
||||||
c.Add(selector, ident)
|
c.Add(selector, ident)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a selector and call to the call list
|
// Add a selector and call to the call list
|
||||||
func (c CallList) Add(selector, ident string) {
|
func (c CallList) Add(selector, ident string) {
|
||||||
if _, ok := c[selector]; !ok {
|
if _, ok := c[selector]; !ok {
|
||||||
c[selector] = make(set)
|
c[selector] = make(set)
|
||||||
|
@ -43,7 +43,7 @@ func (c CallList) Add(selector, ident string) {
|
||||||
c[selector][ident] = true
|
c[selector][ident] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains returns true if the package and function are
|
// Contains returns true if the package and function are
|
||||||
/// members of this call list.
|
/// members of this call list.
|
||||||
func (c CallList) Contains(selector, ident string) bool {
|
func (c CallList) Contains(selector, ident string) bool {
|
||||||
if idents, ok := c[selector]; ok {
|
if idents, ok := c[selector]; ok {
|
||||||
|
@ -53,7 +53,7 @@ func (c CallList) Contains(selector, ident string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ContainsCallExpr resolves the call expression name and type
|
// ContainsCallExpr resolves the call expression name and type
|
||||||
/// or package and determines if it exists within the CallList
|
/// or package and determines if it exists within the CallList
|
||||||
func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) *ast.CallExpr {
|
func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) *ast.CallExpr {
|
||||||
selector, ident, err := GetCallInfo(n, ctx)
|
selector, ident, err := GetCallInfo(n, ctx)
|
||||||
|
|
12
issue.go
12
issue.go
|
@ -11,6 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package gas
|
package gas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -25,12 +26,15 @@ import (
|
||||||
type Score int
|
type Score int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Low Score = iota // Low value
|
// Low severity or confidence
|
||||||
Medium // Medium value
|
Low Score = iota
|
||||||
High // High value
|
// Medium severity or confidence
|
||||||
|
Medium
|
||||||
|
// High severity or confidence
|
||||||
|
High
|
||||||
)
|
)
|
||||||
|
|
||||||
// An Issue is returnd by a GAS rule if it discovers an issue with the scanned code.
|
// Issue is returnd by a GAS rule if it discovers an issue with the scanned code.
|
||||||
type Issue struct {
|
type Issue struct {
|
||||||
Severity Score `json:"severity"` // issue severity (how problematic it is)
|
Severity Score `json:"severity"` // issue severity (how problematic it is)
|
||||||
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
|
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
|
||||||
|
|
|
@ -78,7 +78,7 @@ var _ = Describe("Issue", func() {
|
||||||
|
|
||||||
// Use SQL rule to check binary expr
|
// Use SQL rule to check binary expr
|
||||||
cfg := gas.NewConfig()
|
cfg := gas.NewConfig()
|
||||||
rule, _ := rules.NewSqlStrConcat(cfg)
|
rule, _ := rules.NewSQLStrConcat(cfg)
|
||||||
issue, err := rule.Match(target, ctx)
|
issue, err := rule.Match(target, ctx)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(issue).ShouldNot(BeNil())
|
Expect(issue).ShouldNot(BeNil())
|
||||||
|
|
|
@ -24,13 +24,18 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The output format for reported issues
|
// ReportFormat enumrates the output format for reported issues
|
||||||
type ReportFormat int
|
type ReportFormat int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// ReportText is the default format that writes to stdout
|
||||||
ReportText ReportFormat = iota // Plain text format
|
ReportText ReportFormat = iota // Plain text format
|
||||||
ReportJSON // Json format
|
|
||||||
ReportCSV // CSV format
|
// ReportJSON set the output format to json
|
||||||
|
ReportJSON // Json format
|
||||||
|
|
||||||
|
// ReportCSV set the output format to csv
|
||||||
|
ReportCSV // CSV format
|
||||||
)
|
)
|
||||||
|
|
||||||
var text = `Results:
|
var text = `Results:
|
||||||
|
|
|
@ -20,20 +20,22 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UsingBigExp struct {
|
type usingBigExp struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
pkg string
|
pkg string
|
||||||
calls []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 {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewUsingBigExp detects issues with modulus == 0 for Bignum
|
||||||
func NewUsingBigExp(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewUsingBigExp(conf gas.Config) (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{
|
||||||
|
|
|
@ -22,13 +22,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
||||||
type BindsToAllNetworkInterfaces struct {
|
type bindsToAllNetworkInterfaces struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
calls gas.CallList
|
calls gas.CallList
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
callExpr := r.calls.ContainsCallExpr(n, c)
|
callExpr := r.calls.ContainsCallExpr(n, c)
|
||||||
if callExpr == nil {
|
if callExpr == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -41,11 +41,13 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Is
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
|
||||||
|
// listen on all network interfaces.
|
||||||
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
calls := gas.NewCallList()
|
calls := gas.NewCallList()
|
||||||
calls.Add("net", "Listen")
|
calls.Add("net", "Listen")
|
||||||
calls.Add("tls", "Listen")
|
calls.Add("tls", "Listen")
|
||||||
return &BindsToAllNetworkInterfaces{
|
return &bindsToAllNetworkInterfaces{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
|
|
@ -20,60 +20,57 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlacklistImport struct {
|
type blacklistedImport struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
Path string
|
Blacklisted map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
func (r *blacklistedImport) 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() != "_" {
|
description, ok := r.Blacklisted[node.Path.Value]
|
||||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
if ok && node.Name.String() != "_" {
|
||||||
|
return gas.NewIssue(c, n, description, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_md5(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewBlacklistedImports reports when a blacklisted import is being used.
|
||||||
return &BlacklistImport{
|
// 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{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.High,
|
Severity: gas.Medium,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
|
||||||
},
|
},
|
||||||
Path: `"crypto/md5"`,
|
Blacklisted: blacklist,
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_des(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewBlacklistedImportMD5 fails if MD5 is imported
|
||||||
return &BlacklistImport{
|
func NewBlacklistedImportMD5(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
MetaData: gas.MetaData{
|
return NewBlacklistedImports(conf, map[string]string{
|
||||||
Severity: gas.High,
|
"crypto/md5": "Use of weak cryptographic primitive",
|
||||||
Confidence: gas.High,
|
})
|
||||||
What: "Use of weak cryptographic primitive",
|
|
||||||
},
|
|
||||||
Path: `"crypto/des"`,
|
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_crypto_rc4(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewBlacklistedImportDES fails if DES is imported
|
||||||
return &BlacklistImport{
|
func NewBlacklistedImportDES(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
MetaData: gas.MetaData{
|
return NewBlacklistedImports(conf, map[string]string{
|
||||||
Severity: gas.High,
|
"crypto/des": "Use of weak cryptographic primitive",
|
||||||
Confidence: gas.High,
|
})
|
||||||
What: "Use of weak cryptographic primitive",
|
|
||||||
},
|
|
||||||
Path: `"crypto/rc4"`,
|
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlacklist_net_http_cgi(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewBlacklistedImportRC4 fails if DES is imported
|
||||||
return &BlacklistImport{
|
func NewBlacklistedImportRC4(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
MetaData: gas.MetaData{
|
return NewBlacklistedImports(conf, map[string]string{
|
||||||
Severity: gas.High,
|
"crypto/rc4": "Use of weak cryptographic primitive",
|
||||||
Confidence: gas.High,
|
})
|
||||||
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
}
|
||||||
},
|
|
||||||
Path: `"net/http/cgi"`,
|
// NewBlacklistedImportCGI fails if CGI is imported
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
func NewBlacklistedImportCGI(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
|
return NewBlacklistedImports(conf, map[string]string{
|
||||||
|
"net/http/cgi": "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NoErrorCheck struct {
|
type noErrorCheck struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
whitelist gas.CallList
|
whitelist gas.CallList
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ 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) {
|
||||||
case *types.Tuple:
|
case *types.Tuple:
|
||||||
for pos := 0; pos < t.Len(); pos += 1 {
|
for pos := 0; pos < t.Len(); pos++ {
|
||||||
variable := t.At(pos)
|
variable := t.At(pos)
|
||||||
if variable != nil && variable.Type().String() == "error" {
|
if variable != nil && variable.Type().String() == "error" {
|
||||||
return pos
|
return pos
|
||||||
|
@ -45,7 +45,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
||||||
return -1
|
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) {
|
switch stmt := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
for _, expr := range stmt.Rhs {
|
for _, expr := range stmt.Rhs {
|
||||||
|
@ -70,6 +70,7 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewNoErrorCheck detects if the returned error is unchecked
|
||||||
func NewNoErrorCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewNoErrorCheck(conf gas.Config) (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
|
||||||
|
@ -86,7 +87,7 @@ func NewNoErrorCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &NoErrorCheck{
|
return &noErrorCheck{
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.Low,
|
Severity: gas.Low,
|
||||||
Confidence: gas.High,
|
Confidence: gas.High,
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FilePermissions struct {
|
type filePermissions struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
mode int64
|
mode int64
|
||||||
pkg string
|
pkg string
|
||||||
|
@ -30,7 +30,7 @@ type FilePermissions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = defaultMode
|
||||||
if value, ok := conf[configKey]; ok {
|
if value, ok := conf[configKey]; ok {
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
case int64:
|
case int64:
|
||||||
|
@ -46,7 +46,7 @@ func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMod
|
||||||
return mode
|
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 {
|
if callexpr, matched := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matched {
|
||||||
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
||||||
if mode, err := gas.GetInt(modeArg); err == nil && mode > r.mode {
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
func NewFilePerms(conf gas.Config) (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"},
|
||||||
|
@ -70,9 +72,11 @@ func NewFilePerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMkdirPerms creates a rule to detect directory creation with more permissive than
|
||||||
|
// configured permission mask.
|
||||||
func NewMkdirPerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewMkdirPerms(conf gas.Config) (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"},
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/nbutton23/zxcvbn-go"
|
"github.com/nbutton23/zxcvbn-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Credentials struct {
|
type credentials struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
entropyThreshold float64
|
entropyThreshold float64
|
||||||
|
@ -40,7 +40,7 @@ func truncate(s string, n int) string {
|
||||||
return s[:n]
|
return s[:n]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Credentials) isHighEntropyString(str string) bool {
|
func (r *credentials) isHighEntropyString(str string) bool {
|
||||||
s := truncate(str, r.truncate)
|
s := truncate(str, r.truncate)
|
||||||
info := zxcvbn.PasswordStrength(s, []string{})
|
info := zxcvbn.PasswordStrength(s, []string{})
|
||||||
entropyPerChar := info.Entropy / float64(len(s))
|
entropyPerChar := info.Entropy / float64(len(s))
|
||||||
|
@ -49,7 +49,7 @@ func (r *Credentials) isHighEntropyString(str string) bool {
|
||||||
entropyPerChar >= r.perCharThreshold))
|
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) {
|
switch node := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
return r.matchAssign(node, ctx)
|
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
|
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 {
|
for _, i := range assign.Lhs {
|
||||||
if ident, ok := i.(*ast.Ident); ok {
|
if ident, ok := i.(*ast.Ident); ok {
|
||||||
if r.pattern.MatchString(ident.Name) {
|
if r.pattern.MatchString(ident.Name) {
|
||||||
|
@ -76,7 +76,7 @@ func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*ga
|
||||||
return nil, nil
|
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 {
|
if decl.Tok != token.CONST && decl.Tok != token.VAR {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -100,12 +100,14 @@ func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Is
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
func NewHardcodedCredentials(conf gas.Config) (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
|
||||||
ignoreEntropy := false
|
ignoreEntropy := false
|
||||||
var truncateString int = 16
|
var truncateString = 16
|
||||||
if val, ok := conf["G101"]; ok {
|
if val, ok := conf["G101"]; ok {
|
||||||
conf := val.(map[string]string)
|
conf := val.(map[string]string)
|
||||||
if configPattern, ok := conf["pattern"]; ok {
|
if configPattern, ok := conf["pattern"]; ok {
|
||||||
|
@ -133,7 +135,7 @@ func NewHardcodedCredentials(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Credentials{
|
return &credentials{
|
||||||
pattern: regexp.MustCompile(pattern),
|
pattern: regexp.MustCompile(pattern),
|
||||||
entropyThreshold: entropyThreshold,
|
entropyThreshold: entropyThreshold,
|
||||||
perCharThreshold: perCharThreshold,
|
perCharThreshold: perCharThreshold,
|
||||||
|
|
|
@ -20,13 +20,13 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WeakRand struct {
|
type weakRand struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
funcNames []string
|
funcNames []string
|
||||||
packagePath 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 {
|
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 {
|
||||||
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
|
||||||
func NewWeakRandCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewWeakRandCheck(conf gas.Config) (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{
|
||||||
|
|
|
@ -21,13 +21,13 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WeakKeyStrength struct {
|
type weakKeyStrength struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
calls gas.CallList
|
calls gas.CallList
|
||||||
bits int
|
bits int
|
||||||
}
|
}
|
||||||
|
|
||||||
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 callExpr := w.calls.ContainsCallExpr(n, c); callExpr != nil {
|
if callExpr := w.calls.ContainsCallExpr(n, c); callExpr != nil {
|
||||||
if bits, err := gas.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
|
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 gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
||||||
|
@ -36,11 +36,12 @@ func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits
|
||||||
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
calls := gas.NewCallList()
|
calls := gas.NewCallList()
|
||||||
calls.Add("rsa", "GenerateKey")
|
calls.Add("rsa", "GenerateKey")
|
||||||
bits := 2048
|
bits := 2048
|
||||||
return &WeakKeyStrength{
|
return &weakKeyStrength{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
bits: bits,
|
bits: bits,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
|
|
@ -67,8 +67,8 @@ func Generate(filters ...RuleFilter) RuleList {
|
||||||
"G105": RuleDefinition{"Audit the use of big.Exp function", NewUsingBigExp},
|
"G105": RuleDefinition{"Audit the use of big.Exp function", NewUsingBigExp},
|
||||||
|
|
||||||
// injection
|
// injection
|
||||||
"G201": RuleDefinition{"SQL query construction using format string", NewSqlStrFormat},
|
"G201": RuleDefinition{"SQL query construction using format string", NewSQLStrFormat},
|
||||||
"G202": RuleDefinition{"SQL query construction using string concatenation", NewSqlStrConcat},
|
"G202": RuleDefinition{"SQL query construction using string concatenation", NewSQLStrConcat},
|
||||||
"G203": RuleDefinition{"Use of unescaped data in HTML templates", NewTemplateCheck},
|
"G203": RuleDefinition{"Use of unescaped data in HTML templates", NewTemplateCheck},
|
||||||
"G204": RuleDefinition{"Audit use of command execution", NewSubproc},
|
"G204": RuleDefinition{"Audit use of command execution", NewSubproc},
|
||||||
|
|
||||||
|
@ -79,15 +79,15 @@ func Generate(filters ...RuleFilter) RuleList {
|
||||||
|
|
||||||
// crypto
|
// crypto
|
||||||
"G401": RuleDefinition{"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
|
"G401": RuleDefinition{"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
|
||||||
"G402": RuleDefinition{"Look for bad TLS connection settings", NewIntermediateTlsCheck},
|
"G402": RuleDefinition{"Look for bad TLS connection settings", NewIntermediateTLSCheck},
|
||||||
"G403": RuleDefinition{"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
|
"G403": RuleDefinition{"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
|
||||||
"G404": RuleDefinition{"Insecure random number source (rand)", NewWeakRandCheck},
|
"G404": RuleDefinition{"Insecure random number source (rand)", NewWeakRandCheck},
|
||||||
|
|
||||||
// blacklist
|
// blacklist
|
||||||
"G501": RuleDefinition{"Import blacklist: crypto/md5", NewBlacklist_crypto_md5},
|
"G501": RuleDefinition{"Import blacklist: crypto/md5", NewBlacklistedImportMD5},
|
||||||
"G502": RuleDefinition{"Import blacklist: crypto/des", NewBlacklist_crypto_des},
|
"G502": RuleDefinition{"Import blacklist: crypto/des", NewBlacklistedImportDES},
|
||||||
"G503": RuleDefinition{"Import blacklist: crypto/rc4", NewBlacklist_crypto_rc4},
|
"G503": RuleDefinition{"Import blacklist: crypto/rc4", NewBlacklistedImportRC4},
|
||||||
"G504": RuleDefinition{"Import blacklist: net/http/cgi", NewBlacklist_net_http_cgi},
|
"G504": RuleDefinition{"Import blacklist: net/http/cgi", NewBlacklistedImportCGI},
|
||||||
}
|
}
|
||||||
|
|
||||||
for rule := range rules {
|
for rule := range rules {
|
||||||
|
|
30
rules/sql.go
30
rules/sql.go
|
@ -21,17 +21,17 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SqlStatement struct {
|
type sqlStatement struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqlStrConcat struct {
|
type sqlStrConcat struct {
|
||||||
SqlStatement
|
sqlStatement
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
|
return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for "SELECT * FROM table WHERE " + " ' OR 1=1"
|
// 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 node, ok := n.(*ast.BinaryExpr); ok {
|
||||||
if start, ok := node.X.(*ast.BasicLit); 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); s.pattern.MatchString(str) && e == nil {
|
||||||
|
@ -56,9 +56,10 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
|
||||||
return &SqlStrConcat{
|
func NewSQLStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
SqlStatement: SqlStatement{
|
return &sqlStrConcat{
|
||||||
|
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{
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
|
@ -69,13 +70,13 @@ func NewSqlStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}, []ast.Node{(*ast.BinaryExpr)(nil)}
|
}, []ast.Node{(*ast.BinaryExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqlStrFormat struct {
|
type sqlStrFormat struct {
|
||||||
SqlStatement
|
sqlStatement
|
||||||
calls gas.CallList
|
calls gas.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
||||||
func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
func (s *sqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
|
|
||||||
// TODO(gm) improve confidence if database/sql is being used
|
// TODO(gm) improve confidence if database/sql is being used
|
||||||
if node := s.calls.ContainsCallExpr(n, c); node != nil {
|
if node := s.calls.ContainsCallExpr(n, c); node != nil {
|
||||||
|
@ -86,10 +87,11 @@ func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSqlStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
|
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
|
||||||
rule := &SqlStrFormat{
|
func NewSQLStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
|
rule := &sqlStrFormat{
|
||||||
calls: gas.NewCallList(),
|
calls: gas.NewCallList(),
|
||||||
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{
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Subprocess struct {
|
type subprocess struct {
|
||||||
gas.CallList
|
gas.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ type Subprocess struct {
|
||||||
// is unsafe. For example:
|
// is unsafe. For example:
|
||||||
//
|
//
|
||||||
// syscall.Exec("echo", "foobar" + tainted)
|
// syscall.Exec("echo", "foobar" + tainted)
|
||||||
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 := r.ContainsCallExpr(n, c); node != nil {
|
if node := r.ContainsCallExpr(n, c); node != nil {
|
||||||
for _, arg := range node.Args {
|
for _, arg := range node.Args {
|
||||||
if ident, ok := arg.(*ast.Ident); ok {
|
if ident, ok := arg.(*ast.Ident); ok {
|
||||||
|
@ -49,8 +49,9 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSubproc detects cases where we are forking out to an external process
|
||||||
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
rule := &Subprocess{gas.NewCallList()}
|
rule := &subprocess{gas.NewCallList()}
|
||||||
rule.Add("exec", "Command")
|
rule.Add("exec", "Command")
|
||||||
rule.Add("syscall", "Exec")
|
rule.Add("syscall", "Exec")
|
||||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -21,13 +21,13 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BadTempFile struct {
|
type badTempFile struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
calls gas.CallList
|
calls gas.CallList
|
||||||
args *regexp.Regexp
|
args *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
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 := t.calls.ContainsCallExpr(n, c); node != nil {
|
if node := t.calls.ContainsCallExpr(n, c); 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 {
|
||||||
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
||||||
|
@ -36,11 +36,12 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewBadTempFile detects direct writes to predictable path in temporary directory
|
||||||
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
calls := gas.NewCallList()
|
calls := gas.NewCallList()
|
||||||
calls.Add("ioutil", "WriteFile")
|
calls.Add("ioutil", "WriteFile")
|
||||||
calls.Add("os", "Create")
|
calls.Add("os", "Create")
|
||||||
return &BadTempFile{
|
return &badTempFile{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
|
|
16
rules/tls.go
16
rules/tls.go
|
@ -62,7 +62,7 @@ func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gas.Context) *
|
||||||
return nil
|
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 {
|
if ident, ok := n.Key.(*ast.Ident); ok {
|
||||||
switch ident.Name {
|
switch ident.Name {
|
||||||
case "InsecureSkipVerify":
|
case "InsecureSkipVerify":
|
||||||
|
@ -118,7 +118,7 @@ func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er
|
||||||
if node := gas.MatchCompLit(n, c, t.requiredType); node != nil {
|
if node := gas.MatchCompLit(n, c, t.requiredType); node != nil {
|
||||||
for _, elt := range node.Elts {
|
for _, elt := range node.Elts {
|
||||||
if kve, ok := elt.(*ast.KeyValueExpr); ok {
|
if kve, ok := elt.(*ast.KeyValueExpr); ok {
|
||||||
gi = t.processTlsConfVal(kve, c)
|
gi = t.processTLSConfVal(kve, c)
|
||||||
if gi != nil {
|
if gi != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -128,8 +128,8 @@ func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewModernTlsCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
// NewModernTLSCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||||
func NewModernTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewModernTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
requiredType: "tls.Config",
|
requiredType: "tls.Config",
|
||||||
MinVersion: 0x0303, // TLS 1.2 only
|
MinVersion: 0x0303, // TLS 1.2 only
|
||||||
|
@ -143,8 +143,8 @@ func NewModernTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntermediateTlsCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
// NewIntermediateTLSCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
||||||
func NewIntermediateTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewIntermediateTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
requiredType: "tls.Config",
|
requiredType: "tls.Config",
|
||||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||||
|
@ -169,8 +169,8 @@ func NewIntermediateTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCompatTlsCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
// NewCompatTLSCheck see: https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
||||||
func NewCompatTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewCompatTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
requiredType: "tls.Config",
|
requiredType: "tls.Config",
|
||||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||||
|
|
|
@ -20,12 +20,12 @@ import (
|
||||||
"github.com/GoASTScanner/gas"
|
"github.com/GoASTScanner/gas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UsesWeakCryptography struct {
|
type usesWeakCryptography struct {
|
||||||
gas.MetaData
|
gas.MetaData
|
||||||
blacklist map[string][]string
|
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 {
|
for pkg, funcs := range r.blacklist {
|
||||||
if _, matched := gas.MatchCallByPackage(n, c, pkg, funcs...); matched {
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses des.* md5.* or rc4.*
|
// NewUsesWeakCryptography detects uses of des.* md5.* or rc4.*
|
||||||
func NewUsesWeakCryptography(conf gas.Config) (gas.Rule, []ast.Node) {
|
func NewUsesWeakCryptography(conf gas.Config) (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"}
|
||||||
calls["crypto/rc4"] = []string{"NewCipher"}
|
calls["crypto/rc4"] = []string{"NewCipher"}
|
||||||
rule := &UsesWeakCryptography{
|
rule := &usesWeakCryptography{
|
||||||
blacklist: calls,
|
blacklist: calls,
|
||||||
MetaData: gas.MetaData{
|
MetaData: gas.MetaData{
|
||||||
Severity: gas.Medium,
|
Severity: gas.Medium,
|
||||||
|
|
Loading…
Reference in a new issue