mirror of
https://github.com/securego/gosec.git
synced 2024-11-05 19:45:51 +00:00
Restructure and introduce a standalone config
This commit is contained in:
parent
cacf21f3c0
commit
bf78d027a9
26 changed files with 234 additions and 127 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,7 +3,6 @@
|
|||
*.a
|
||||
*.so
|
||||
*.swp
|
||||
gas
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
|
|
16
analyzer.go
16
analyzer.go
|
@ -82,27 +82,33 @@ type Analyzer struct {
|
|||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
Issues []*Issue `json:"issues"`
|
||||
Stats *Metrics `json:"metrics"`
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new anaylzer.
|
||||
func NewAnalyzer(conf map[string]interface{}, logger *log.Logger) Analyzer {
|
||||
func NewAnalyzer(conf Config, logger *log.Logger) Analyzer {
|
||||
if logger == nil {
|
||||
logger = log.New(os.Stdout, "[gas]", 0)
|
||||
}
|
||||
ignoreNoSec := false
|
||||
if val, err := conf.Get("ignoreNoSec"); err == nil {
|
||||
if override, ok := val.(bool); ok {
|
||||
ignoreNoSec = override
|
||||
}
|
||||
}
|
||||
a := Analyzer{
|
||||
ignoreNosec: conf["ignoreNosec"].(bool),
|
||||
ignoreNosec: ignoreNoSec,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
Issues: make([]*Issue, 0, 16),
|
||||
Stats: &Metrics{0, 0, 0, 0},
|
||||
}
|
||||
|
||||
// TODO(tkelsey): use the inc/exc lists
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
|
@ -111,6 +117,7 @@ func (gas *Analyzer) process(filename string, source interface{}) error {
|
|||
gas.context.FileSet = token.NewFileSet()
|
||||
root, err := parser.ParseFile(gas.context.FileSet, filename, source, mode)
|
||||
if err == nil {
|
||||
gas.context.Config = gas.config
|
||||
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, root, root.Comments)
|
||||
gas.context.Root = root
|
||||
|
||||
|
@ -171,6 +178,7 @@ func (gas *Analyzer) Process(filename string) error {
|
|||
func (gas *Analyzer) ProcessPackage(prog *loader.Program, pkg *loader.PackageInfo, file *ast.File) error {
|
||||
|
||||
gas.context.FileSet = prog.Fset
|
||||
gas.context.Config = gas.config
|
||||
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, file, file.Comments)
|
||||
gas.context.Root = file
|
||||
gas.context.Info = &pkg.Info
|
||||
|
|
BIN
cmd/gas/gas
Executable file
BIN
cmd/gas/gas
Executable file
Binary file not shown.
|
@ -29,6 +29,7 @@ import (
|
|||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/GoASTScanner/gas/output"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
|
@ -138,7 +139,7 @@ func usage() {
|
|||
fmt.Fprint(os.Stderr, "\n\nRULES:\n\n")
|
||||
|
||||
// sorted rule list for eas of reading
|
||||
rl := GetFullRuleList()
|
||||
rl := rules.Generate()
|
||||
keys := make([]string, 0, len(rl))
|
||||
for key := range rl {
|
||||
keys = append(keys, key)
|
||||
|
@ -146,13 +147,13 @@ func usage() {
|
|||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := rl[k]
|
||||
fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.description)
|
||||
fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.Description)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
// TODO(gm) This needs to be refactored (potentially included in Analyzer)
|
||||
func analyzePackage(packageDirectory string, metrics *gas.Metrics, config map[string]interface{}, logger *log.Logger) ([]*gas.Issue, error) {
|
||||
func analyzePackage(packageDirectory string, metrics *gas.Metrics, config gas.Config, logger *log.Logger, ruleDefs rules.RuleList) ([]*gas.Issue, error) {
|
||||
|
||||
basePackage, err := build.Default.ImportDir(packageDirectory, build.ImportComment)
|
||||
if err != nil {
|
||||
|
@ -174,7 +175,9 @@ func analyzePackage(packageDirectory string, metrics *gas.Metrics, config map[st
|
|||
|
||||
for _, pkg := range builtPackage.Created {
|
||||
analyzer := gas.NewAnalyzer(config, logger)
|
||||
AddRules(&analyzer, config)
|
||||
for _, rule := range ruleDefs {
|
||||
analyzer.AddRule(rule.Create(config))
|
||||
}
|
||||
for _, file := range pkg.Files {
|
||||
analyzer.ProcessPackage(builtPackage, pkg, file)
|
||||
}
|
||||
|
@ -227,10 +230,30 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
config := buildConfig(incRules, excRules)
|
||||
// Load config
|
||||
config := gas.NewConfig()
|
||||
if flagConfig != nil && *flagConfig != "" {
|
||||
file, err := os.Open(*flagConfig)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := config.ReadFrom(file); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
filters := make([]rules.RuleFilter, 0)
|
||||
if incRules != "" {
|
||||
including := strings.Split(incRules, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(false, including...))
|
||||
}
|
||||
if excRules != "" {
|
||||
excluding := strings.Split(excRules, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(true, excluding...))
|
||||
}
|
||||
ruleDefinitions := rules.Generate(filters...)
|
||||
issues := make([]*gas.Issue, 0)
|
||||
metrics := &gas.Metrics{}
|
||||
|
||||
for _, arg := range flag.Args() {
|
||||
if arg == "./..." {
|
||||
baseDirectory, err := os.Getwd()
|
||||
|
@ -246,7 +269,7 @@ func main() {
|
|||
log.Printf("Skipping %s\n", path)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
newIssues, err := analyzePackage(path, metrics, config, logger)
|
||||
newIssues, err := analyzePackage(path, metrics, config, logger, ruleDefinitions)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
|
@ -256,7 +279,7 @@ func main() {
|
|||
return nil
|
||||
})
|
||||
} else {
|
||||
newIssues, err := analyzePackage(arg, metrics, config, logger)
|
||||
newIssues, err := analyzePackage(arg, metrics, config, logger, ruleDefinitions)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
// (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 main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
)
|
||||
|
||||
type RuleInfo struct {
|
||||
description string
|
||||
build func(map[string]interface{}) (gas.Rule, []ast.Node)
|
||||
}
|
||||
|
||||
// GetFullRuleList get the full list of all rules available to GAS
|
||||
func GetFullRuleList() map[string]RuleInfo {
|
||||
return map[string]RuleInfo{
|
||||
// misc
|
||||
"G101": RuleInfo{"Look for hardcoded credentials", rules.NewHardcodedCredentials},
|
||||
"G102": RuleInfo{"Bind to all interfaces", rules.NewBindsToAllNetworkInterfaces},
|
||||
"G103": RuleInfo{"Audit the use of unsafe block", rules.NewUsingUnsafe},
|
||||
"G104": RuleInfo{"Audit errors not checked", rules.NewNoErrorCheck},
|
||||
"G105": RuleInfo{"Audit the use of big.Exp function", rules.NewUsingBigExp},
|
||||
|
||||
// injection
|
||||
"G201": RuleInfo{"SQL query construction using format string", rules.NewSqlStrFormat},
|
||||
"G202": RuleInfo{"SQL query construction using string concatenation", rules.NewSqlStrConcat},
|
||||
"G203": RuleInfo{"Use of unescaped data in HTML templates", rules.NewTemplateCheck},
|
||||
"G204": RuleInfo{"Audit use of command execution", rules.NewSubproc},
|
||||
|
||||
// filesystem
|
||||
"G301": RuleInfo{"Poor file permissions used when creating a directory", rules.NewMkdirPerms},
|
||||
"G302": RuleInfo{"Poor file permisions used when creation file or using chmod", rules.NewFilePerms},
|
||||
"G303": RuleInfo{"Creating tempfile using a predictable path", rules.NewBadTempFile},
|
||||
|
||||
// crypto
|
||||
"G401": RuleInfo{"Detect the usage of DES, RC4, or MD5", rules.NewUsesWeakCryptography},
|
||||
"G402": RuleInfo{"Look for bad TLS connection settings", rules.NewIntermediateTlsCheck},
|
||||
"G403": RuleInfo{"Ensure minimum RSA key length of 2048 bits", rules.NewWeakKeyStrength},
|
||||
"G404": RuleInfo{"Insecure random number source (rand)", rules.NewWeakRandCheck},
|
||||
|
||||
// blacklist
|
||||
"G501": RuleInfo{"Import blacklist: crypto/md5", rules.NewBlacklist_crypto_md5},
|
||||
"G502": RuleInfo{"Import blacklist: crypto/des", rules.NewBlacklist_crypto_des},
|
||||
"G503": RuleInfo{"Import blacklist: crypto/rc4", rules.NewBlacklist_crypto_rc4},
|
||||
"G504": RuleInfo{"Import blacklist: net/http/cgi", rules.NewBlacklist_net_http_cgi},
|
||||
}
|
||||
}
|
||||
|
||||
func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) {
|
||||
var all map[string]RuleInfo
|
||||
|
||||
inc := conf["include"].([]string)
|
||||
exc := conf["exclude"].([]string)
|
||||
|
||||
// add included rules
|
||||
if len(inc) == 0 {
|
||||
all = GetFullRuleList()
|
||||
} else {
|
||||
all = map[string]RuleInfo{}
|
||||
tmp := GetFullRuleList()
|
||||
for _, v := range inc {
|
||||
if val, ok := tmp[v]; ok {
|
||||
all[v] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove excluded rules
|
||||
for _, v := range exc {
|
||||
delete(all, v)
|
||||
}
|
||||
|
||||
for _, v := range all {
|
||||
analyzer.AddRule(v.build(conf))
|
||||
}
|
||||
}
|
80
config.go
Normal file
80
config.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package gas
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// Config is used to provide configuration and customization to each of the rules.
|
||||
type Config map[string]interface{}
|
||||
|
||||
// NewConfig initializes a new configuration instance. The configuration data then
|
||||
// needs to be loaded via c.ReadFrom(strings.NewReader("config data"))
|
||||
// or from a *os.File.
|
||||
func NewConfig() Config {
|
||||
return make(Config)
|
||||
}
|
||||
|
||||
// ReadFrom implements the io.ReaderFrom interface. This
|
||||
// should be used with io.Reader to load configuration from
|
||||
//file or from string etc.
|
||||
func (c Config) ReadFrom(r io.Reader) (int64, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
if err = json.Unmarshal(data, c); err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return int64(len(data)), nil
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriteTo interface. This should
|
||||
// be used to save or print out the configuration information.
|
||||
func (c Config) WriteTo(w io.Writer) (int64, error) {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return io.Copy(w, bytes.NewReader(data))
|
||||
}
|
||||
|
||||
// EnableRule will change the rule to the specified enabled state
|
||||
func (c Config) EnableRule(ruleID string, enabled bool) {
|
||||
if data, found := c["rules"]; found {
|
||||
if rules, ok := data.(map[string]bool); ok {
|
||||
rules[ruleID] = enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled returns a list of rules that are enabled
|
||||
func (c Config) Enabled() []string {
|
||||
if data, found := c["rules"]; found {
|
||||
if rules, ok := data.(map[string]bool); ok {
|
||||
enabled := make([]string, len(rules))
|
||||
for ruleID := range rules {
|
||||
enabled = append(enabled, ruleID)
|
||||
}
|
||||
return enabled
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the configuration section for a given rule
|
||||
func (c Config) Get(ruleID string) (interface{}, error) {
|
||||
section, found := c[ruleID]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Rule %s not in configuration", ruleID)
|
||||
}
|
||||
return section, nil
|
||||
}
|
||||
|
||||
// Set section for a given rule
|
||||
func (c Config) Set(ruleID string, val interface{}) {
|
||||
c[ruleID] = val
|
||||
}
|
|
@ -15,8 +15,9 @@
|
|||
package rules
|
||||
|
||||
import (
|
||||
"github.com/GoASTScanner/gas"
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type UsingBigExp struct {
|
||||
|
@ -31,7 +32,7 @@ func (r *UsingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
func NewUsingBigExp(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewUsingBigExp(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &UsingBigExp{
|
||||
pkg: "*math/big.Int",
|
||||
calls: []string{"Exp"},
|
||||
|
|
|
@ -39,7 +39,7 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas
|
|||
return
|
||||
}
|
||||
|
||||
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BindsToAllNetworkInterfaces{
|
||||
call: regexp.MustCompile(`^(net|tls)\.Listen$`),
|
||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||
|
|
|
@ -34,7 +34,7 @@ func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewBlacklist_crypto_md5(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
|
@ -45,7 +45,7 @@ func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
|||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewBlacklist_crypto_des(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
|
@ -56,7 +56,7 @@ func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
|||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewBlacklist_crypto_rc4(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
|
@ -67,7 +67,7 @@ func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
|||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
}
|
||||
|
||||
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewBlacklist_net_http_cgi(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
|
|
|
@ -70,7 +70,7 @@ 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) {
|
||||
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.
|
||||
|
|
|
@ -56,7 +56,7 @@ 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) {
|
||||
func NewFilePerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G302", 0600)
|
||||
return &FilePermissions{
|
||||
mode: mode,
|
||||
|
@ -70,7 +70,7 @@ 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) {
|
||||
func NewMkdirPerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G301", 0700)
|
||||
return &FilePermissions{
|
||||
mode: mode,
|
||||
|
|
|
@ -100,7 +100,7 @@ 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) {
|
||||
func NewHardcodedCredentials(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
||||
entropyThreshold := 80.0
|
||||
perCharThreshold := 3.0
|
||||
|
|
|
@ -36,7 +36,7 @@ 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) {
|
||||
func NewWeakRandCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &WeakRand{
|
||||
funcNames: []string{"Read", "Int"},
|
||||
packagePath: "math/rand",
|
||||
|
|
|
@ -37,7 +37,7 @@ func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func NewWeakKeyStrength(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
bits := 2048
|
||||
return &WeakKeyStrength{
|
||||
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
||||
|
|
87
rules/rulelist.go
Normal file
87
rules/rulelist.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// (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 (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type RuleDefinition struct {
|
||||
Description string
|
||||
Create func(c gas.Config) (gas.Rule, []ast.Node)
|
||||
}
|
||||
|
||||
type RuleList map[string]RuleDefinition
|
||||
|
||||
type RuleFilter func(string) bool
|
||||
|
||||
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": RuleDefinition{"Look for hardcoded credentials", NewHardcodedCredentials},
|
||||
"G102": RuleDefinition{"Bind to all interfaces", NewBindsToAllNetworkInterfaces},
|
||||
"G103": RuleDefinition{"Audit the use of unsafe block", NewUsingUnsafe},
|
||||
"G104": RuleDefinition{"Audit errors not checked", NewNoErrorCheck},
|
||||
"G105": RuleDefinition{"Audit the use of big.Exp function", NewUsingBigExp},
|
||||
|
||||
// injection
|
||||
"G201": RuleDefinition{"SQL query construction using format string", NewSqlStrFormat},
|
||||
"G202": RuleDefinition{"SQL query construction using string concatenation", NewSqlStrConcat},
|
||||
"G203": RuleDefinition{"Use of unescaped data in HTML templates", NewTemplateCheck},
|
||||
"G204": RuleDefinition{"Audit use of command execution", NewSubproc},
|
||||
|
||||
// filesystem
|
||||
"G301": RuleDefinition{"Poor file permissions used when creating a directory", NewMkdirPerms},
|
||||
"G302": RuleDefinition{"Poor file permisions used when creation file or using chmod", NewFilePerms},
|
||||
"G303": RuleDefinition{"Creating tempfile using a predictable path", NewBadTempFile},
|
||||
|
||||
// crypto
|
||||
"G401": RuleDefinition{"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
|
||||
"G402": RuleDefinition{"Look for bad TLS connection settings", NewIntermediateTlsCheck},
|
||||
"G403": RuleDefinition{"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
|
||||
"G404": RuleDefinition{"Insecure random number source (rand)", NewWeakRandCheck},
|
||||
|
||||
// blacklist
|
||||
"G501": RuleDefinition{"Import blacklist: crypto/md5", NewBlacklist_crypto_md5},
|
||||
"G502": RuleDefinition{"Import blacklist: crypto/des", NewBlacklist_crypto_des},
|
||||
"G503": RuleDefinition{"Import blacklist: crypto/rc4", NewBlacklist_crypto_rc4},
|
||||
"G504": RuleDefinition{"Import blacklist: net/http/cgi", NewBlacklist_net_http_cgi},
|
||||
}
|
||||
|
||||
for rule := range rules {
|
||||
for _, filter := range filters {
|
||||
if filter(rule) {
|
||||
delete(rules, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}
|
|
@ -56,7 +56,7 @@ 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) {
|
||||
func NewSqlStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &SqlStrConcat{
|
||||
SqlStatement: SqlStatement{
|
||||
pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||
|
@ -84,7 +84,7 @@ func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func NewSqlStrFormat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewSqlStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &SqlStrFormat{
|
||||
call: regexp.MustCompile(`^fmt\.Sprintf$`),
|
||||
SqlStatement: SqlStatement{
|
||||
|
|
|
@ -49,7 +49,7 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &Subprocess{
|
||||
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -36,7 +36,7 @@ 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) {
|
||||
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &BadTempFile{
|
||||
call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`),
|
||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||
|
|
|
@ -37,7 +37,7 @@ 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) {
|
||||
func NewTemplateCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &TemplateCheck{
|
||||
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
||||
MetaData: gas.MetaData{
|
||||
|
|
|
@ -121,7 +121,7 @@ func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er
|
|||
return
|
||||
}
|
||||
|
||||
func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewModernTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
|
@ -136,7 +136,7 @@ func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
|||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewIntermediateTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
|
@ -162,7 +162,7 @@ func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
|||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewCompatTlsCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
|
|
|
@ -33,7 +33,7 @@ func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func NewUsingUnsafe(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
func NewUsingUnsafe(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &UsingUnsafe{
|
||||
pkg: "unsafe",
|
||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||
|
|
|
@ -36,7 +36,7 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er
|
|||
}
|
||||
|
||||
// Uses des.* md5.* or rc4.*
|
||||
func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
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"}
|
||||
|
|
Loading…
Reference in a new issue