Bläddra i källkod

fix(validation): 优化 URL 验证逻辑,支持中文域名并确保域名编码安全

- 调整 IP 地址检查顺序,提高验证效率
- 增加 UTF-8 编码有效性检查,防止非 UTF-8编码的字节流通过验证
- 优化中文域名处理逻辑,确保正确转换为 Punycode 格式
- 严格遵循 IDNA2008 标准,增强域名格式验证安全性
fusu 1 vecka sedan
förälder
incheckning
a8b8334720
1 ändrade filer med 34 tillägg och 11 borttagningar
  1. 34 11
      pkg/validation/validation.go

+ 34 - 11
pkg/validation/validation.go

@@ -15,6 +15,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"unicode/utf8"
 )
 
 // validate 是一个单例的 validator 实例,确保全局只有一个验证器,以提高性能。
@@ -156,10 +157,6 @@ func validateHostPort(fl validator.FieldLevel) bool {
 		return false // 格式不正确,或者主机或端口为空
 	}
 
-	// 检查主机部分是否为 IP 地址
-	if net.ParseIP(host) != nil {
-		return true
-	}
 
 	portInt, err := strconv.Atoi(port)
 	if err != nil {
@@ -169,6 +166,13 @@ func validateHostPort(fl validator.FieldLevel) bool {
 		return false
 	}
 
+	// 检查主机部分是否为 IP 地址
+	if net.ParseIP(host) != nil {
+		return true
+	}
+
+
+
 	// --- 如果不是 IP,则按域名处理(这是支持中文域名的关键部分) ---
 
 	// 4. 将可能为中文的域名转换为 Punycode (ASCII) 格式
@@ -190,18 +194,37 @@ func isIdnFqdn(fl validator.FieldLevel) bool {
 	// 获取字段的值
 	domain := fl.Field().String()
 
-	// omitempty 的行为由 validator 自身处理,
-	// 如果字段为空,我们的函数不应该判定为 false。
+	// omitempty 的行为由 validator 自身处理
 	if domain == "" {
 		return true
 	}
 
-	// idna.ToASCII 会将域名转换为 Punycode 格式。
-	// 这个过程本身就包含了对 IDNA2008 标准的严格验证。
-	// 如果域名格式不正确(例如包含非法字符、标签过长等),它会返回一个错误。
-	// 因此,我们只需要检查这个函数是否返回错误即可。
+	// 关键步骤 1:一个有效的 FQDN 必须包含至少一个点来分隔 TLD。
+	// 这会直接拦截掉 "你好世界" 这样的输入。
+	if !strings.Contains(domain, ".") {
+		return false
+	}
+
+	// 关键步骤 2:FQDN 不能以点开头或结尾。
+	// 注意:idna.ToASCII 会检查标签是否以连字符开头/结尾,所以我们只需要检查点。
+	if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") {
+		return false
+	}
+
+	// 关键步骤 3:检查是否为有效的 UTF-8 字符串。
+	// 这是防止非 UTF-8 编码字节流的关键。
+	if !utf8.ValidString(domain) {
+		return false
+	}
+
+	// 关键步骤 4:使用 idna.ToASCII 进行最严格的格式验证。
+	// 它会检查:
+	// - 是否包含非法字符(如 @, :, / 等)。
+	// - 每个标签(点之间的部分)是否过长。
+	// - 每个标签是否以连字符(-)开头或结尾。
+	// - 以及其他所有 IDNA2008 标准中定义的规则。
 	_, err := idna.ToASCII(domain)
 
-	// 如果没有错误,说明它是一个有效的(可能是国际化的)域名。
+	// 如果没有错误,说明它在格式上是一个有效的 FQDN
 	return err == nil
 }