mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 07:40:56 +08:00 
			
		
		
		
	增加Javascript Cookie验证
This commit is contained in:
		
							
								
								
									
										128
									
								
								internal/waf/action_js_cookie.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								internal/waf/action_js_cookie.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package waf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type JSCookieAction struct {
 | 
			
		||||
	BaseAction
 | 
			
		||||
 | 
			
		||||
	Life             int32  `yaml:"life" json:"life"`
 | 
			
		||||
	MaxFails         int    `yaml:"maxFails" json:"maxFails"`                 // 最大失败次数
 | 
			
		||||
	FailBlockTimeout int    `yaml:"failBlockTimeout" json:"failBlockTimeout"` // 失败拦截时间
 | 
			
		||||
	Scope            string `yaml:"scope" json:"scope"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) Init(waf *WAF) error {
 | 
			
		||||
	this.Scope = firewallconfigs.FirewallScopeGlobal
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) Code() string {
 | 
			
		||||
	return ActionJavascriptCookie
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) IsAttack() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) WillChange() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, req requests.Request, writer http.ResponseWriter) (allow bool) {
 | 
			
		||||
	// 是否在白名单中
 | 
			
		||||
	if SharedIPWhiteList.Contains("set:"+types.String(set.Id), this.Scope, req.WAFServerId(), req.WAFRemoteIP()) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nodeConfig, err := nodeconfigs.SharedNodeConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var life = this.Life
 | 
			
		||||
	if life <= 0 {
 | 
			
		||||
		life = 3600
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检查Cookie
 | 
			
		||||
	var cookieName = "ge_js_validator_" + types.String(set.Id)
 | 
			
		||||
	cookie, err := req.WAFRaw().Cookie(cookieName)
 | 
			
		||||
	if err == nil && cookie != nil {
 | 
			
		||||
		var cookieValue = cookie.Value
 | 
			
		||||
		if len(cookieValue) > 10 {
 | 
			
		||||
			var timestamp = cookieValue[:10]
 | 
			
		||||
			if types.Int64(timestamp) >= time.Now().Unix()-int64(life) && fmt.Sprintf("%x", md5.Sum([]byte(timestamp+"@"+nodeConfig.NodeId))) == cookieValue[10:] {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	writer.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
	writer.Header().Set("Cache-Control", "no-cache")
 | 
			
		||||
 | 
			
		||||
	var timestamp = types.String(time.Now().Unix())
 | 
			
		||||
 | 
			
		||||
	var cookieValue = timestamp + fmt.Sprintf("%x", md5.Sum([]byte(timestamp+"@"+nodeConfig.NodeId)))
 | 
			
		||||
 | 
			
		||||
	_, _ = writer.Write([]byte(`<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<title></title>
 | 
			
		||||
<meta charset="UTF-8"/>
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
document.cookie = "` + cookieName + `=` + cookieValue + `; path=/; max-age=` + types.String(life) + `;";
 | 
			
		||||
window.location.reload();
 | 
			
		||||
</script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
</body>
 | 
			
		||||
</html>`))
 | 
			
		||||
 | 
			
		||||
	// 记录失败次数
 | 
			
		||||
	this.increaseFails(req, waf.Id, group.Id, set.Id)
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *JSCookieAction) increaseFails(req requests.Request, policyId int64, groupId int64, setId int64) (goNext bool) {
 | 
			
		||||
	var maxFails = this.MaxFails
 | 
			
		||||
	var failBlockTimeout = this.FailBlockTimeout
 | 
			
		||||
 | 
			
		||||
	if maxFails <= 0 {
 | 
			
		||||
		maxFails = 10 // 默认10次
 | 
			
		||||
	} else if maxFails <= 3 {
 | 
			
		||||
		maxFails = 3 // 不能小于3,防止意外刷新出现
 | 
			
		||||
	}
 | 
			
		||||
	if failBlockTimeout <= 0 {
 | 
			
		||||
		failBlockTimeout = 1800 // 默认1800s
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var key = "JS_COOKIE:FAILS:" + req.WAFRemoteIP() + ":" + types.String(req.WAFServerId())
 | 
			
		||||
 | 
			
		||||
	var countFails = ttlcache.SharedCache.IncreaseInt64(key, 1, time.Now().Unix()+300, true)
 | 
			
		||||
	if int(countFails) >= maxFails {
 | 
			
		||||
		var useLocalFirewall = false
 | 
			
		||||
 | 
			
		||||
		if this.Scope == firewallconfigs.FirewallScopeGlobal {
 | 
			
		||||
			useLocalFirewall = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SharedIPBlackList.RecordIP(IPTypeAll, firewallconfigs.FirewallScopeService, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(failBlockTimeout), policyId, useLocalFirewall, groupId, setId, "JS_COOKIE验证连续失败超过"+types.String(maxFails)+"次")
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
@@ -5,18 +5,19 @@ import "reflect"
 | 
			
		||||
type ActionString = string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ActionLog      ActionString = "log"       // allow and log
 | 
			
		||||
	ActionBlock    ActionString = "block"     // block
 | 
			
		||||
	ActionCaptcha  ActionString = "captcha"   // block and show captcha
 | 
			
		||||
	ActionNotify   ActionString = "notify"    // 告警
 | 
			
		||||
	ActionGet302   ActionString = "get_302"   // 针对GET的302重定向认证
 | 
			
		||||
	ActionPost307  ActionString = "post_307"  // 针对POST的307重定向认证
 | 
			
		||||
	ActionRecordIP ActionString = "record_ip" // 记录IP
 | 
			
		||||
	ActionTag      ActionString = "tag"       // 标签
 | 
			
		||||
	ActionPage     ActionString = "page"      // 显示网页
 | 
			
		||||
	ActionAllow    ActionString = "allow"     // allow
 | 
			
		||||
	ActionGoGroup  ActionString = "go_group"  // go to next rule group
 | 
			
		||||
	ActionGoSet    ActionString = "go_set"    // go to next rule set
 | 
			
		||||
	ActionLog              ActionString = "log"       // allow and log
 | 
			
		||||
	ActionBlock            ActionString = "block"     // block
 | 
			
		||||
	ActionCaptcha          ActionString = "captcha"   // block and show captcha
 | 
			
		||||
	ActionJavascriptCookie ActionString = "js_cookie" // js cookie
 | 
			
		||||
	ActionNotify           ActionString = "notify"    // 告警
 | 
			
		||||
	ActionGet302           ActionString = "get_302"   // 针对GET的302重定向认证
 | 
			
		||||
	ActionPost307          ActionString = "post_307"  // 针对POST的307重定向认证
 | 
			
		||||
	ActionRecordIP         ActionString = "record_ip" // 记录IP
 | 
			
		||||
	ActionTag              ActionString = "tag"       // 标签
 | 
			
		||||
	ActionPage             ActionString = "page"      // 显示网页
 | 
			
		||||
	ActionAllow            ActionString = "allow"     // allow
 | 
			
		||||
	ActionGoGroup          ActionString = "go_group"  // go to next rule group
 | 
			
		||||
	ActionGoSet            ActionString = "go_set"    // go to next rule set
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AllActions = []*ActionDefinition{
 | 
			
		||||
@@ -44,6 +45,12 @@ var AllActions = []*ActionDefinition{
 | 
			
		||||
		Instance: new(CaptchaAction),
 | 
			
		||||
		Type:     reflect.TypeOf(new(CaptchaAction)).Elem(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:     "JS Cookie验证",
 | 
			
		||||
		Code:     ActionJavascriptCookie,
 | 
			
		||||
		Instance: new(JSCookieAction),
 | 
			
		||||
		Type:     reflect.TypeOf(new(JSCookieAction)).Elem(),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:     "告警",
 | 
			
		||||
		Code:     ActionNotify,
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ func CaptchaIncreaseFails(req requests.Request, actionConfig *CaptchaAction, pol
 | 
			
		||||
				useLocalFirewall = true
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SharedIPBlackList.RecordIP(IPTypeAll, firewallconfigs.FirewallScopeService, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(failBlockTimeout), policyId, useLocalFirewall, groupId, setId, "CAPTCHA验证连续失败")
 | 
			
		||||
			SharedIPBlackList.RecordIP(IPTypeAll, firewallconfigs.FirewallScopeService, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(failBlockTimeout), policyId, useLocalFirewall, groupId, setId, "CAPTCHA验证连续失败超过"+types.String(maxFails)+"次")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user