github.com/crowdsecurity/crowdsec@v1.6.1/pkg/appsec/appsec_rules_collection.go (about)

     1  package appsec
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/crowdsecurity/crowdsec/pkg/appsec/appsec_rule"
    10  	"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
    11  
    12  	log "github.com/sirupsen/logrus"
    13  )
    14  
    15  type AppsecCollection struct {
    16  	collectionName string
    17  	Rules          []string
    18  }
    19  
    20  var APPSEC_RULE = "appsec-rule"
    21  
    22  // to be filled w/ seb update
    23  type AppsecCollectionConfig struct {
    24  	Type              string                   `yaml:"type"`
    25  	Name              string                   `yaml:"name"`
    26  	Debug             bool                     `yaml:"debug"`
    27  	Description       string                   `yaml:"description"`
    28  	SecLangFilesRules []string                 `yaml:"seclang_files_rules"`
    29  	SecLangRules      []string                 `yaml:"seclang_rules"`
    30  	Rules             []appsec_rule.CustomRule `yaml:"rules"`
    31  
    32  	Labels map[string]interface{} `yaml:"labels"` //Labels is K:V list aiming at providing context the overflow
    33  
    34  	Data    interface{} `yaml:"data"` //Ignore it
    35  	hash    string      `yaml:"-"`
    36  	version string      `yaml:"-"`
    37  }
    38  
    39  type RulesDetails struct {
    40  	LogLevel log.Level
    41  	Hash     string
    42  	Version  string
    43  	Name     string
    44  }
    45  
    46  // FIXME: this shouldn't be a global
    47  // Is using the id is a good idea ? might be too specific to coraza and not easily reusable
    48  var AppsecRulesDetails = make(map[int]RulesDetails)
    49  
    50  func LoadCollection(pattern string, logger *log.Entry) ([]AppsecCollection, error) {
    51  	ret := make([]AppsecCollection, 0)
    52  
    53  	for _, appsecRule := range appsecRules {
    54  
    55  		tmpMatch, err := exprhelpers.Match(pattern, appsecRule.Name)
    56  
    57  		if err != nil {
    58  			logger.Errorf("unable to match %s with %s : %s", appsecRule.Name, pattern, err)
    59  			continue
    60  		}
    61  
    62  		matched, ok := tmpMatch.(bool)
    63  
    64  		if !ok {
    65  			logger.Errorf("unable to match %s with %s : %s", appsecRule.Name, pattern, err)
    66  			continue
    67  		}
    68  
    69  		if !matched {
    70  			continue
    71  		}
    72  
    73  		appsecCol := AppsecCollection{
    74  			collectionName: appsecRule.Name,
    75  		}
    76  
    77  		if appsecRule.SecLangFilesRules != nil {
    78  			for _, rulesFile := range appsecRule.SecLangFilesRules {
    79  				logger.Debugf("Adding rules from %s", rulesFile)
    80  				fullPath := filepath.Join(hub.GetDataDir(), rulesFile)
    81  				c, err := os.ReadFile(fullPath)
    82  				if err != nil {
    83  					logger.Errorf("unable to read file %s : %s", rulesFile, err)
    84  					continue
    85  				}
    86  				for _, line := range strings.Split(string(c), "\n") {
    87  					if strings.HasPrefix(line, "#") {
    88  						continue
    89  					}
    90  					if strings.TrimSpace(line) == "" {
    91  						continue
    92  					}
    93  					appsecCol.Rules = append(appsecCol.Rules, line)
    94  				}
    95  			}
    96  		}
    97  
    98  		if appsecRule.SecLangRules != nil {
    99  			logger.Tracef("Adding inline rules %+v", appsecRule.SecLangRules)
   100  			appsecCol.Rules = append(appsecCol.Rules, appsecRule.SecLangRules...)
   101  		}
   102  
   103  		if appsecRule.Rules != nil {
   104  			for _, rule := range appsecRule.Rules {
   105  				strRule, rulesId, err := rule.Convert(appsec_rule.ModsecurityRuleType, appsecRule.Name)
   106  				if err != nil {
   107  					logger.Errorf("unable to convert rule %s : %s", appsecRule.Name, err)
   108  					return nil, err
   109  				}
   110  				logger.Debugf("Adding rule %s", strRule)
   111  				appsecCol.Rules = append(appsecCol.Rules, strRule)
   112  
   113  				//We only take the first id, as it's the one of the "main" rule
   114  				if _, ok := AppsecRulesDetails[int(rulesId[0])]; !ok {
   115  					AppsecRulesDetails[int(rulesId[0])] = RulesDetails{
   116  						LogLevel: log.InfoLevel,
   117  						Hash:     appsecRule.hash,
   118  						Version:  appsecRule.version,
   119  						Name:     appsecRule.Name,
   120  					}
   121  				} else {
   122  					logger.Warnf("conflicting id %d for rule %s !", rulesId[0], rule.Name)
   123  				}
   124  
   125  				for _, id := range rulesId {
   126  					SetRuleDebug(int(id), appsecRule.Debug)
   127  				}
   128  			}
   129  		}
   130  		ret = append(ret, appsecCol)
   131  	}
   132  	if len(ret) == 0 {
   133  		return nil, fmt.Errorf("no appsec-rules found for pattern %s", pattern)
   134  	}
   135  	return ret, nil
   136  }
   137  
   138  func (w AppsecCollection) String() string {
   139  	ret := ""
   140  	for _, rule := range w.Rules {
   141  		ret += rule + "\n"
   142  	}
   143  	return ret
   144  }