teawaf

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2020 License: MIT, MIT Imports: 32 Imported by: 0

README

WAF

A basic WAF for TeaWeb.

Config Constructions

WAF
  Inbound
	  Rule Groups
		Rule Sets
		  Rules
			Checkpoint Param <Operator> Value
  Outbound
  	  Rule Groups
  	    ... 				

Apply WAF

Request  -->  WAF  -->   Backends
			/
Response  <-- WAF <----		

Coding

waf := teawaf.NewWAF()

// add rule groups here

err := waf.Init()
if err != nil {
	return
}
waf.Start()

// match http request
// (req *http.Request, responseWriter http.ResponseWriter)
goNext, ruleSet, _ := waf.MatchRequest(req, responseWriter)
if ruleSet != nil {
	log.Println("meet rule set:", ruleSet.Name, "action:", ruleSet.Action)
}
if !goNext {
	return
}

// stop the waf
// waf.Stop()

Documentation

Index

Constants

View Source
const (
	ActionLog     = "log"      // allow and log
	ActionBlock   = "block"    // block
	ActionCaptcha = "captcha"  // block and show captcha
	ActionAllow   = "allow"    // allow
	ActionGoGroup = "go_group" // go to next rule group
	ActionGoSet   = "go_set"   // go to next rule set
)
View Source
const (
	RuleConnectorAnd = "and"
	RuleConnectorOr  = "or"
)
View Source
const (
	CaptchaSeconds = 600 // 10 minutes
)

Variables

View Source
var AllActions = []*ActionDefinition{
	{
		Name:     "阻止",
		Code:     ActionBlock,
		Instance: new(BlockAction),
	},
	{
		Name:     "允许通过",
		Code:     ActionAllow,
		Instance: new(AllowAction),
	},
	{
		Name:     "允许并记录日志",
		Code:     ActionLog,
		Instance: new(LogAction),
	},
	{
		Name:     "Captcha验证码",
		Code:     ActionCaptcha,
		Instance: new(CaptchaAction),
	},
	{
		Name:     "跳到下一个规则分组",
		Code:     ActionGoGroup,
		Instance: new(GoGroupAction),
		Type:     reflect.TypeOf(new(GoGroupAction)).Elem(),
	},
	{
		Name:     "跳到下一个规则集",
		Code:     ActionGoSet,
		Instance: new(GoSetAction),
		Type:     reflect.TypeOf(new(GoSetAction)).Elem(),
	},
}
View Source
var AllRuleOperators = []*RuleOperatorDefinition{
	{
		Name:            "数值大于",
		Code:            RuleOperatorGt,
		Description:     "使用数值对比大于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "数值大于等于",
		Code:            RuleOperatorGte,
		Description:     "使用数值对比大于等于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "数值小于",
		Code:            RuleOperatorLt,
		Description:     "使用数值对比小于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "数值小于等于",
		Code:            RuleOperatorLte,
		Description:     "使用数值对比小于等于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "数值等于",
		Code:            RuleOperatorEq,
		Description:     "使用数值对比等于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "数值不等于",
		Code:            RuleOperatorNeq,
		Description:     "使用数值对比不等于",
		CaseInsensitive: RuleCaseInsensitiveNone,
	},
	{
		Name:            "字符串等于",
		Code:            RuleOperatorEqString,
		Description:     "使用字符串对比等于",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "字符串不等于",
		Code:            RuleOperatorNeqString,
		Description:     "使用字符串对比不等于",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "正则匹配",
		Code:            RuleOperatorMatch,
		Description:     "使用正则表达式匹配,在头部使用(?i)表示不区分大小写,<a href=\"http://teaos.cn/doc/regexp/Regexp.md\" target=\"_blank\">正则表达式语法 &raquo;</a>",
		CaseInsensitive: RuleCaseInsensitiveYes,
	},
	{
		Name:            "正则不匹配",
		Code:            RuleOperatorNotMatch,
		Description:     "使用正则表达式不匹配,在头部使用(?i)表示不区分大小写,<a href=\"http://teaos.cn/doc/regexp/Regexp.md\" target=\"_blank\">正则表达式语法 &raquo;</a>",
		CaseInsensitive: RuleCaseInsensitiveYes,
	},
	{
		Name:            "包含字符串",
		Code:            RuleOperatorContains,
		Description:     "包含某个字符串",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "不包含字符串",
		Code:            RuleOperatorNotContains,
		Description:     "不包含某个字符串",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "包含前缀",
		Code:            RuleOperatorPrefix,
		Description:     "包含某个前缀",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "包含后缀",
		Code:            RuleOperatorSuffix,
		Description:     "包含某个后缀",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "包含索引",
		Code:            RuleOperatorHasKey,
		Description:     "对于一组数据拥有某个键值或者索引",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "版本号大于",
		Code:            RuleOperatorVersionGt,
		Description:     "对比版本号大于",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "版本号小于",
		Code:            RuleOperatorVersionLt,
		Description:     "对比版本号小于",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "版本号范围",
		Code:            RuleOperatorVersionRange,
		Description:     "判断版本号在某个范围内,格式为version1,version2",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP等于",
		Code:            RuleOperatorEqIP,
		Description:     "将参数转换为IP进行对比",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP大于",
		Code:            RuleOperatorGtIP,
		Description:     "将参数转换为IP进行对比",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP大于等于",
		Code:            RuleOperatorGteIP,
		Description:     "将参数转换为IP进行对比",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP小于",
		Code:            RuleOperatorLtIP,
		Description:     "将参数转换为IP进行对比",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP小于等于",
		Code:            RuleOperatorLteIP,
		Description:     "将参数转换为IP进行对比",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP范围",
		Code:            RuleOperatorIPRange,
		Description:     "IP在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "不在IP范围",
		Code:            RuleOperatorNotIPRange,
		Description:     "IP不在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP取模10",
		Code:            RuleOperatorIPMod10,
		Description:     "对IP参数值取模,除数为10,对比值为余数",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP取模100",
		Code:            RuleOperatorIPMod100,
		Description:     "对IP参数值取模,除数为100,对比值为余数",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
	{
		Name:            "IP取模",
		Code:            RuleOperatorIPMod,
		Description:     "对IP参数值取模,对比值格式为:除数,余数,比如10,1",
		CaseInsensitive: RuleCaseInsensitiveNo,
	},
}

Functions

func FindActionName

func FindActionName(action ActionString) string

Types

type Action

type Action struct {
}

type ActionDefinition

type ActionDefinition struct {
	Name        string
	Code        ActionString
	Description string
	Instance    ActionInterface
	Type        reflect.Type
}

action definition

type ActionInterface

type ActionInterface interface {
	Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)
}

func FindActionInstance

func FindActionInstance(action ActionString, options maps.Map) ActionInterface

type ActionString

type ActionString = string

type AllowAction

type AllowAction struct {
}

func (*AllowAction) Perform

func (this *AllowAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type BlockAction

type BlockAction struct {
	StatusCode int    `yaml:"statusCode" json:"statusCode"`
	Body       string `yaml:"body" json:"body"` // supports HTML
	URL        string `yaml:"url" json:"url"`
}

func (*BlockAction) Perform

func (this *BlockAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type CaptchaAction

type CaptchaAction struct {
}

func (*CaptchaAction) Perform

func (this *CaptchaAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type CaptchaValidator

type CaptchaValidator struct {
}

func (*CaptchaValidator) Run

func (this *CaptchaValidator) Run(request *requests.Request, writer http.ResponseWriter)

type GoGroupAction

type GoGroupAction struct {
	GroupId string `yaml:"groupId" json:"groupId"`
}

func (*GoGroupAction) Perform

func (this *GoGroupAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type GoSetAction

type GoSetAction struct {
	GroupId string `yaml:"groupId" json:"groupId"`
	SetId   string `yaml:"setId" json:"setId"`
}

func (*GoSetAction) Perform

func (this *GoSetAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type IPAction

type IPAction = string
const (
	IPActionAccept IPAction = "accept"
	IPActionReject IPAction = "reject"
)

type IPTable

type IPTable struct {
	Id       string   `yaml:"id" json:"id"`
	On       bool     `yaml:"on" json:"on"`
	IP       string   `yaml:"ip" json:"ip"`             // single ip, cidr, ip range, TODO support *
	Port     string   `yaml:"port" json:"port"`         // single port, range, *
	Action   IPAction `yaml:"action" json:"action"`     // accept, reject
	TimeFrom int64    `yaml:"timeFrom" json:"timeFrom"` // from timestamp
	TimeTo   int64    `yaml:"timeTo" json:"timeTo"`     // zero means forever
	Remark   string   `yaml:"remark" json:"remark"`
	// contains filtered or unexported fields
}

ip table

func NewIPTable

func NewIPTable() *IPTable

func (*IPTable) Init

func (this *IPTable) Init() error

func (*IPTable) Match

func (this *IPTable) Match(ip string, port int) (isMatched bool)

check ip

type LogAction

type LogAction struct {
}

func (*LogAction) Perform

func (this *LogAction) Perform(waf *WAF, request *requests.Request, writer http.ResponseWriter) (allow bool)

type Rule

type Rule struct {
	Description       string            `yaml:"description" json:"description"`
	Param             string            `yaml:"param" json:"param"`       // such as ${arg.name} or ${args}, can be composite as ${arg.firstName}${arg.lastName}
	Operator          RuleOperator      `yaml:"operator" json:"operator"` // such as contains, gt,  ...
	Value             string            `yaml:"value" json:"value"`       // compared value
	IsCaseInsensitive bool              `yaml:"isCaseInsensitive" json:"isCaseInsensitive"`
	CheckpointOptions map[string]string `yaml:"checkpointOptions" json:"checkpointOptions"`
	// contains filtered or unexported fields
}

rule

func NewRule

func NewRule() *Rule

func (*Rule) Init

func (this *Rule) Init() error

func (*Rule) IsSingleCheckpoint

func (this *Rule) IsSingleCheckpoint() bool

func (*Rule) MatchRequest

func (this *Rule) MatchRequest(req *requests.Request) (b bool, err error)

func (*Rule) MatchResponse

func (this *Rule) MatchResponse(req *requests.Request, resp *requests.Response) (b bool, err error)

func (*Rule) SetCheckpointFinder

func (this *Rule) SetCheckpointFinder(finder func(prefix string) checkpoints.CheckpointInterface)

func (*Rule) Test

func (this *Rule) Test(value interface{}) bool

type RuleCaseInsensitive

type RuleCaseInsensitive = string

type RuleConnector

type RuleConnector = string

type RuleGroup

type RuleGroup struct {
	Id          string     `yaml:"id" json:"id"`
	On          bool       `yaml:"on" json:"on"`
	Name        string     `yaml:"name" json:"name"` // such as SQL Injection
	Description string     `yaml:"description" json:"description"`
	Code        string     `yaml:"code" json:"code"` // identify the group
	RuleSets    []*RuleSet `yaml:"ruleSets" json:"ruleSets"`
	IsInbound   bool       `yaml:"isInbound" json:"isInbound"`
	// contains filtered or unexported fields
}

rule group

func NewRuleGroup

func NewRuleGroup() *RuleGroup

func (*RuleGroup) AddRuleSet

func (this *RuleGroup) AddRuleSet(ruleSet *RuleSet)

func (*RuleGroup) FindRuleSet

func (this *RuleGroup) FindRuleSet(id string) *RuleSet

func (*RuleGroup) FindRuleSetWithCode

func (this *RuleGroup) FindRuleSetWithCode(code string) *RuleSet

func (*RuleGroup) Init

func (this *RuleGroup) Init() error

func (*RuleGroup) MatchRequest

func (this *RuleGroup) MatchRequest(req *requests.Request) (b bool, set *RuleSet, err error)

func (*RuleGroup) MatchResponse

func (this *RuleGroup) MatchResponse(req *requests.Request, resp *requests.Response) (b bool, set *RuleSet, err error)

func (*RuleGroup) MoveRuleSet

func (this *RuleGroup) MoveRuleSet(fromIndex int, toIndex int)

func (*RuleGroup) RemoveRuleSet

func (this *RuleGroup) RemoveRuleSet(id string)

type RuleOperator

type RuleOperator = string
const (
	RuleOperatorGt           RuleOperator = "gt"
	RuleOperatorGte          RuleOperator = "gte"
	RuleOperatorLt           RuleOperator = "lt"
	RuleOperatorLte          RuleOperator = "lte"
	RuleOperatorEq           RuleOperator = "eq"
	RuleOperatorNeq          RuleOperator = "neq"
	RuleOperatorEqString     RuleOperator = "eq string"
	RuleOperatorNeqString    RuleOperator = "neq string"
	RuleOperatorMatch        RuleOperator = "match"
	RuleOperatorNotMatch     RuleOperator = "not match"
	RuleOperatorContains     RuleOperator = "contains"
	RuleOperatorNotContains  RuleOperator = "not contains"
	RuleOperatorPrefix       RuleOperator = "prefix"
	RuleOperatorSuffix       RuleOperator = "suffix"
	RuleOperatorHasKey       RuleOperator = "has key" // has key in slice or map
	RuleOperatorVersionGt    RuleOperator = "version gt"
	RuleOperatorVersionLt    RuleOperator = "version lt"
	RuleOperatorVersionRange RuleOperator = "version range"

	// ip
	RuleOperatorEqIP       RuleOperator = "eq ip"
	RuleOperatorGtIP       RuleOperator = "gt ip"
	RuleOperatorGteIP      RuleOperator = "gte ip"
	RuleOperatorLtIP       RuleOperator = "lt ip"
	RuleOperatorLteIP      RuleOperator = "lte ip"
	RuleOperatorIPRange    RuleOperator = "ip range"
	RuleOperatorNotIPRange RuleOperator = "not ip range"
	RuleOperatorIPMod10    RuleOperator = "ip mod 10"
	RuleOperatorIPMod100   RuleOperator = "ip mod 100"
	RuleOperatorIPMod      RuleOperator = "ip mod"

	RuleCaseInsensitiveNone = "none"
	RuleCaseInsensitiveYes  = "yes"
	RuleCaseInsensitiveNo   = "no"
)

type RuleOperatorDefinition

type RuleOperatorDefinition struct {
	Name            string
	Code            string
	Description     string
	CaseInsensitive RuleCaseInsensitive // default caseInsensitive setting
}

type RuleSet

type RuleSet struct {
	Id          string        `yaml:"id" json:"id"`
	Code        string        `yaml:"code" json:"code"`
	On          bool          `yaml:"on" json:"on"`
	Name        string        `yaml:"name" json:"name"`
	Description string        `yaml:"description" json:"description"`
	Rules       []*Rule       `yaml:"rules" json:"rules"`
	Connector   RuleConnector `yaml:"connector" json:"connector"` // rules connector

	Action        ActionString `yaml:"action" json:"action"`
	ActionOptions maps.Map     `yaml:"actionOptions" json:"actionOptions"` // TODO TO BE IMPLEMENTED
	// contains filtered or unexported fields
}

func NewRuleSet

func NewRuleSet() *RuleSet

func (*RuleSet) AddRule

func (this *RuleSet) AddRule(rule ...*Rule)

func (*RuleSet) Init

func (this *RuleSet) Init() error

func (*RuleSet) MatchRequest

func (this *RuleSet) MatchRequest(req *requests.Request) (b bool, err error)

func (*RuleSet) MatchResponse

func (this *RuleSet) MatchResponse(req *requests.Request, resp *requests.Response) (b bool, err error)

type WAF

type WAF struct {
	Id             string                `yaml:"id" json:"id"`
	On             bool                  `yaml:"on" json:"on"`
	Name           string                `yaml:"name" json:"name"`
	Inbound        []*RuleGroup          `yaml:"inbound" json:"inbound"`
	Outbound       []*RuleGroup          `yaml:"outbound" json:"outbound"`
	CreatedVersion string                `yaml:"createdVersion" json:"createdVersion"`
	Cond           []*shared.RequestCond `yaml:"cond" json:"cond"`

	ActionBlock *BlockAction `yaml:"actionBlock" json:"actionBlock"` // action block config

	IPTables []*IPTable `yaml:"ipTables" json:"ipTables"` // IP table list
	// contains filtered or unexported fields
}

func NewWAF

func NewWAF() *WAF

func NewWAFFromFile

func NewWAFFromFile(path string) (waf *WAF, err error)

func Template

func Template() *WAF

感谢以下规则来源: - Janusec: https://www.janusec.com/

func (*WAF) AddRuleGroup

func (this *WAF) AddRuleGroup(ruleGroup *RuleGroup)

func (*WAF) ContainsGroupCode

func (this *WAF) ContainsGroupCode(code string) bool

func (*WAF) Copy

func (this *WAF) Copy() *WAF

func (*WAF) CountInboundRuleSets

func (this *WAF) CountInboundRuleSets() int

func (*WAF) CountOutboundRuleSets

func (this *WAF) CountOutboundRuleSets() int

func (*WAF) FindCheckpointInstance

func (this *WAF) FindCheckpointInstance(prefix string) checkpoints.CheckpointInterface

func (*WAF) FindRuleGroup

func (this *WAF) FindRuleGroup(ruleGroupId string) *RuleGroup

func (*WAF) FindRuleGroupWithCode

func (this *WAF) FindRuleGroupWithCode(ruleGroupCode string) *RuleGroup

func (*WAF) Init

func (this *WAF) Init() error

func (*WAF) MatchConds

func (this *WAF) MatchConds(formatter func(string) string) bool

match cond

func (*WAF) MatchKeyword

func (this *WAF) MatchKeyword(keyword string) (matched bool, name string, tags []string)

match keyword

func (*WAF) MatchRequest

func (this *WAF) MatchRequest(rawReq *http.Request, writer http.ResponseWriter) (goNext bool, group *RuleGroup, set *RuleSet, err error)

func (*WAF) MatchResponse

func (this *WAF) MatchResponse(rawReq *http.Request, rawResp *http.Response, writer http.ResponseWriter) (goNext bool, group *RuleGroup, set *RuleSet, err error)

func (*WAF) MergeTemplate

func (this *WAF) MergeTemplate() (changedItems []string)

merge with template

func (*WAF) MoveInboundRuleGroup

func (this *WAF) MoveInboundRuleGroup(fromIndex int, toIndex int)

func (*WAF) MoveOutboundRuleGroup

func (this *WAF) MoveOutboundRuleGroup(fromIndex int, toIndex int)

func (*WAF) OnAction

func (this *WAF) OnAction(onActionCallback func(action ActionString) (goNext bool))

func (*WAF) RemoveRuleGroup

func (this *WAF) RemoveRuleGroup(ruleGroupId string)

func (*WAF) Save

func (this *WAF) Save(path string) error

save to file path

func (*WAF) Start

func (this *WAF) Start()

start

func (*WAF) Stop

func (this *WAF) Stop()

call stop() when the waf was deleted

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL