Iris中需手动设置安全头,用ctx.Header覆盖式添加,中间件统一配置更可靠;CSP需动态生成nonce并透传模板;Cookie必须显式设Secure、HttpOnly和SameSite。

怎么用iris.Context.SetHeader写安全头
直接调用 ctx.SetHeader 是最简单的方式,但要注意它不覆盖已存在的同名头,且必须在 ctx.JSON 或 ctx.View 之前执行。Iris 不会自动帮你加 X-Content-Type-Options: nosniff 这类头,全靠手动。
常见组合示例:
func (c *UserController) GetByID(ctx iris.Context) {
ctx.SetHeader("X-Content-Type-Options", "nosniff")
ctx.SetHeader("X-Frame-Options", "DENY")
ctx.SetHeader("X-XSS-Protection", "1; mode=block")
ctx.SetHeader("Referrer-Policy", "strict-origin-when-cross-origin")
ctx.JSON(user)
}
- 不要在中间件里统一设
Content-Security-Policy后又在 controller 里覆盖——Iris 不合并字符串,后设的会完全替换前设的 -
SetHeader对大小写不敏感,但值必须严格匹配规范(如"DENY"不能写成"deny") - 若需动态生成 CSP(比如带 nonce),必须在 handler 开头就计算好并
SetHeader,不能等模板渲染完再补
怎么用全局中间件统一加安全头
把重复逻辑提到中间件里更可靠,但要注意执行顺序:安全头中间件必须注册在路由匹配之后、controller 执行之前,否则可能被 controller 覆盖。
推荐注册位置(在 mvc.New() 之前或之后均可,但必须早于 app.Listen()):
app.Use(func(ctx iris.Context) {
ctx.Header("X-Content-Type-Options", "nosniff")
ctx.Header("X-Frame-Options", "DENY")
ctx.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
ctx.Next()
})
- 用
ctx.Header而非ctx.SetHeader——前者是强制覆盖,后者是追加(当头已存在时行为不一致) - HTTPS 环境下必须加
Strict-Transport-Security,否则浏览器不会强制跳转;本地开发可临时去掉 - 不要在中间件里调用
ctx.StatusCode()或ctx.JSON(),否则会中断正常流程
怎么避免CSP和script nonce冲突
Iris 模板不自动注入 nonce,你得自己生成、传入模板、再由前端脚本读取。整个链路断一环,CSP 就失效。
- 在 handler 中生成随机 nonce:
nonce := base64.StdEncoding.EncodeToString(randomBytes) - 通过
ctx.ViewData("Nonce", nonce)传给模板 - 在 HTML 模板中写:
<script nonce="{{.Nonce}}">...</script> - 对应设置 CSP:
ctx.Header("Content-Security-Policy", "script-src 'self' 'nonce-" + nonce + "'")
漏掉任意一步,浏览器控制台就会报 Refused to execute inline script。特别注意:nonce 值不能缓存、不能复用、不能硬编码。
为什么SetCookie的Secure和HttpOnly要手动开
Iris 的 ctx.SetCookie 默认不设 Secure 和 HttpOnly,这是历史兼容性设计,不是 bug。生产环境必须显式开启。
- HTTPS 下必须加
secure: true,否则 Cookie 会被浏览器拒绝发送 - 敏感 Cookie(如 session_id)必须加
httpOnly: true,否则 JS 可读取导致 XSS 泄露 - 示例:
ctx.SetCookie(&http.Cookie{Name: "session_id", Value: token, Secure: true, HttpOnly: true, SameSite: http.SameSiteLaxMode})
最容易忽略的是 SameSite:不设默认为 SameSite= lax,但现代浏览器对跨站 POST 请求会拦截,登录态丢失。建议明确写 SameSiteLaxMode 或 SameSiteStrictMode。


















