github.com/TeaOSLab/EdgeNode@v1.3.8/internal/waf/injectionutils/utils_xss.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  	"unsafe"
    20  )
    21  
    22  func DetectXSSCache(input string, isStrict bool, cacheLife utils.CacheLife) bool {
    23  	var l = len(input)
    24  
    25  	if l == 0 {
    26  		return false
    27  	}
    28  
    29  	if cacheLife <= 0 || l < 512 || l > utils.MaxCacheDataSize {
    30  		return DetectXSS(input, isStrict)
    31  	}
    32  
    33  	var hash = xxhash.Sum64String(input)
    34  	var key = "WAF@XSS@" + strconv.FormatUint(hash, 10)
    35  	if isStrict {
    36  		key += "@1"
    37  	}
    38  	var item = utils.SharedCache.Read(key)
    39  	if item != nil {
    40  		return item.Value == 1
    41  	}
    42  
    43  	var result = DetectXSS(input, isStrict)
    44  	if result {
    45  		utils.SharedCache.Write(key, 1, fasttime.Now().Unix()+cacheLife)
    46  	} else {
    47  		utils.SharedCache.Write(key, 0, fasttime.Now().Unix()+cacheLife)
    48  	}
    49  	return result
    50  }
    51  
    52  // DetectXSS detect XSS in string
    53  func DetectXSS(input string, isStrict bool) bool {
    54  	if len(input) == 0 {
    55  		return false
    56  	}
    57  
    58  	if detectXSSOne(input, isStrict) {
    59  		return true
    60  	}
    61  
    62  	// 兼容 /PATH?URI
    63  	if (input[0] == '/' || strings.HasPrefix(input, "http://") || strings.HasPrefix(input, "https://")) && len(input) < 1024 {
    64  		var argsIndex = strings.Index(input, "?")
    65  		if argsIndex > 0 {
    66  			var args = input[argsIndex+1:]
    67  			unescapeArgs, err := url.QueryUnescape(args)
    68  			if err == nil && args != unescapeArgs {
    69  				return detectXSSOne(args, isStrict) || detectXSSOne(unescapeArgs, isStrict)
    70  			} else {
    71  				return detectXSSOne(args, isStrict)
    72  			}
    73  		}
    74  	} else {
    75  		unescapedInput, err := url.QueryUnescape(input)
    76  		if err == nil && input != unescapedInput {
    77  			return detectXSSOne(unescapedInput, isStrict)
    78  		}
    79  	}
    80  
    81  	return false
    82  }
    83  
    84  func detectXSSOne(input string, isStrict bool) bool {
    85  	if len(input) == 0 {
    86  		return false
    87  	}
    88  
    89  	var cInput = C.CString(input)
    90  	defer C.free(unsafe.Pointer(cInput))
    91  
    92  	var isStrictInt = 0
    93  	if isStrict {
    94  		isStrictInt = 1
    95  	}
    96  	return C.libinjection_xss(cInput, C.size_t(len(input)), C.int(isStrictInt)) == 1
    97  }