跳转到内容

Security Primer

当你已经通过 稳定根 确认改动仍属于默认服务路径,而且问题进一步收窄到服务如何保护自身时,就打开这一页:验证身份、加固 HTTP headers、清洗输入,或防范滥用。

security 拥有 auth identity 基础元语、JWT 助手、security headers、输入安全和防滥用保护基础元语。它被标记为 risk: critical — 此处的每一次改动都可能影响整个攻击面。

claims, err := jwt.Verify(r, secretKey)
if err != nil {
_ = contract.WriteError(w, r, contract.NewErrorBuilder().
Type(contract.TypeUnauthorized).
Message("invalid token").
Build())
return
}
_ = contract.WriteResponse(w, r, http.StatusOK,
map[string]string{"sub": claims.Subject}, nil)
  • 你正在实现或验证 JWT token(security/jwt
  • 你正在设置或审计 HTTP security headers(security/headers
  • 你正在清洗用户输入或转义值(security/input
  • 你正在添加速率限制守卫或防滥用检测基础元语(security/abuse
  • 你正在对密码进行哈希或验证(security/password
  • 你正在读取或设置请求上的 auth identity(security/authn
  • 改动关于 session lifecycle、session 撤销或 tenant-session sentinel 错误 — 那属于 x/tenant
  • 改动添加了断路器或弹性封装 — 那属于 x/resilience
  • 改动引入了 app bootstrap、服务构造或持久化逻辑
  • 工作关于可观测性策略、结构化日志或请求追踪
  1. security/module.yaml
  2. security/authn/
  3. security/jwt/
  4. security/headers/
  5. security/input/
  6. security/abuse/
  7. security/password/
这些工作适合留在 security一旦变成这些问题就应移出
JWT 签发、验证与 claims 提取 — security/jwtsession 撤销、token 刷新编排或 tenant-session lifecycle
HTTP security headers:Content-Security-PolicyX-Frame-Options、HSTS — security/headers观察延迟、关联日志或计数错误的传输 middleware
输入清洗、HTML 转义或危险字符拒绝 — security/input带有领域特定不变量的业务规则验证
速率限制基础元语与防滥用信号检测 — security/abuse完整弹性编排,如断路器或自适应退避
密码哈希与计时安全比较 — security/password用户管理、档案存储或身份联合
import (
"github.com/spcent/plumego/security/jwt"
kvstore "github.com/spcent/plumego/store/kv"
)
store, _ := kvstore.NewKVStore(kvstore.Options{DataDir: "/var/lib/myapp/jwt"})
cfg := jwt.DefaultJWTConfig() // HMAC-SHA256,access 15m,refresh 7d
manager, _ := jwt.NewJWTManager(store, cfg)
// 签发 token 对
pair, _ := manager.GenerateTokenPair(ctx,
jwt.IdentityClaims{Subject: userID},
jwt.AuthorizationClaims{Roles: []string{"user"}},
)
// pair.AccessToken — 短期有效
// pair.RefreshToken — 长期有效
// 验证 token
claims, err := manager.VerifyToken(ctx, tokenString, jwt.TokenTypeAccess)

完整接入流程见 添加 JWT 认证指南

import "github.com/spcent/plumego/security/authn"
// 在 handler 中,auth 中间件运行后:
principal := authn.PrincipalFromContext(r.Context())
if principal == nil {
// 未认证 — 中间件应已拦截此请求
}
userID := principal.Subject
roles := principal.Roles
import (
"github.com/spcent/plumego/security/headers"
secmw "github.com/spcent/plumego/middleware/security"
)
policy := headers.DefaultPolicy() // 合理的默认值
// 或
policy := headers.StrictPolicy() // 更严格的 CSP,适合 SPA
mw, err := secmw.Middleware(secmw.Config{Policy: &policy})
if err != nil {
return err
}
app.Use(mw)

构建自定义 CSP:

csp := headers.NewCSPBuilder().
DefaultSrc("'self'").
ScriptSrc("'self'", "https://cdn.example.com").
StyleSrc("'self'", "'unsafe-inline'").
Build()
policy.ContentSecurityPolicy = csp
import "github.com/spcent/plumego/security/input"
if !input.ValidateEmail(email) { ... }
if !input.ValidateURL(rawURL) { ... }
clean := input.BestEffortSanitizeHTML(userContent) // 去除危险 HTML 标签
safe := input.StripControlChars(rawInput) // 去除控制字符
import "github.com/spcent/plumego/security/password"
hash, _ := password.HashPassword(plaintext)
err := password.CheckPassword(hash, plaintext) // 计时安全比较

安全是唯一一个部分正确会导致真实伤害的模块。security 的审查清单与所有其他稳定根不同:fail-closed 是强制要求,计时安全比较是强制要求,密钥绝不能被记录。了解哪个子包负责特定的安全问题,可以防止导致 auth 绕过或 header 注入的意外模糊。