iris.context.writestring 不能直接拼接用户输入,因其原样写入响应体、不作 html 转义,易导致 xss;如 userinput 含 alert(1),ctx.writestring(""+userinput+"") 将触发脚本执行。

iris.Context.WriteString 为什么不能直接拼接用户输入
因为 WriteString 只是把字符串原样写入响应体,不做任何 HTML 转义。如果用户提交了 <script>alert(1)</script>,而你用 ctx.WriteString("<h3>" + userInput + "</h3>") 输出,浏览器就会执行脚本。
这不是 Iris 的 bug,而是设计使然:框架不替你决定数据该以什么上下文输出。你得自己负责转义时机和方式。
常见错误现象:
- 用户昵称里含
<b>admin</b>,页面上真渲染出加粗效果,但别人贴个<img src="x" onerror="alert(1)">就弹窗 - 评论列表页突然所有用户都触发了钓鱼请求 —— 因为某条存储型 XSS 载荷被直接
WriteString渲染了
iris.Render 模板中如何安全插值
Iris 默认启用 Go 标准库的 html/template,它会对 {{.Name}} 这类插值自动做 HTML 实体转义,前提是使用双大括号语法且变量类型是 string。
但注意几个关键点:
- 必须用
{{.Field}},不是{{.Field | safe}}或自定义safe函数 —— 后者会绕过转义 - 如果字段是
template.HTML类型,模板会跳过转义,所以别把用户输入强制转成这个类型 - URL 属性要单独处理:
<a href="%7B%7B.URL%7D%7D"></a>不够,得先确保.URL是合法 HTTPS 地址(比如用url.Parse校验 scheme/host),再用html.EscapeString包一层 - JavaScript 上下文完全不适用模板自动转义,
<script>var name = "{{.Name}}";</script>仍可能被闭合引号逃逸 —— 此时应改用 JSON 编码:var name = {{.NameJSON}};,后端把.Name用json.Marshal序列化并传入
富文本内容怎么放行又不失控
如果你真需要让用户发带格式的评论(比如支持 <b></b>、<ul></ul>),就不能依赖简单转义,得用净化器。
Iris 本身不提供 HTML 净化,推荐接入 bluemonday(Go 生态最成熟):
- 定义白名单策略:
bluemonday.UGCPolicy()允许常见排版标签,禁用on*事件、javascript:、data:协议 - 净化必须放在输出前,不是入库前 —— 存原始数据,渲染时再净化,避免双重编码或丢失语义
- 别用正则“删掉 script 标签”:攻击者可用
<scr>ipt></scr>或注释绕过 - 对图片 URL 额外校验:只允许 HTTPS + 白名单域名,防止通过
<img src="http://evil.com/xss?x-oss-process=image/resize,p_40">加载远程恶意资源
哪些地方最容易漏掉转义
最容易被忽略的是非 HTML 响应上下文,比如 JSON API 或 HTTP 头,它们看似“不执行 JS”,但仍有风险。
-
ctx.JSON():Go 的json.Marshal会自动转义为 <code>\u003c,这是安全的;但如果你手动拼 JSON 字符串(如ctx.WriteString(`{"name":"` + name + `"}`)),就完全不安全 -
ctx.ResponseWriter().Header().Set("X-User", userInput):HTTP 头不解析 HTML,但某些老浏览器或中间件可能误解析换行符(CRLF 注入),需过滤\r\n - 重定向 Location:
ctx.Redirect(302, "/profile?msg="+userInput)—— 这里userInput必须先url.QueryEscape,否则可注入恶意参数甚至换行 - 日志打印:
log.Printf("user input: %s", userInput)看似无害,但如果日志系统带 Web 查看界面且未转义,就变成 DOM 型 XSS 温床
真正难防的不是 <script></script>,而是那些“看起来像正常内容”的载荷,比如 <img src="x" onerror="fetch('/api/steal')"> —— 它能绕过多数前端关键词过滤,却在服务端模板里被原样吐出。防御的关键永远是:在最终输出点,按目标上下文做精准转义,而不是在输入时幻想“拦住所有坏字符”。











