Nessus扫描报前端JS有安全风险,这代码真有问题吗?

シ志玉 阅读 20

最近用Nessus扫我们项目,说前端这段JS存在“客户端脚本注入”风险,但我只是在做URL参数解析啊,这算漏洞吗?

我试过对参数做encodeURIComponent,但Nessus还是报同样的问题,有点懵。

const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
if (token) {
  document.getElementById('user-token').innerText = token;
}
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
♫梦媛
♫梦媛 Lv1
你这段代码确实有风险,Nessus报得没错,不是因为用了 innerText 就安全了,也不是因为没做 encodeURIComponent —— 关键问题在于你把用户可控的 URL 参数直接塞进 DOM 了,哪怕只是设置 innerText,也仍然可能被利用。

先说问题根源:
Nessus 报的是「客户端脚本注入」,本质是 XSS(Cross-Site Scripting)。
虽然你用的是 innerText,它确实不会把字符串当 HTML 解析,但问题出在元素本身的位置和上下文。比如:

- 如果这个 div#user-token 后面又被其他 JS 用 innerHTML 拼接进页面(常见于模板渲染)
- 或者它被嵌在某个 <a href="xxx"><img src="xxx"><script> 标签的属性里(比如你这个 token 最终被拼到 redirect URL 里)
- 甚至只是被后续的 eval()Function 构造器引用了,都可能触发 XSS

举个真实场景:
假设页面后续有这么一段代码:

document.getElementById('redirect').href = '/profile?token=' + document.getElementById('user-token').innerText;


如果攻击者构造 URL:

https://your-site.com/?token=123" onmouseover="alert(document.cookie)


那最后生成的 HTML 可能是:

<a id="redirect" href="/profile?token=123" onmouseover="alert(document.cookie)">...</a>


注意,这里 innerText 确实不会解析 HTML 标签,但它没做任何转义,所以双引号、空格、属性名都原样保留了,拼接进 HTML 属性时就形成事件劫持。

再比如更隐蔽的:
如果这个 token 之后被传给某个第三方 SDK,比如:

analytics.track('login', { token: token });


而这个 SDK 内部用了 JSON.parse + eval 或类似逻辑(不规范的 SDK 很多),那 payload 就能逃逸。



正确做法分三步走:

1. 校验参数合法性(白名单过滤)
token 通常应该是固定格式(比如 JWT、UUID、base64 字符串),不要无脑接受任意字符串。
例如只允许字母、数字、短横线、下划线、点号(具体按你业务定),其他一概丢弃或报错。

2. 设置时用 textContent,而不是 innerText
innerText 会触发重排(layout),还受 CSS 影响(比如 display:none 的元素它可能不返回内容),而 textContent 是纯文本节点操作,更干净。
重点不是它和 innerText 的区别,而是确保 DOM 插入点本身是安全的。

3. 关键:避免把用户输入拼到 HTML 属性、JS 上下文、URL 里
如果 token 最终要用于跳转或作为参数,必须用 encodeURIencodeURIComponent,但不是在获取时做,而是在使用时做。



修正后的代码示例(带防御性校验):

// 定义允许的 token 字符集(根据实际业务调整)
// 例如 JWT 通常是 base64url,只含 A-Za-z0-9-._
const TOKEN_REGEX = /^[A-Za-z0-9-._]+$/;

const urlParams = new URLSearchParams(window.location.search);
const rawToken = urlParams.get('token');

let safeToken = null;

// 1. 校验格式
if (rawToken !== null && TOKEN_REGEX.test(rawToken)) {
safeToken = rawToken;
} else if (rawToken !== null) {
// 可选:记录可疑请求(用于安全监控)
console.warn('Invalid token format detected:', rawToken);
}

// 2. 安全地设置文本(用 textContent,避免任何解析风险)
const tokenEl = document.getElementById('user-token');
if (tokenEl) {
// 清空旧内容,防止残留
tokenEl.textContent = safeToken || '';
}




额外提醒几个坑:

- 不要指望 innerHTML + DOMPurify 来救场——你这根本不需要 HTML,用 textContent 就行,别多此一举
- encodeURIComponent 只能防 URL 参数注入,防不住 HTML 注入,比如 <>innerText 场景里不会被解析成标签,但如果后续被拼进 HTML 属性," 这种实体还是能逃逸
- 真正的防御是:输入校验 + 上下文安全输出。URL 参数 → 文本节点 → 安全;URL 参数 → 属性值 → 用 encodeURI;URL 参数 → JS 字符串 → 用 JSON.stringify 包一层



最后说句实话:
Nessus 的扫描结果很多是“假阳性”,但它报这个确实有道理——你这代码在安全审计里属于「低风险但可优化」的典型,不是现在立刻会炸,但足够让安全扫描工具点名。
按上面改完,再扫基本就过了。
点赞 2
2026-02-25 10:24