全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-18 6 分钟 ✍️ juanwangdev

Gin XSS过滤

XSS(跨站脚本攻击)是 Web 常见安全漏洞,Gin 框架需从输入、输出、响应头三方面综合防护。

XSS攻击原理

攻击者注入恶意脚本到网页,在用户浏览器执行,窃取 Cookie、Session 或进行恶意操作。

HTML
<!-- 攻击示例 -->
<script>alert(document.cookie)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>

输入过滤

使用 validator 验证

Go
type CommentRequest struct {
    Content string `form:"content" binding:"required,max=500"`
}

func PostComment(c *gin.Context) {
    var req CommentRequest
    if err := c.ShouldBind(&req); err != nil {
        c.JSON(400, gin.H{"error": "参数错误"})
        return
    }
    // 存储前进行清理
    content := sanitizeInput(req.Content)
    // 保存到数据库
}

HTML 标签过滤

Go
import "strings"

// 简单过滤危险标签
func sanitizeInput(input string) string {
    // 移除 script 标签
    input = strings.ReplaceAll(input, "<script", "&lt;script")
    input = strings.ReplaceAll(input, "</script>", "&lt;/script&gt;")
    // 移除事件属性
    input = strings.ReplaceAll(input, "onerror", "data-onerror")
    input = strings.ReplaceAll(input, "onclick", "data-onclick")
    return input
}

使用专业库 bluemonday

Go
import "github.com/microcosm-cc/bluemonday"

func sanitizeHTML(input string) string {
    // 严格策略:只允许纯文本
    p := bluemonday.StrictPolicy()
    return p.Sanitize(input)
}

func sanitizeHTMLAllowBasic(input string) string {
    // 允许基本格式标签
    p := bluemonday.UGCPolicy()
    return p.Sanitize(input)
}

func PostComment(c *gin.Context) {
    var req CommentRequest
    if err := c.ShouldBind(&req); err != nil {
        c.JSON(400, gin.H{"error": "参数错误"})
        return
    }
    cleanContent := sanitizeHTML(req.Content)
    // 保存清理后的内容
}

输出转义

JSON 响应自动转义

Go
func GetUser(c *gin.Context) {
    user := User{
        Name: "<script>alert(1)</script>",
    }
    c.JSON(200, user)
    // 输出: {"name":"\u003cscript\u003ealert(1)\u003c/script\u003e"}
    // Gin 的 JSON 方法自动转义特殊字符
}

HTML 模板转义

Go
import "html/template"

func RenderPage(c *gin.Context) {
    data := gin.H{
        "Content": "<script>alert(1)</script>",
    }
    c.HTML(200, "page.html", data)
}

<!-- 模板文件 page.html -->
<!-- 自动转义 -->
<div>{{.Content}}</div>
<!-- 输出: <div>&lt;script&gt;alert(1)&lt;/script&gt;</div> -->

<!-- 需要原始输出时确保内容安全 -->
<div>{{.Content | safe}}</div>

Content-Type 设置

Go
func GetAPI(c *gin.Context) {
    // 明确设置 Content-Type,防止浏览器误解析
    c.Header("Content-Type", "application/json; charset=utf-8")
    c.JSON(200, gin.H{"data": "response"})
}

func DownloadFile(c *gin.Context) {
    // 文件下载时设置正确类型
    c.Header("Content-Type", "application/octet-stream")
    c.Header("Content-Disposition", "attachment; filename=file.txt")
    c.Data(200, "application/octet-stream", fileBytes)
}

Content-Security-Policy 头

Go
func SecurityHeaders() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 禁止内联脚本和外部脚本
        c.Header("Content-Security-Policy", "default-src 'self'; script-src 'self'")
        // 防止 MIME 类型嗅探
        c.Header("X-Content-Type-Options", "nosniff")
        // 防止点击劫持
        c.Header("X-Frame-Options", "DENY")
        // XSS 保护
        c.Header("X-XSS-Protection", "1; mode=block")
        c.Next()
    }
}

func main() {
    r := gin.Default()
    r.Use(SecurityHeaders())
}

防护策略对比

层面方法作用
输入validator + bluemonday过滤危险标签和属性
输出JSON自动转义 + 模板转义防止脚本执行
响应头CSP + X-XSS-Protection浏览器层面阻断

注意:XSS 防护需多层防御,不能只依赖单一措施。

要点总结

  1. 输入过滤:使用 bluemonday 清理 HTML 标签
  2. 输出转义:Gin JSON 响应自动转义,模板使用 {{.}}
  3. 响应头:设置 CSP、X-Content-Type-Options、X-XSS-Protection
  4. 验证长度:限制输入长度减少攻击面
  5. 避免 | safe 输出用户内容,除非明确安全

📝 发现内容有误?点击此处直接编辑

← 上一篇 Gin SQL注入防范
下一篇 → Gin 中间件安全控制
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库