toString() 不能直接检测混淆或防护注入,但可作为运行时完整性哨兵:通过比对哈希、检查返回值特征(如[native code]、可疑字符串)、验证toString是否被篡改,快速发现函数被包装、混淆或劫持。

函数的 toString() 方法本身不能直接用于代码混淆检测或逻辑注入防护,但它可以作为辅助手段,在特定场景下暴露异常行为——比如被恶意重写、包裹、或动态篡改的函数体内容。关键不在于“用 toString 检测混淆”,而在于:**当函数本体被非预期方式修改时,其字符串表示会泄露蛛丝马迹**。
识别被包装/代理的函数
许多混淆工具或运行时注入(如某些调试器插件、前端监控 SDK、甚至恶意脚本)会用 Proxy、高阶函数封装或 eval 重定义原生方法。此时虽然调用行为不变,但 toString() 返回值往往暴露真实来源:
- 原生函数(如
Array.prototype.push)调用toString()通常返回"function push() { [native code] }" - 被
Proxy包裹的函数,toString()默认返回"function () { [native code] }"(现代浏览器已屏蔽 Proxy 的自定义 toString),但若手动重写了toString属性,就可能返回可疑字符串,例如包含"eval("、"atob("、或明显 base64 片段的内容 - 被混淆器(如 JavaScript Obfuscator)处理后的函数,
toString()会显示大量乱码变量名、while(1)循环、或String.fromCharCode(...)拼接逻辑
检测 toString 被篡改的函数
攻击者可能直接覆盖函数自身的 toString 方法来隐藏真实行为。可比对函数是否仍使用内置实现:
- 用
Function.prototype.toString.call(fn) === fn.toString()判断是否被重写(注意:箭头函数和某些绑定函数不适用) - 检查
fn.toString是否为原生方法:fn.toString.toString().includes('[native code]')—— 若返回 false,说明toString本身被替换 - 对关键函数(如
fetch、XMLHttpRequest.prototype.send、console.log)定期快照其toString()结果并哈希,变化即告警
警惕基于 toString 的“假混淆”绕过
有些轻量级混淆仅靠 eval(toString()) 或 new Function(fn.toString()) 动态重建函数,看似“还原逻辑”,实则可能引入注入点:
- 若某处代码写成
const f = new Function('return ' + originalFn.toString())(),就给了中间劫持机会——只要提前污染originalFn.toString,就能控制生成的函数体 - 避免在生产环境使用
eval、new Function执行任意toString()输出;确需动态构造,应白名单校验字符串是否含危险模式(如/[;\{\}]+.*eval|function\(/i)
实用建议:轻量级运行时完整性检查
不依赖复杂 AST 解析,仅用 toString() 做快速水印验证:
- 在初始化阶段,对核心函数(如
JSON.parse、setTimeout)记录其toString()截断哈希(取前 32 字符 SHA-256 或简单 CRC32) - 在关键操作前(如提交表单、发起支付请求),重新计算并比对;差异则触发降级(如禁用自动填充、弹出提示)或上报
- 配合
Object.defineProperty冻结关键函数的toString属性(仅限非严格模式且支持 defineProperty 的环境)
本质上,toString() 是一个低开销、高可见性的函数“指纹窗口”。它不能替代 SRI、CSP 或代码签名,但在无构建期干预的运行时环境中,是发现浅层篡改与注入的可靠哨兵。

















