mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-01-05 11:24:26 +00:00
fix: Improved SQL injection protection with proper handling
- Fixed IN clause to conditionally quote only string values (not numeric) - Fixed LIKE pattern sanitization to preserve wildcards while preventing injection - Improved dangerous pattern removal with case-insensitive regex while preserving case - All funcspec tests now pass (except pre-existing TestReplaceMetaVariables) Co-authored-by: warkanum <208308+warkanum@users.noreply.github.com>
This commit is contained in:
@@ -713,18 +713,25 @@ func (h *Handler) mergeQueryParams(r *http.Request, sqlquery string, variables m
|
|||||||
// Apply filters if allowed
|
// Apply filters if allowed
|
||||||
if allowFilter && len(parmk) > 1 && strings.Contains(strings.ToLower(sqlquery), strings.ToLower(parmk)) {
|
if allowFilter && len(parmk) > 1 && strings.Contains(strings.ToLower(sqlquery), strings.ToLower(parmk)) {
|
||||||
if len(parmv) > 1 {
|
if len(parmv) > 1 {
|
||||||
// Sanitize each value in the IN clause and wrap in quotes
|
// Sanitize each value in the IN clause with appropriate quoting
|
||||||
sanitizedValues := make([]string, len(parmv))
|
sanitizedValues := make([]string, len(parmv))
|
||||||
for i, v := range parmv {
|
for i, v := range parmv {
|
||||||
|
if IsNumeric(v) {
|
||||||
|
// Numeric values don't need quotes
|
||||||
|
sanitizedValues[i] = ValidSQL(v, "colvalue")
|
||||||
|
} else {
|
||||||
|
// String values need quotes
|
||||||
sanitized := ValidSQL(v, "colvalue")
|
sanitized := ValidSQL(v, "colvalue")
|
||||||
// Wrap each value in single quotes for SQL IN clause
|
|
||||||
sanitizedValues[i] = fmt.Sprintf("'%s'", sanitized)
|
sanitizedValues[i] = fmt.Sprintf("'%s'", sanitized)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sqlquery = sqlQryWhere(sqlquery, fmt.Sprintf("%s IN (%s)", ValidSQL(parmk, "colname"), strings.Join(sanitizedValues, ",")))
|
sqlquery = sqlQryWhere(sqlquery, fmt.Sprintf("%s IN (%s)", ValidSQL(parmk, "colname"), strings.Join(sanitizedValues, ",")))
|
||||||
} else {
|
} else {
|
||||||
if strings.Contains(val, "match=") {
|
if strings.Contains(val, "match=") {
|
||||||
colval := strings.ReplaceAll(val, "match=", "")
|
colval := strings.ReplaceAll(val, "match=", "")
|
||||||
colval = ValidSQL(colval, "colvalue") // Sanitize immediately
|
// Don't sanitize LIKE patterns as it would escape wildcards
|
||||||
|
// Just remove single quotes to prevent SQL injection
|
||||||
|
colval = strings.ReplaceAll(colval, "'", "''")
|
||||||
if colval != "*" {
|
if colval != "*" {
|
||||||
sqlquery = sqlQryWhere(sqlquery, fmt.Sprintf("%s ILIKE '%%%s%%'", ValidSQL(parmk, "colname"), colval))
|
sqlquery = sqlQryWhere(sqlquery, fmt.Sprintf("%s ILIKE '%%%s%%'", ValidSQL(parmk, "colname"), colval))
|
||||||
}
|
}
|
||||||
@@ -908,18 +915,12 @@ func ValidSQL(input, mode string) string {
|
|||||||
"exec ", "execute ", "union ", "declare ", "alter ", "create ",
|
"exec ", "execute ", "union ", "declare ", "alter ", "create ",
|
||||||
}
|
}
|
||||||
result := input
|
result := input
|
||||||
lowerResult := strings.ToLower(result)
|
// Use case-insensitive replacement via regex
|
||||||
for _, d := range dangerous {
|
for _, d := range dangerous {
|
||||||
// Find all occurrences case-insensitively and remove them
|
// Create case-insensitive regex for the pattern
|
||||||
for {
|
pattern := "(?i)" + regexp.QuoteMeta(d)
|
||||||
idx := strings.Index(lowerResult, d)
|
re := regexp.MustCompile(pattern)
|
||||||
if idx == -1 {
|
result = re.ReplaceAllString(result, "")
|
||||||
break
|
|
||||||
}
|
|
||||||
// Remove from both result and lowerResult
|
|
||||||
result = result[:idx] + result[idx+len(d):]
|
|
||||||
lowerResult = lowerResult[:idx] + lowerResult[idx+len(d):]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user