深入分析 JavaScript eval() 和 new Function() 的安全风险，并讨论 CSP (Content Security Policy) 如何限制它们的滥用。

admin
Sat, 26 Jul 2025 17:59:34 +0000
Javascript, eval, javascript, new

各位程序猿朋友们，晚上好！我是今晚的客座讲师，代号“Bug终结者”。今天咱们聊聊JavaScript里两个威力巨大，但也危机四伏的家伙：eval() 和 new Function()，以及如何用CSP这把“安全锁”来驯服它们。 第一部分：eval() 和 new Function()：双刃剑的威力 先来认识一下这两位主角。 eval()：字符串界的变形金刚 eval() 是一个函数，它接收一个字符串作为参数，然后把这个字符串当成 JavaScript 代码来执行。简单粗暴，但也危险至极。你可以把它想象成一个“代码解释器”，藏在一个函数里。 let x = 10; let expression = "x + 5"; let result = eval(expression); // result 现在是 15 console.log(result); 看起来很方便，对吧？但如果 expression 的内容来自用户输入，那就完蛋了。想象一下： let userInput = prompt("请输入表达式："); // 用户输入 "window.location.href='http:// …

继续阅读“深入分析 JavaScript eval() 和 new Function() 的安全风险，并讨论 CSP (Content Security Policy) 如何限制它们的滥用。”

The post 深入分析 JavaScript eval() 和 new Function() 的安全风险，并讨论 CSP (Content Security Policy) 如何限制它们的滥用。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

各位程序猿朋友们，晚上好！我是今晚的客座讲师，代号“Bug终结者”。今天咱们聊聊JavaScript里两个威力巨大，但也危机四伏的家伙：eval() 和 new Function()，以及如何用CSP这把“安全锁”来驯服它们。

第一部分：eval() 和 new Function()：双刃剑的威力

先来认识一下这两位主角。

eval()：字符串界的变形金刚

eval() 是一个函数，它接收一个字符串作为参数，然后把这个字符串当成 JavaScript 代码来执行。简单粗暴，但也危险至极。你可以把它想象成一个“代码解释器”，藏在一个函数里。

let x = 10;
let expression = "x + 5";
let result = eval(expression); // result 现在是 15
console.log(result);

看起来很方便，对吧？但如果 expression 的内容来自用户输入，那就完蛋了。想象一下：

let userInput = prompt("请输入表达式："); // 用户输入 "window.location.href='http://evil.com'"
eval(userInput); // 你的网站就被重定向到 evil.com 了！

这就是 代码注入 的威力。用户输入恶意代码，eval() 照单全收，直接执行。

new Function()：动态代码生成器

new Function() 也是一个函数，它可以动态地创建新的 JavaScript 函数。它的参数是字符串，最后一个参数是函数体，前面的参数是函数的参数名。

let add = new Function('a', 'b', 'return a + b;');
let sum = add(2, 3); // sum 现在是 5
console.log(sum);

跟 eval() 类似，new Function() 也很灵活，但同样存在安全隐患。如果函数体来自用户输入，一样会造成代码注入。

let userFunctionBody = prompt("请输入函数体："); // 用户输入 "return alert('Hacked!');"
let evilFunction = new Function(userFunctionBody);
evilFunction(); // 弹出一个警告框，显示 "Hacked!"

第二部分：安全风险：一不小心，全盘皆输

eval() 和 new Function() 的安全风险主要集中在以下几个方面：

代码注入 (Code Injection)：这是最常见的风险。恶意用户通过控制传递给 eval() 或 new Function() 的字符串，注入任意 JavaScript 代码，从而窃取用户数据、篡改页面内容，甚至控制用户的浏览器。

性能问题：eval() 和 new Function() 在执行时，需要动态地编译代码，这会消耗大量的资源，降低程序的性能。而且，JavaScript 引擎通常无法对动态生成的代码进行优化，导致执行效率低下。

调试困难：动态生成的代码很难调试。因为代码是在运行时生成的，调试器可能无法跟踪到这些代码的执行过程，给调试带来很大的麻烦。

安全审查困难：使用 eval() 和 new Function() 的代码很难进行安全审查。因为代码的内容是在运行时确定的，安全审查人员无法提前发现潜在的安全漏洞。

为了更直观地展示这些风险，我们用一个表格来总结一下：

风险类型 | 描述 | 示例
代码注入 | 恶意用户通过控制字符串，注入任意 JavaScript 代码。 | eval("window.location.href='http://evil.com'")，new Function("return alert('Hacked!')")
性能问题 | 动态编译代码消耗大量资源，降低程序性能。 | 频繁调用 eval() 或 new Function() 生成大量代码。
调试困难 | 动态生成的代码很难调试，调试器可能无法跟踪到执行过程。 | 在复杂的程序中使用 eval() 或 new Function() 生成的代码，出现问题时难以定位。
安全审查困难 | 使用 eval() 和 new Function() 的代码很难进行安全审查，难以发现潜在的安全漏洞。 | 包含大量 eval() 和 new Function() 调用的代码，安全审查人员无法逐行分析，容易忽略潜在的漏洞。

第三部分：CSP：安全锁的正确用法

Content Security Policy (CSP) 是一种 HTTP 响应头，它允许网站管理员控制浏览器可以加载哪些资源。简单来说，CSP 就像一把安全锁，可以限制浏览器加载来自不可信来源的脚本、样式表、图片等资源，从而防止 XSS 攻击和其他安全漏洞。

CSP 的核心思想是 白名单。网站管理员需要明确指定哪些来源的资源是允许加载的，浏览器只会加载来自这些来源的资源，其他的资源都会被阻止。

CSP 主要通过 Content-Security-Policy HTTP 响应头来配置。这个响应头包含一系列指令，每个指令都定义了一种资源的加载策略。

script-src：控制 JavaScript 脚本的来源

script-src 指令用于控制浏览器可以加载哪些来源的 JavaScript 脚本。它可以指定具体的域名、协议、或者使用 self 关键字表示同源。

例如，以下 CSP 策略只允许加载来自同源的 JavaScript 脚本：

Content-Security-Policy: script-src 'self'

如果尝试加载来自其他来源的脚本，浏览器会阻止并发出警告。

script-src 指令还可以使用以下关键字：

'none'：禁止加载任何 JavaScript 脚本。

'unsafe-inline'：允许加载内联 JavaScript 脚本（例如，onclick 事件处理程序）。强烈不推荐使用，因为它会增加 XSS 攻击的风险。

'unsafe-eval'：允许使用 eval() 和 new Function()。强烈不推荐使用，因为它会增加代码注入的风险。

'nonce-{随机字符串}'：允许加载带有指定 nonce 属性的内联脚本。例如：


// 内联脚本


Content-Security-Policy: script-src 'nonce-r4nd0m'

nonce 属性的值必须是随机生成的，并且每次请求都不同。

'sha256-{哈希值}'：允许加载哈希值与指定值匹配的内联脚本。例如：


// 内联脚本


Content-Security-Policy: script-src 'sha256-YOUR_SCRIPT_HASH'

sha256 哈希值可以使用工具生成。

style-src：控制 CSS 样式表的来源

style-src 指令用于控制浏览器可以加载哪些来源的 CSS 样式表。它的用法与 script-src 类似。

例如，以下 CSP 策略只允许加载来自同源的 CSS 样式表：

Content-Security-Policy: style-src 'self'

style-src 指令也可以使用 'unsafe-inline' 关键字，允许加载内联样式。但同样 强烈不推荐使用。

img-src：控制图片的来源

img-src 指令用于控制浏览器可以加载哪些来源的图片。

例如，以下 CSP 策略只允许加载来自 example.com 域名的图片：

Content-Security-Policy: img-src example.com

default-src：设置默认的资源来源

default-src 指令用于设置所有资源的默认来源。如果某个资源没有明确指定来源，浏览器会使用 default-src 的值。

例如，以下 CSP 策略只允许加载来自同源的资源：

Content-Security-Policy: default-src 'self'

report-uri：报告违规行为

report-uri 指令用于指定一个 URL，浏览器会将 CSP 违规报告发送到该 URL。

例如：

Content-Security-Policy: default-src 'self'; report-uri /csp-report

当浏览器检测到 CSP 违规时，它会向 /csp-report 发送一个 JSON 格式的报告，包含违规的详细信息。

第四部分：CSP 与 eval() 和 new Function()：强力限制

CSP 可以通过 script-src 指令来限制 eval() 和 new Function() 的使用。

禁止使用 eval() 和 new Function()

最简单的方法是直接禁止使用 eval() 和 new Function()。只需要在 script-src 指令中不包含 'unsafe-eval' 关键字即可。

Content-Security-Policy: script-src 'self'

在这种情况下，如果代码中使用了 eval() 或 new Function()，浏览器会阻止并发出警告。

使用 nonce 或 hash 允许特定的动态代码

如果必须使用 eval() 或 new Function()，可以使用 nonce 或 hash 来允许特定的动态代码。

使用 nonce


let code = "alert('Hello from eval!')";
eval(code);


Content-Security-Policy: script-src 'nonce-r4nd0m'

使用 hash


let code = "alert('Hello from eval!')";
eval(code);


Content-Security-Policy: script-src 'sha256-YOUR_SCRIPT_HASH'

需要注意的是，使用 nonce 或 hash 只能允许特定的动态代码，不能允许任意的动态代码。

第五部分：实战演练：代码示例

下面我们通过一些代码示例来演示 CSP 的使用。

示例 1：禁止使用 eval() 和 new Function()

try {
    eval("alert('Hello from eval!')");
} catch (e) {
    console.error(e); // 浏览器会阻止 eval() 并抛出错误
}

try {
    new Function("alert('Hello from new Function!')")();
} catch (e) {
    console.error(e); // 浏览器会阻止 new Function() 并抛出错误
}

需要在 HTTP 响应头中设置以下 CSP 策略：

Content-Security-Policy: script-src 'self'

示例 2：使用 nonce 允许特定的动态代码


let code = "alert('Hello from eval!')";
eval(code);


需要在 HTTP 响应头中设置以下 CSP 策略：

Content-Security-Policy: script-src 'nonce-r4nd0m'

示例 3：使用 hash 允许特定的动态代码


let code = "alert('Hello from eval!')";
eval(code);


首先，需要计算内联脚本的 SHA256 哈希值。可以使用以下命令：

echo -n "let code = "alert('Hello from eval!')";neval(code);" | openssl dgst -sha256 -binary | base64

假设计算得到的哈希值是 YOUR_SCRIPT_HASH，则需要在 HTTP 响应头中设置以下 CSP 策略：

Content-Security-Policy: script-src 'sha256-YOUR_SCRIPT_HASH'

第六部分：最佳实践：让你的网站更安全

以下是一些使用 CSP 的最佳实践：

从最严格的策略开始，逐步放宽：先设置一个非常严格的 CSP 策略，然后根据实际需要逐步放宽。

使用 report-uri 收集违规报告：通过 report-uri 指令收集 CSP 违规报告，可以帮助你发现潜在的安全漏洞，并及时调整 CSP 策略。

定期审查 CSP 策略：随着网站的不断发展，CSP 策略也需要定期审查和更新。

不要使用 'unsafe-inline' 和 'unsafe-eval'：除非万不得已，否则不要使用 'unsafe-inline' 和 'unsafe-eval' 关键字。

使用 nonce 或 hash 允许特定的动态代码：如果必须使用 eval() 或 new Function()，可以使用 nonce 或 hash 来允许特定的动态代码。

在开发和测试环境中启用 CSP：在开发和测试环境中启用 CSP，可以帮助你尽早发现 CSP 违规问题。

了解浏览器兼容性：不同的浏览器对 CSP 的支持程度可能不同，需要了解浏览器的兼容性，并采取相应的措施。

第七部分：总结

eval() 和 new Function() 就像两把锋利的宝剑，用好了可以所向披靡，用不好则会伤人伤己。CSP 则是一把坚固的安全锁，可以有效地限制 eval() 和 new Function() 的滥用，保护你的网站免受 XSS 攻击和其他安全威胁。

记住，安全是一场永无止境的战斗。我们需要不断学习新的安全技术，并采取相应的措施，才能保护我们的网站和用户免受攻击。

今天的讲座就到这里。希望大家能够从中受益，并在实际开发中应用这些知识，让我们的代码更安全、更可靠。

感谢大家的聆听！下次再见！