49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package middleware
|
||
|
||
import (
|
||
"github.com/EthanCodeCraft/xlgo-core/utils"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// 请求 ID 校验约束(M15 修复:不无条件信任客户端 X-Request-ID,防头注入/日志伪造)。
|
||
const (
|
||
// requestIDMaxLen 客户端传入请求 ID 的最大长度。超长视为非法并重新生成,避免日志膨胀/注入。
|
||
requestIDMaxLen = 128
|
||
)
|
||
|
||
// sanitizeRequestID 校验客户端传入的 X-Request-ID:仅允许可见 ASCII(0x20-0x7e)且
|
||
// 不含 CR/LF(防 HTTP 头注入与日志换行伪造),长度不超过 requestIDMaxLen。
|
||
// 非法或为空时返回 "",由调用方重新生成。
|
||
func sanitizeRequestID(id string) string {
|
||
if len(id) == 0 || len(id) > requestIDMaxLen {
|
||
return ""
|
||
}
|
||
for i := 0; i < len(id); i++ {
|
||
c := id[i]
|
||
if c < 0x20 || c > 0x7e {
|
||
return ""
|
||
}
|
||
}
|
||
return id
|
||
}
|
||
|
||
// RequestID 请求ID中间件,为每个请求生成唯一ID便于追踪。
|
||
//
|
||
// 客户端可经 X-Request-ID 头传入 ID 用于链路串联,但会做校验(M15 修复):
|
||
// 仅接受可见 ASCII、无换行、长度 ≤128 的值,否则忽略并重新生成——防头注入与日志伪造。
|
||
func RequestID() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
requestID := sanitizeRequestID(c.GetHeader("X-Request-ID"))
|
||
if requestID == "" {
|
||
requestID = utils.UUID()
|
||
}
|
||
c.Set("request_id", requestID)
|
||
c.Header("X-Request-ID", requestID)
|
||
c.Next()
|
||
}
|
||
}
|
||
|
||
// GetRequestID 从上下文获取请求ID
|
||
func GetRequestID(c *gin.Context) string {
|
||
return c.GetString("request_id")
|
||
} |