173 lines
4.4 KiB
Go
173 lines
4.4 KiB
Go
package validation
|
|
|
|
import (
|
|
"html"
|
|
"regexp"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// InputSanitizer provides comprehensive input sanitization
|
|
type InputSanitizer struct {
|
|
maxLength int
|
|
}
|
|
|
|
// NewInputSanitizer creates a new input sanitizer
|
|
func NewInputSanitizer(maxLength int) *InputSanitizer {
|
|
return &InputSanitizer{maxLength: maxLength}
|
|
}
|
|
|
|
// SanitizeString performs comprehensive sanitization on a string
|
|
func (s *InputSanitizer) SanitizeString(input string) string {
|
|
if input == "" {
|
|
return input
|
|
}
|
|
|
|
// Check length limit
|
|
if utf8.RuneCountInString(input) > s.maxLength {
|
|
input = string([]rune(input)[:s.maxLength])
|
|
}
|
|
|
|
// Remove null bytes and control characters
|
|
input = strings.Map(func(r rune) rune {
|
|
if r < 32 && r != 9 && r != 10 && r != 13 { // Allow tab, LF, CR
|
|
return -1
|
|
}
|
|
return r
|
|
}, input)
|
|
|
|
// HTML escape to prevent XSS
|
|
input = html.EscapeString(input)
|
|
|
|
// Remove potentially dangerous patterns
|
|
dangerousPatterns := []string{
|
|
`<script[^>]*>.*?</script>`,
|
|
`<iframe[^>]*>.*?</iframe>`,
|
|
`<object[^>]*>.*?</object>`,
|
|
`<embed[^>]*>.*?</embed>`,
|
|
`javascript:`,
|
|
`vbscript:`,
|
|
`data:`,
|
|
`on\w+\s*=`,
|
|
}
|
|
|
|
for _, pattern := range dangerousPatterns {
|
|
re := regexp.MustCompile(`(?i)` + pattern)
|
|
input = re.ReplaceAllString(input, "")
|
|
}
|
|
|
|
// Trim whitespace
|
|
return strings.TrimSpace(input)
|
|
}
|
|
|
|
// SanitizeSQLInput sanitizes input specifically for SQL queries
|
|
func (s *InputSanitizer) SanitizeSQLInput(input string) string {
|
|
input = s.SanitizeString(input)
|
|
|
|
// Additional SQL-specific sanitization
|
|
sqlPatterns := []string{
|
|
`;`, `--`, `/*`, `*/`, `@@`, `@`,
|
|
`xp_`, `sp_`, `exec`, `execute`,
|
|
`information_schema`, `sysobjects`,
|
|
`syscolumns`, `sysdatabases`,
|
|
}
|
|
|
|
for _, pattern := range sqlPatterns {
|
|
input = strings.ReplaceAll(input, pattern, "")
|
|
}
|
|
|
|
return input
|
|
}
|
|
|
|
// ValidateSQLSafe checks if input is safe for SQL queries
|
|
func (s *InputSanitizer) ValidateSQLSafe(input string) bool {
|
|
if input == "" {
|
|
return true
|
|
}
|
|
|
|
// Check for SQL injection patterns
|
|
suspiciousPatterns := []string{
|
|
"union select", "union all select",
|
|
"select.*from", "insert.*into", "update.*set", "delete.*from",
|
|
"drop table", "drop database", "alter table", "create table",
|
|
"information_schema", "sysobjects", "syscolumns", "sysdatabases",
|
|
"mysql.", "pg_", "sqlite_",
|
|
";--", "/*", "*/", "@@",
|
|
"script>", "<script",
|
|
"javascript:", "vbscript:",
|
|
"onload=", "onerror=", "eval(", "alert(",
|
|
}
|
|
|
|
lowerInput := strings.ToLower(input)
|
|
for _, pattern := range suspiciousPatterns {
|
|
if strings.Contains(lowerInput, pattern) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// SanitizeJSON sanitizes JSON input
|
|
func (s *InputSanitizer) SanitizeJSON(input string) string {
|
|
input = s.SanitizeString(input)
|
|
|
|
// Remove JSON-specific dangerous patterns
|
|
jsonPatterns := []string{
|
|
`{"\w+":\s*"[^"]*javascript:[^"]*"}`,
|
|
`{"\w+":\s*"[^"]*vbscript:[^"]*"}`,
|
|
`{"\w+":\s*"[^"]*data:[^"]*"}`,
|
|
}
|
|
|
|
for _, pattern := range jsonPatterns {
|
|
re := regexp.MustCompile(`(?i)` + pattern)
|
|
input = re.ReplaceAllString(input, "")
|
|
}
|
|
|
|
return input
|
|
}
|
|
|
|
// SanitizeFilename sanitizes filename inputs
|
|
func (s *InputSanitizer) SanitizeFilename(filename string) string {
|
|
filename = s.SanitizeString(filename)
|
|
|
|
// Remove path traversal attempts
|
|
filename = strings.ReplaceAll(filename, "../", "")
|
|
filename = strings.ReplaceAll(filename, "..\\", "")
|
|
|
|
// Remove dangerous characters for filenames
|
|
dangerousChars := []string{"/", "\\", ":", "*", "?", "\"", "<", ">", "|"}
|
|
for _, char := range dangerousChars {
|
|
filename = strings.ReplaceAll(filename, char, "")
|
|
}
|
|
|
|
return filename
|
|
}
|
|
|
|
// BatchSanitize sanitizes multiple inputs at once
|
|
func (s *InputSanitizer) BatchSanitize(inputs map[string]string) map[string]string {
|
|
sanitized := make(map[string]string)
|
|
for key, value := range inputs {
|
|
sanitized[key] = s.SanitizeString(value)
|
|
}
|
|
return sanitized
|
|
}
|
|
|
|
// IsValidInputLength checks if input length is within acceptable limits
|
|
func (s *InputSanitizer) IsValidInputLength(input string, minLen, maxLen int) bool {
|
|
length := utf8.RuneCountInString(input)
|
|
return length >= minLen && length <= maxLen
|
|
}
|
|
|
|
// ContainsHTML checks if input contains HTML tags
|
|
func (s *InputSanitizer) ContainsHTML(input string) bool {
|
|
htmlRegex := regexp.MustCompile(`<[^>]+>`)
|
|
return htmlRegex.MatchString(input)
|
|
}
|
|
|
|
// StripHTML removes HTML tags from input
|
|
func (s *InputSanitizer) StripHTML(input string) string {
|
|
htmlRegex := regexp.MustCompile(`<[^>]+>`)
|
|
return htmlRegex.ReplaceAllString(input, "")
|
|
}
|