禁止直接使用gin.Default()启动生产服务,因其默认启用Logger和Recovery中间件,会泄露敏感信息、暴露源码路径及变量名,且未设安全响应头;应改用gin.New()手动注册中间件,自定义panic处理、日志输出与安全头。

直接暴露 Gin 的默认错误页、未校验输入、跳过中间件认证,等于把数据库密码贴在服务器门口。
禁止直接使用 gin.Default() 启动生产服务
它默认启用 Logger 和 Recovery 中间件,但 Recovery 会把 panic 堆栈完整返回给客户端——攻击者能从中看到路径、Go 版本、甚至变量名。更危险的是,gin.Default() 不设任何安全头,也不拦截敏感路径。
- 改用
gin.New()手动注册中间件,显式控制行为 - 替换
Recovery:用自定义中间件捕获 panic 并只返回通用错误(如{"error": "internal server error"}),日志写入本地文件或 Loki,绝不回传 - 必须添加基础安全响应头:
X-Content-Type-Options: nosniff、X-Frame-Options: DENY、X-XSS-Protection: 1; mode=block
JWT 认证中间件里别硬编码密钥或忽略签发时间
很多示例代码直接写 jwt.Parse(token, func() []byte { return []byte("my-secret") }),这会导致密钥泄露风险高、无法轮换;更常见的是没验证 exp 和 nbf 字段,让过期 Token 仍能访问。
- 密钥必须从环境变量加载,且长度 ≥ 32 字节(推荐用
crypto/rand生成) - 解析时强制校验时间:
jwt.WithValidTimeRange()或手动检查token.Claims.(jwt.MapClaims)["exp"] - 不要只依赖
token.Valid—— 它不校验时间,只检查签名和结构 - Token 存储在
Authorization: Bearer <token>,别接受 URL 参数或 Cookie 传 Token
静态资源别用 gin.Static() 直接挂载整个目录
gin.Static("/static", "./static") 看似方便,但一旦前端构建出 .git、.env 或 node_modules 被意外放入该目录,就会被直接下载。Gin 不做路径净化,GET /static/../../etc/passwd 在某些配置下也可能绕过。
立即学习“go语言免费学习笔记(深入)”;
- 改用
http.FileServer+http.StripPrefix+ 自定义FileSystem包装器 - 在 ServeHTTP 前拦截所有以
/.开头的路径,直接http.NotFound - 设置
Content-Security-Policy限制脚本只允许来自'self',防 XSS 注入后盗 Token - 前端资源统一走 Nginx 静态服务,Gin 只负责 API —— 这比在 Go 层做文件服务更安全、更快
SQL 查询必须用 GORM 的参数化,禁用 db.Raw() 拼接
Gin 本身不处理数据库,但开发者常在路由 handler 里直接调 db.Raw("SELECT * FROM users WHERE name = '" + name + "'")。这种写法哪怕加了 strings.TrimSpace 也挡不住 ' OR '1'='1。
- GORM 的
Where("name = ?", name)是安全的,底层走预编译,参数永远是数据,不是 SQL 片段 - 如果非要用
Raw,只允许占位符?(SQLite/MySQL)或$1(PostgreSQL),禁止字符串拼接 - 数据库账号权限最小化:应用账号只给
SELECT/INSERT/UPDATE,删表、建库、读系统表权限一律关闭 - 对用户输入做白名单过滤(如 ID 只允许数字,邮箱用
mail.ParseAddress校验格式),别信正则“差不多就行”
最易被忽略的一点:安全头和认证逻辑必须放在所有业务路由之前注册,中间件顺序错一位,整个防护就形同虚设。Gin 的 Use() 和 GET() 调用顺序就是执行顺序,没有隐式优先级。


















