场景1:用户输入表单(如评论框)
错误做法:直接渲染未过滤的用户输入
javascript
// WXML
<view>{{ userInput }}</view>
// JS(用户输入了恶意内容)
Page({
data: { userInput: '<script>alert("XSS攻击")</script>' }
})
结果 :小程序会自动转义,页面显示为文本:<script>alert("XSS攻击")</script>
,不会执行脚本。
防护原理 :数据绑定 ({``{ }}
) 默认转义 HTML 特殊字符(如 <
→ <
)。
场景2:动态渲染富文本(如用户发布的文章)
错误做法 :直接用 rich-text
渲染未过滤的内容
javascript
// WXML
<rich-text nodes="{{ userContent }}"></rich-text>
// JS(用户输入了危险内容)
Page({
data: {
userContent: '<img src="x" onerror="alert(1)">' // 包含恶意 onerror 事件
}
})
结果 :小程序 rich-text
组件会自动过滤 onerror
属性,最终渲染成 <img src="x">
。
防护原理 :rich-text
组件内置黑名单,过滤 script
、iframe
和危险属性(如 onclick
、onerror
)。
场景3:使用 web-view
嵌入外部网页
错误做法:加载不可信的第三方网页
html
<web-view src="{{ externalUrl }}"></web-view>
// JS(外部链接被篡改)
Page({
data: {
externalUrl: 'https://恶意网站.com?attack=...'
}
})
风险 :外部网页可能含有 XSS 攻击代码,通过 web-view
传播。
正确做法:
- 限制
web-view
只能加载白名单域名(在小程序后台配置)。 - 对
src
参数做合法性校验:
javascript
// 校验 URL 是否合法
if (!isValidUrl(externalUrl)) {
externalUrl = ''; // 拒绝加载
}
场景4:调用接口获取数据
错误做法:信任后端返回的未过滤数据
javascript
// 假设后端返回数据:{ content: '<script>恶意代码</script>' }
wx.request({
url: 'api/getData',
success: (res) => {
this.setData({ content: res.data.content }); // 直接渲染
}
})
结果 :虽然小程序默认转义,但如果数据用于不安全场景(如 web-view
),仍可能引发风险。
正确做法:
- 后端返回前对数据做 XSS 过滤。
- 前端对关键内容二次过滤:
javascript
// 使用微信提供的安全过滤函数(示例)
const safeContent = filterXSS(res.data.content);
this.setData({ content: safeContent });
场景5:用户昵称/简介中的特殊字符
错误做法:允许用户输入任意字符
javascript
// 用户输入昵称:<img src=x onerror=alert(1)>
Page({
data: { nickname: userInput }
})
结果 :渲染到页面时会被转义,但若其他地方误用(如转发到其他系统),可能引发风险。
正确做法:
- 输入时过滤危险字符:
javascript
// 前端过滤
const cleanNickname = nickname.replace(/[<>"'&]/g, '');
// 或调用微信内容安全接口(推荐)
wx.msgSecCheck({
content: nickname,
success: () => { /* 内容安全 */ },
fail: () => { /* 拦截危险内容 */ }
})
总结:XSS 防护口诀
- 数据绑定用双花 :
{``{ }}
默认转义,别用innerHTML
。 - 富文本要过滤 :
rich-text
或安全解析库。 - 用户输入必校验:前后端双重过滤。
- 动态代码要禁用 :别用
eval
、new Function
。 - 外部内容严管控 :
web-view
域名白名单。
附:XSS 测试工具
-
安全测试输入 :尝试输入以下内容,检查是否被转义:
html<img src=x onerror=alert(1)> <!-- 测试HTML属性 --> <script>alert(1)</script> <!-- 测试脚本标签 --> javascript:alert(1) <!-- 测试URL协议 -->