Gin 防 XSS 需输入校验、输出编码、CSP 三者结合;html/template 仅对 HTML 文本上下文自动转义,JS/CSS/URL/属性值须显式用 |js、|url 等函数处理,后端需白名单过滤或正则校验。

直接在 Gin 中防 XSS,不能只靠模板自动转义,必须分层设防:输入校验、输出编码、CSP 策略三者缺一不可;否则哪怕 html/template 转义了,攻击者仍可能通过 DOM 操作或未转义的 JS 上下文绕过。
用 html/template 渲染时必须显式声明上下文
Gin 默认使用 html/template,但它只对 {{.}} 在 HTML 文本上下文中自动转义,对 JS、CSS、URL 或属性值不自动处理:
- 错误写法:
<script>var name = "{{.UserName}}";</script>—— 双引号内仍是 JS 上下文,"和;不会被转义,可注入闭合语句 - 正确写法:
<script>var name = {{.UserName | js}}</script>或<script>var name = {{printf "%q" .UserName}}</script>,强制进入 JS 字符串上下文 - 所有动态插入到
href、src、onclick等属性中的变量,必须用| url、| htmlattr等对应函数修饰
后端接收用户输入时不能跳过白名单过滤
模板转义是“最后一道防线”,但不该承担输入净化责任。Gin 接收参数后应立即做结构化校验:
- 对富文本字段(如评论),用
bluemonday或go-sanitize做白名单 HTML 过滤,而非简单 strip tags - 对纯文本字段(如昵称、搜索词),用正则限制字符集:
^[a-zA-Z0-9u4e00-u9fa5_\-]{1,32}$,拒绝、<code>&、javascript:等危险模式 - 避免使用
c.PostForm("content")后直接存库或传给模板——中间必须经过清洗函数,例如:clean := bluemonday.UGCPolicy().Sanitize(input)
必须配合 Nginx 层 CSP 头,且禁用 'unsafe-inline'
仅靠 Go 层防护无法覆盖所有 XSS 场景(比如第三方 SDK 注入、CDN 脚本污染)。Nginx 必须统一注入 CSP:
- 先启用
Content-Security-Policy-Report-Only收集 3–7 天真实违规,再切为正式策略 - 禁止出现
'unsafe-inline'和'unsafe-eval';改用nonce:Nginx 动态生成并注入nonce="...",后端模板中同步写入<script nonce="{{.Nonce}}">...</script> - 所有
add_header必须带always参数,防止 302/404 等响应遗漏 CSP - 确认 Gin 或其他中间件没再输出同名头,否则会被覆盖——CSP 必须由 Nginx 单一源头管理
最易被忽略的是 DOM 型 XSS 场景:比如前端用 innerHTML = data 渲染服务端返回的 JSON 字段,此时 Go 层和 Nginx CSP 都无效,必须由前端用 textContent 或 DOMPurify.sanitize() 处理。后端能做的,是绝不返回未经清洗的原始 HTML 片段。


















