mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-02 22:10:26 +08:00
自动升级WAF策略中SQL注入检测和XSS注入检测
This commit is contained in:
@@ -101,6 +101,9 @@ var upgradeFuncs = []*upgradeVersion{
|
||||
{
|
||||
"1.2.10", upgradeV1_2_10,
|
||||
},
|
||||
{
|
||||
"1.3.1.1", upgradeV1_3_2, // 1.3.2
|
||||
},
|
||||
}
|
||||
|
||||
// UpgradeSQLData 升级SQL数据
|
||||
@@ -816,3 +819,338 @@ func upgradeV1_2_10(db *dbs.DB) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 1.3.2
|
||||
func upgradeV1_3_2(db *dbs.DB) error {
|
||||
// waf
|
||||
{
|
||||
var disableSet = func(setId int64) error {
|
||||
_, err := db.Exec("UPDATE edgeHTTPFirewallRuleSets SET state=0 WHERE id=?", setId)
|
||||
return err
|
||||
}
|
||||
|
||||
var addRuleToGroup = func(groupId int64, setCode string, setName string, actions []*firewallconfigs.HTTPFirewallActionConfig, ruleParam string, ruleOperator string, value string) error {
|
||||
actionsJSON, err := json.Marshal(actions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rule
|
||||
ruleResult, err := db.Exec("INSERT INTO edgeHTTPFirewallRules (isOn, param, operator, value, isCaseInsensitive, state) VALUES (1, ?, ?, ?, 0, 1)", ruleParam, ruleOperator, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ruleId, err := ruleResult.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{
|
||||
{
|
||||
IsOn: true,
|
||||
RuleId: ruleId,
|
||||
},
|
||||
}
|
||||
ruleRefsJSON, err := json.Marshal(ruleRefs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set
|
||||
setResult, err := db.Exec("INSERT INTO edgeHTTPFirewallRuleSets (isOn, code, name, rules, connector, state, actions) VALUES (1, ?, ?, ?, 'or', 1, ?)", setCode, setName, ruleRefsJSON, actionsJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setId, err := setResult.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{
|
||||
{
|
||||
IsOn: true,
|
||||
SetId: setId,
|
||||
},
|
||||
}
|
||||
setRefsJSON, err := json.Marshal(setRefs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// group
|
||||
_, err = db.Exec("UPDATE edgeHTTPFirewallRuleGroups SET sets=? WHERE id=?", setRefsJSON, groupId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sql injection
|
||||
{
|
||||
ruleGroups, _, err := db.FindOnes("SELECT id, sets FROM edgeHTTPFirewallRuleGroups WHERE code='sqlInjection' AND state=1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ruleGroup := range ruleGroups {
|
||||
var setsJSON = ruleGroup.GetBytes("sets")
|
||||
if len(setsJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
|
||||
err = json.Unmarshal(setsJSON, &setRefs)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(setRefs) != 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
var isChanged = false
|
||||
for setIndex, setRef := range setRefs {
|
||||
set, setErr := db.FindOne("SELECT id, rules, isOn, actions FROM edgeHTTPFirewallRuleSets WHERE id=? AND state=1", setRef.SetId)
|
||||
if setErr != nil {
|
||||
return setErr
|
||||
}
|
||||
if set == nil {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var rulesJSON = set.GetBytes("rules")
|
||||
if len(rulesJSON) == 0 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
|
||||
err = json.Unmarshal(rulesJSON, &ruleRefs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ruleRefs) < 1 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
var actionsJSON = set.GetBytes("actions")
|
||||
if len(actionsJSON) == 0 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var actions = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||
err = json.Unmarshal(actionsJSON, &actions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !(len(actions) == 1 && actions[0].Code == firewallconfigs.HTTPFirewallActionBlock) {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
var rules = []maps.Map{}
|
||||
for _, ruleRef := range ruleRefs {
|
||||
rule, ruleErr := db.FindOne("SELECT * FROM edgeHTTPFirewallRules WHERE id=? AND state=1", ruleRef.RuleId)
|
||||
if ruleErr != nil {
|
||||
return ruleErr
|
||||
}
|
||||
if rule == nil {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
if isChanged {
|
||||
break
|
||||
}
|
||||
if len(rules) < 1 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
switch setIndex {
|
||||
case 0:
|
||||
var rule = rules[0]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `union[\s/\*]+select`) {
|
||||
isChanged = true
|
||||
}
|
||||
case 1:
|
||||
var rule = rules[0]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `/\*(!|\x00)`) {
|
||||
isChanged = true
|
||||
}
|
||||
case 2:
|
||||
if len(rules) != 4 {
|
||||
isChanged = true
|
||||
} else {
|
||||
{
|
||||
var rule = rules[0]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s(and|or|rlike)\s+(if|updatexml)\s*\(`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rule = rules[1]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s+(and|or|rlike)\s+(select|case)\s+`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rule = rules[2]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\s+(and|or|procedure)\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+(\s|$|--|#)`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rule = rules[3]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\(\s*case\s+when\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+\s+then\s+`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
var rule = rules[0]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `\b(updatexml|extractvalue|ascii|ord|char|chr|count|concat|rand|floor|substr|length|len|user|database|benchmark|analyse)\s*\(.*\)`) {
|
||||
isChanged = true
|
||||
}
|
||||
case 4:
|
||||
var rule = rules[0]
|
||||
if !(rule.GetString("param") == "${requestAll}" && rule.GetString("operator") == "match" && rule.GetString("value") == `;\s*(declare|use|drop|create|exec|delete|update|insert)\s`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if isChanged {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, setRef := range setRefs {
|
||||
err = disableSet(setRef.SetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = addRuleToGroup(ruleGroup.GetInt64("id"), "7010", "SQL注入检测", []*firewallconfigs.HTTPFirewallActionConfig{
|
||||
{
|
||||
Code: firewallconfigs.HTTPFirewallActionPage,
|
||||
Options: maps.Map{"status": 403, "body": ""},
|
||||
},
|
||||
}, "${requestAll}", firewallconfigs.HTTPFirewallRuleOperatorContainsSQLInjection, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// xss
|
||||
{
|
||||
ruleGroups, _, err := db.FindOnes("SELECT id, sets FROM edgeHTTPFirewallRuleGroups WHERE code='xss' AND state=1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ruleGroup := range ruleGroups {
|
||||
var setsJSON = ruleGroup.GetBytes("sets")
|
||||
if len(setsJSON) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var setRefs = []*firewallconfigs.HTTPFirewallRuleSetRef{}
|
||||
err = json.Unmarshal(setsJSON, &setRefs)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(setRefs) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
var isChanged = false
|
||||
for setIndex, setRef := range setRefs {
|
||||
set, setErr := db.FindOne("SELECT id, rules, isOn, actions FROM edgeHTTPFirewallRuleSets WHERE id=? AND state=1", setRef.SetId)
|
||||
if setErr != nil {
|
||||
return setErr
|
||||
}
|
||||
if set == nil {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var rulesJSON = set.GetBytes("rules")
|
||||
if len(rulesJSON) == 0 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var ruleRefs = []*firewallconfigs.HTTPFirewallRuleRef{}
|
||||
err = json.Unmarshal(rulesJSON, &ruleRefs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ruleRefs) != 1 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
var actionsJSON = set.GetBytes("actions")
|
||||
if len(actionsJSON) == 0 {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
var actions = []*firewallconfigs.HTTPFirewallActionConfig{}
|
||||
err = json.Unmarshal(actionsJSON, &actions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !(len(actions) == 1 && actions[0].Code == firewallconfigs.HTTPFirewallActionBlock) {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
rule, ruleErr := db.FindOne("SELECT * FROM edgeHTTPFirewallRules WHERE id=? AND state=1", ruleRefs[0].RuleId)
|
||||
if ruleErr != nil {
|
||||
return ruleErr
|
||||
}
|
||||
if rule == nil {
|
||||
isChanged = true
|
||||
break
|
||||
}
|
||||
|
||||
switch setIndex {
|
||||
case 0:
|
||||
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `(onmouseover|onmousemove|onmousedown|onmouseup|onerror|onload|onclick|ondblclick|onkeydown|onkeyup|onkeypress)\s*=`) {
|
||||
isChanged = true
|
||||
}
|
||||
case 1:
|
||||
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `(alert|eval|prompt|confirm)\s*\(`) {
|
||||
isChanged = true
|
||||
}
|
||||
case 2:
|
||||
if !(rule.GetString("param") == "${requestURI}" && rule.GetString("operator") == "match" && rule.GetString("value") == `<(script|iframe|link)`) {
|
||||
isChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if isChanged {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, setRef := range setRefs {
|
||||
err = disableSet(setRef.SetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = addRuleToGroup(ruleGroup.GetInt64("id"), "1010", "XSS攻击检测", []*firewallconfigs.HTTPFirewallActionConfig{
|
||||
{
|
||||
Code: firewallconfigs.HTTPFirewallActionPage,
|
||||
Options: maps.Map{"status": 403, "body": ""},
|
||||
},
|
||||
}, "${requestAll}", firewallconfigs.HTTPFirewallRuleOperatorContainsXSS, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -289,3 +289,23 @@ func TestUpgradeSQLData_v1_2_10(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
|
||||
func TestUpgradeSQLData_v1_3_2(t *testing.T) {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = db.Close()
|
||||
}()
|
||||
err = upgradeV1_3_2(db)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
Reference in New Issue
Block a user