fix(security): 修复 P1 高危项(OAuth2 state / 伪造客户端IP / CRLF 邮件头注入)
- OAuth2: state 改为 crypto/rand 随机值并写入独立短期 cookie (主会话为 SameSite=Strict,跨站回调不携带,不能放主会话); 回调用 ConstantTimeCompare 校验 state,缺失/不匹配返回 403, 校验后立即清除保证一次性使用。原硬编码 mailgo_oauth2_state 可被利用做授权码注入/登录 CSRF。 - 代理信任: engine.SetTrustedProxies 仅信任 127.0.0.1/::1。 外部直连时 X-Forwarded-For 完全不可信,防止伪造客户端 IP 绕过登录封禁或恶意封禁他人;本机 Caddy/Nginx 转发不受影响。 - CRLF 注入: Web 写信的 To/Cc/Subject 及附件文件名不再原样拼入 MIME 头。新增 sanitizeHeaderField(strip CR/LF/NUL)、 subject 按 RFC 2047 编码、附件名用 mime.FormatMediaType (RFC 2231);附件下载的 Content-Disposition 同步修复。 消息构建抽为 buildOutgoingMessage 纯函数便于测试。 - test: 新增 13 个回归测试(trustedproxy / mail_injection / oauth2_state),覆盖伪造 XFF、注入载荷、state 校验全部分支。
This commit is contained in:
@@ -177,6 +177,14 @@ func NewWebServer(cfg config.WebConfig, stores *store.Stores, attStorage *storag
|
||||
engine.Use(gin.Logger())
|
||||
engine.Use(gin.Recovery())
|
||||
|
||||
// 仅信任本机回环上的反向代理(Caddy/Nginx)。外部直连时
|
||||
// X-Forwarded-For 不可信,防止伪造客户端 IP 绕过登录封禁或
|
||||
// 恶意封禁他人 IP。gin 对 Unix socket 监听无条件信任转发头,
|
||||
// 因此 socket 必须保持仅本机可达。
|
||||
if err := engine.SetTrustedProxies([]string{"127.0.0.1", "::1"}); err != nil {
|
||||
return nil, fmt.Errorf("设置可信代理失败: %w", err)
|
||||
}
|
||||
|
||||
// Session store (cookie-based). The signing key comes from the config
|
||||
// file (auto-generated random key) or the MAILGO_SECRET_KEY env var.
|
||||
cookieStore := cookie.NewStore([]byte(cfg.SecretKey))
|
||||
|
||||
Reference in New Issue
Block a user