github.com/TeaOSLab/EdgeNode@v1.3.8/internal/waf/injectionutils/utils_sqli.go (about) 1 // Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . 2 3 package injectionutils 4 5 /* 6 #cgo CFLAGS: -O2 -I./libinjection/src 7 8 #include <libinjection.h> 9 #include <stdlib.h> 10 */ 11 import "C" 12 import ( 13 "github.com/TeaOSLab/EdgeNode/internal/utils/fasttime" 14 "github.com/TeaOSLab/EdgeNode/internal/waf/utils" 15 "github.com/cespare/xxhash/v2" 16 "net/url" 17 "strconv" 18 "strings" 19 "unicode/utf8" 20 "unsafe" 21 ) 22 23 // DetectSQLInjectionCache detect sql injection in string with cache 24 func DetectSQLInjectionCache(input string, isStrict bool, cacheLife utils.CacheLife) bool { 25 var l = len(input) 26 27 if l == 0 { 28 return false 29 } 30 31 if cacheLife <= 0 || l < 128 || l > utils.MaxCacheDataSize { 32 return DetectSQLInjection(input, isStrict) 33 } 34 35 var hash = xxhash.Sum64String(input) 36 var key = "WAF@SQLI@" + strconv.FormatUint(hash, 10) 37 var item = utils.SharedCache.Read(key) 38 if item != nil { 39 return item.Value == 1 40 } 41 42 var result = DetectSQLInjection(input, isStrict) 43 if result { 44 utils.SharedCache.Write(key, 1, fasttime.Now().Unix()+cacheLife) 45 } else { 46 utils.SharedCache.Write(key, 0, fasttime.Now().Unix()+cacheLife) 47 } 48 return result 49 } 50 51 // DetectSQLInjection detect sql injection in string 52 func DetectSQLInjection(input string, isStrict bool) bool { 53 if len(input) == 0 { 54 return false 55 } 56 57 if !isStrict { 58 if len(input) > 1024 { 59 if !utf8.ValidString(input[:1024]) && !utf8.ValidString(input[:1023]) && !utf8.ValidString(input[:1022]) { 60 return false 61 } 62 } else { 63 if !utf8.ValidString(input) { 64 return false 65 } 66 } 67 } 68 69 if detectSQLInjectionOne(input) { 70 return true 71 } 72 73 // 兼容 /PATH?URI 74 if (input[0] == '/' || strings.HasPrefix(input, "http://") || strings.HasPrefix(input, "https://")) && len(input) < 1024 { 75 var argsIndex = strings.Index(input, "?") 76 if argsIndex > 0 { 77 var args = input[argsIndex+1:] 78 unescapeArgs, err := url.QueryUnescape(args) 79 if err == nil && args != unescapeArgs { 80 return detectSQLInjectionOne(args) || detectSQLInjectionOne(unescapeArgs) 81 } else { 82 return detectSQLInjectionOne(args) 83 } 84 } 85 } else { 86 unescapedInput, err := url.QueryUnescape(input) 87 if err == nil && input != unescapedInput { 88 return detectSQLInjectionOne(unescapedInput) 89 } 90 } 91 92 return false 93 } 94 95 func detectSQLInjectionOne(input string) bool { 96 if len(input) == 0 { 97 return false 98 } 99 100 var fingerprint [8]C.char 101 var fingerprintPtr = (*C.char)(unsafe.Pointer(&fingerprint[0])) 102 var cInput = C.CString(input) 103 defer C.free(unsafe.Pointer(cInput)) 104 105 return C.libinjection_sqli(cInput, C.size_t(len(input)), fingerprintPtr) == 1 106 }