如何在浏览器控制台引入JS文件链接?CSP限制问题求解
问题背景
尝试使用以下代码在控制台引入外部JS文件:
document.write("<script src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-3.5.0.debug.js'></script>");
触发了CSP错误:
Refused to load the script
'...' because it
violates the following Content Security Policy directive: "script-src
'nonce-74eCu_hm3_B6K5S7B4_qbQ' 'strict-dynamic' 'report-sample'
'unsafe-eval' 'unsafe-inline' https: http:". Note that
'strict-dynamic' is present, so host-based allowlisting is disabled.
Note that 'script-src-elem' was not explicitly set, so 'script-src' is
used as a fallback.
可行解决方案
方法1:Fetch脚本内容后直接执行
利用当前CSP允许unsafe-eval的规则,先获取脚本源码再执行:
fetch('https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-3.5.0.debug.js') .then(response => response.text()) .then(code => eval(code));
这种方式绕开了外部域名脚本加载的限制,直接执行脚本内容,符合CSP的unsafe-eval许可。
方法2:通过Blob URL加载脚本
将外部脚本转为Blob URL后插入页面,Blob URL属于同源资源,可避开strict-dynamic对外部域名的限制:
fetch('https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-3.5.0.debug.js') .then(response => response.blob()) .then(blob => { const blobUrl = URL.createObjectURL(blob); const script = document.createElement('script'); script.src = blobUrl; document.body.appendChild(script); // 加载完成后释放Blob URL script.onload = () => URL.revokeObjectURL(blobUrl); });
原方法失效原因
当前CSP包含strict-dynamic指令,该指令会忽略基于域名的白名单(如https: http:),仅允许由已信任脚本(带合法nonce/哈希的脚本)发起的资源加载。而控制台通过document.write插入的外部脚本,不属于可信脚本发起的加载请求,因此被拦截。
内容的提问来源于stack exchange,提问作者Manue

