iris需自定义中间件拦截user-agent或referer异常:先用ctx.getheader()提取,再结合白名单、黑名单、正则三重校验;referer需检查空值及域名合法性;ip拦截须解析x-forwarded-for并排除私有网段,命中后立即403并stopexecution。

怎么用中间件拦截 User-Agent 或 Referer 异常
直接看结论:Iris 中没有内置的恶意 UA 检测逻辑,必须在自定义中间件里手动提取并校验 ctx.GetHeader("User-Agent") 和 ctx.GetHeader("Referer")。常见漏判是只做字符串包含匹配,结果把正常爬虫(如 Googlebot)也干掉了。
正确做法是结合白名单 + 黑名单 + 正则模式三重判断:
- 先检查是否在可信 UA 白名单里(如
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)") - 再匹配已知恶意 UA 特征(如
"sqlmap"、"nikto"、"masscan"、"gobuster") - 对 Referer 做基础校验:空值或非预期域名(如前端是
https://app.example.com,但 Referer 是https://evil.com)可触发拦截
注意:ctx.GetHeader() 返回空字符串不等于 header 不存在——它可能只是没传,别直接 panic,应走 fallback 分支。
IP 黑名单拦截为什么总失效
问题核心在于:Iris 的 ctx.RemoteAddr() 默认拿到的是反向代理(如 Nginx)的 IP,不是真实客户端 IP。如果没配 X-Forwarded-For 解析,你封的其实是自己的负载均衡器。
必须手动解析转发链:
- 先读
ctx.GetHeader("X-Forwarded-For"),取逗号分隔后的第一个非私有 IP(如排除127.0.0.1、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16) - 若为空,再 fallback 到
ctx.RemoteAddr()(仅限直连场景) - 黑名单建议存在内存 map 或 Redis 中,避免每次查文件;命中后立即
ctx.StatusCode(403)+ctx.StopExecution(),别调ctx.Next()
别用 strings.Contains(ip, "192.168.") 这种粗暴方式——CIDR 匹配要用 net.IPNet.Contains()。
怎么防止恶意参数触发 SQL/XSS 注入
中间件里不能只过滤 query 参数,body(尤其是 application/json)和 form 数据同样危险。Iris 不自动解析 body,得自己调 ctx.ReadBody() 或 ctx.FormValue() 提前扫描。
推荐轻量级防御策略:
- 对所有字符串类型输入(query、form、JSON 字段)统一过一遍敏感字符检测:正则
`(?i)<script></script> - 长度超长字段(如单个参数 > 10KB)直接拒绝,防慢速攻击或日志刷屏
- 关键接口(如登录、密码重置)强制校验
Content-Type是否匹配预期,不匹配就 406
注意:不要在中间件里做完整 HTML 转义或 SQL 参数绑定——那是业务 handler 的事。中间件只负责“拦”,不负责“修”。
拦截后怎么记录又不影响性能
日志写磁盘或发网络会拖慢请求,尤其在高频拦截场景下。Iris 自带的 ctx.Application().Logger() 默认同步写,高并发时容易卡住。
实操建议:
- 拦截日志走异步通道:用
log.SetOutput()指向一个带缓冲的io.Writer(比如bufio.NewWriterSize(os.Stderr, 4096)) - 只记关键字段:客户端 IP、UA 片段、触发规则名、时间戳,别 dump 整个 ctx
- 加采样率:每 100 次拦截只记 1 条,避免日志爆炸(
if rand.Intn(100) == 0 { log... })
最易被忽略的一点:拦截中间件必须放在所有路由注册之前(app.Use()),否则嵌套路由组(如 admin.Party("/api"))不会继承它——Iris 的中间件不自动向下传递。











