如何使用内容安全策略保护 Node.js 应用程序

作者选择了自由软件基金会作为Write for DOnations计划的一部分接受捐赠

介绍

当浏览器加载页面时,它会执行大量代码来呈现内容。代码可以来自与根文档相同的来源,也可以来自不同的来源。默认情况下,浏览器不区分两者并执行页面请求的任何代码,而不考虑来源。攻击者利用此漏洞将脚本恶意注入页面,然后执行这些脚本,因为浏览器无法确定内容是否有害。在这些情况下,内容安全策略 (CSP) 可以提供保护。

CSP是HTTP标头,其提供安全性,防止代码注入攻击,如额外的层跨站点脚本(XSS) 点击劫持,和其他类似的攻击。它有助于创建受信任内容的“许可名单”,并阻止执行来自许可名单中不存在的来源的代码。它还会向您选择的 URL 报告任何违反策略的行为,以便您及时了解潜在的安全攻击。

使用 CSP 标头,您可以指定浏览器可以加载的网站内容的批准来源。任何不是来自批准来源的代码都将被阻止执行,这使得攻击者更难以注入内容和窃取数据。

在本教程中,您将通过在示例 Node.js 应用程序中实现一个来查看 CSP 标头提供的不同保护您还将收集 CSP 违规的 JSON 报告,以发现问题并快速修复漏洞。

先决条件

要遵循本教程,您将需要以下内容:

  • 您的机器上安装了最新版本的 Node.js。按照适用于您的操作系统的相关如何安装 Node.js教程中的步骤设置 Node.js 开发环境。

您还应该使用最新的浏览器版本,最好是Chrome,因为在撰写本文时(2020 年 11 月),它对CSP 级别 3 指令的支持最好此外,请确保在测试 CSP 实现时禁用任何第三方扩展,以便它们不会干扰控制台中呈现的违规报告。

步骤 1 — 设置演示项目

为了演示创建内容安全策略的过程,我们将完成为这个演示项目实现一个的整个过程这是一个包含各种内容的单页网站,类似于典型的网站或应用程序。它包括一个小型Vue.js应用程序、YouTube 嵌入以及一些来自Unsplash 的图像它还使用Google 字体Bootstrap 框架,后者通过内容交付网络 (CDN)加载

在此步骤中,您将在测试服务器或本地计算机上设置演示项目并在浏览器中查看它。

首先,使用以下命令将项目克隆到您的文件系统:

  • git clone https://github.com/do-community/csp-demo

设置项目目录后,使用以下命令切换到该目录:

  • cd csp-demo

接下来,package.json使用下一个命令安装文件中指定的依赖项您使用该express包来设置 Web 服务器,同时nodemon有助于在检测到目录中的文件更改时自动重新启动节点应用程序:

  • npm install

安装依赖项后,输入以下命令以在端口上启动 Web 服务器5500

  • npm start

您现在可以访问your_server_ip:5500localhost:5500在您的浏览器中查看演示页面。您将找到文本Hello World!、YouTube 嵌入以及页面上的一些图像。

CSP演示

在下一节中,我们将实施仅涵盖最基本保护的 CSP 策略。然后,我们将在随后的部分中继续构建,因为我们会发现我们需要在页面上允许的所有合法资源。

步骤 2 — 实施基本 CSP

让我们继续编写一个 CSP 策略,将字体、图像、脚本、样式和嵌入限制为仅源自当前主机的内容。以下是实现此目的的响应标头:

Content-Security-Policy: default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self';

以下是对此标头中的政策指令的解释:

  • font-src 定义可以从中加载字体的来源。
  • img-src 定义允许加载图像的来源。
  • script-src 控制网页上的任何脚本加载权限。
  • style-src 是允许样式表源的指令。
  • frame-src定义允许的框架嵌入源。(它在 CSP 级别 2 中弃用,但在级别 3 中恢复。)
  • default-src如果某些指令未在标头中明确指定,则为某些指令定义回退策略。这里是一个的指令的完整列表是回落到default-src

在此示例中,所有指定的指令都'self'在其源列表中分配了关键字。这表示应该只允许执行来自当前主机的资源(包括 URL 方案和端口号)。例如,script-src 'self'允许从当前主机执行脚本,但会阻止所有其他脚本源。

让我们继续将标头添加到我们的 Node.js 项目中。

保持您的应用程序运行并打开一个新的终端窗口以处理您的server.js文件:

  • nano server.js

接下来,在 Express 中间件层中添加示例中的 CSP 标头。这确保您在来自服务器的每个响应中都包含标头:

服务器.js
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();

app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self'"
  );
  next();
});

app.use(bodyParser.json());
app.use(express.static(path.join(__dirname)));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname + '/index.html'));
});

const server = app.listen(process.env.PORT || 5500, () => {
  const { port } = server.address();
  console.log(`Server running on PORT ${port}`);
});

保存文件并在浏览器中重新加载项目。您会注意到该页面已完全损坏。

我们的 CSP 标头按预期工作,我们在页面上包含的所有外部源都已被阻止加载,因为它们违反了定义的策略。但是,这不是测试全新策略的理想方式,因为它会在发生违规时破坏网站。

添加基本​​ CSP 后页面损坏

这就是Content-Security-Policy-Report-Only标题存在的原因。您可以使用它而不是Content-Security-Policy阻止浏览器执行策略,同时仍然报告发生的违规情况——这意味着您可以改进策略而不会使您的站点面临风险。一旦您对您的策略感到满意,您就可以切换回 enforcing 标头,以便激活保护。

继续并在您的文件中替换Content-Security-Policy标题Content-Security-Policy-Report-Onlyserver.js

  • nano server.js

添加以下突出显示的代码:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self'"
  );
  next();
});
. . .

保存文件并在浏览器中重新加载页面。页面返回到工作状态,但浏览器控制台仍报告 CSP 违规。每个违规都带有前缀,[Report Only]以指示未强制执行该策略。

仅报告模式现在处于活动状态

在本节中,我们创建了 CSP 的初始实现并将其设置为仅报告模式,以便我们可以对其进行改进而不会导致站点中断。在下一部分中,我们将修复通过初始 CSP 触发的违规行为。

第 3 步 – 修复违规行为

我们在上一节中实施的策略引发了多次违规,因为我们将所有资源仅限于来源——但是,我们在页面上有几个第三方资产。

修复 CSP 违规的两种方法是:批准政策中的来源,或删除触发违规的代码。由于合法资源会触发所有违规行为,因此我们将在本节中主要关注前一个选项。

打开浏览器控制台。它将显示所有当前违反 CSP 的情况。让我们解决每个问题。

允许样式表

控制台中的前两个违规来自 Google 字体和 Bootstrap 样式表,您分别从中加载https://fonts.googleapis.comhttps://cdn.jsdelivr.net您可以通过style-src指令在页面上允许它们

style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net;

这指定应在页面上执行来自原始主机https://fonts.googleapis.com、 和 的CSS 文件https://cdn.jsdelivr.net此策略非常广泛,因为它允许来自许可名单域(不仅仅是您当前使用的域)的任何样式表。

我们可以通过使用我们希望允许的确切文件或目录来更具体:

style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css;

现在,它将只允许执行确切的、指定的样式表。它会阻止所有其他样式表——即使它们来自https://cdn.jsdelivr.net.

您可以使用更新的style-src指令更新 CSP 标头,如下所示当您重新加载页面时,这两个违规行为都将得到解决:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self';"
  );
  next();
});
. . .

允许图像源

您在页面上使用的图像来自单一来源:https://images.unsplash.com让我们通过如下img-src指令允许它

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self'; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self'"
  );
  next();
});
. . .

允许 YouTube 嵌入

您可以<iframe>通过frame-src指令允许嵌套浏览上下文的有效来源,这些来源使用诸如, 之类的元素如果此指令不存在,浏览器将查找该child-src指令,然后返回到该default-src指令。

我们当前的政策限制框架嵌入到原始主机。让我们添加https://www.youtube.com到许可名单中,以便 CSP 在我们执行政策后不会阻止加载 Youtube 嵌入:

frame-src 'self' https://www.youtube.com;

请注意,www子域在这里很重要。如果您有来自 的嵌入https://youtube.com,它将根据此政策被阻止,除非您也将其添加https://youtube.com到许可名单:

frame-src 'self' https://www.youtube.com https://youtube.com;

这是更新后的 CSP 标头。更改frame-src指令如下:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self'; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
  );
  next();
});
. . .

允许字体文件

谷歌字体违规

Google 字体样式表包含对来自https://fonts.gstatic.com. 您会发现这些文件当前违反了定义的font-src策略(currently 'self'),因此您需要在修改后的策略中考虑它们:

font-src 'self' https://fonts.gstatic.com;

更新font-srcCSP 标头中指令,如下所示:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
  );
  next();
});
. . .

重新加载页面后,控制台将不再报告 Google 字体文件的违规情况。

允许 Vue.js 脚本

通过CDN加载的 Vue.js 脚本正在呈现Hello world!页面顶部的文本。我们将允许它通过script-src指令在页面上执行如前所述,在允许 CDN 源时要具体化很重要,这样我们就不会向该域上托管的其他可能的恶意脚本开放我们的站点。

script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js;

在此示例中,您只允许在页面上执行该 URL 上的确切脚本。如果您想在开发版本和生产版本之间切换,您还需要将另一个脚本 URL 添加到许可名单中,或者您可以允许该/dist位置中存在的所有资源,同时涵盖这两种情况:

script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/;

这是具有相关更改的更新后的 CSP 标头:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
  );
  next();
});
. . .

此时,我们已成功允许页面依赖的所有外部文件和脚本。但是由于页面上存在内联脚本,我们还有一个 CSP 违规需要解决。在下一节中,我们将探讨此问题的一些解决方案。

第 4 步 – 处理内联源

虽然您可以<script>使用'unsafe-inline'关键字批准CSP 中的内联代码(例如标签中的JavaScript 代码,但不建议这样做,因为它会大大增加代码注入攻击的风险。

此示例策略允许在页面上执行任何内联脚本,但由于上述原因,这并不安全。

script-src 'self' 'unsafe-inline' https://unpkg.com/[email protected]/dist/;

避免使用的最佳方法unsafe-inline是将内联代码移动到外部文件并以这种方式引用它。这是一种更好的缓存、缩小和可维护性方法,也使 CSP 在未来更容易修改。

但是,如果您绝对必须使用内联代码,有两种主要方法可以安全地将它们添加到您的许可名单。

选项 1 – 使用哈希

此方法要求您计算基于脚本本身的 SHA 哈希,然后将其添加到script-src指令中。在最新版本的 Chrome 中,您甚至不需要自己生成哈希值,因为它已包含在控制台的 CSP 违规错误中:

[Report Only] Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https://unpkg.com/[email protected]/dist/". Either the 'unsafe-inline' keyword, a hash ('sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='), or a nonce ('nonce-...') is required to enable inline execution.

此处突出显示的部分是您需要添加到script-src指令中以允许执行触发违规的特定内联脚本的确切 SHA256 哈希

复制哈希并将其添加到您的 CSP 中,如下所示:

script-src 'self' https://unpkg.com/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM=';

这种方式的缺点是如果脚本的内容发生变化,生成的hash就会不同,会触发违规。

选项 2 – 使用 Nonce

允许执行内联代码的第二种方法是使用nonce这些是随机字符串,您可以使用它们来允许完整的代码块,而不管其内容如何。

这是使用中的 nonce 值的示例:

script-src 'self' https://unpkg.com/[email protected]/dist/ 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

CSP 中的 nonce 值必须与nonce脚本上的属性匹配

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code
</script>

每次加载页面时,随机数必须不可猜测并动态生成,以便攻击者无法使用它们来执行恶意脚本。如果您决定实施此选项,您可以使用该crypto包生成一个 nonce,如下所示:

const crypto = require('crypto');
let nonce = crypto.randomBytes(16).toString('base64');

我们将在本教程中选择哈希方法,因为它对我们的用例更实用。

更新script-srcCSP 标头中指令以包含唯一内联脚本的 SHA256 哈希,如下所示:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://unpkg.com/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
  );
  next();
});
. . .

这将删除内联脚本从控制台触发的最终 CSP 违规错误。

在下一节中,我们将监控我们的 CSP 在生产环境中的效果。

步骤 5 — 监控违规行为

一旦你的 CSP 就位,有必要在使用后密切关注它的效果。例如,如果您忘记在生产中允许合法来源,或者当攻击者试图利用 XSS 攻击向量时(您需要立即识别并停止)。

如果没有某种形式的主动报告,就无法知道这些事件。这就是report-to指令存在的原因。它指定浏览器应将 JSON 格式的违规报告 POST 到的位置,以防它必须根据 CSP 采取行动。

要使用此指令,您需要添加一个额外的标头来指定报告 API的端点

Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"http://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}

设置后,在report-to指令中指定组名,如下所示:

report-to csp-endpoint;

这是server.js包含更改文件的更新部分请务必<your_server_ip>Report-To标头中占位符替换为您的实际服务器 IP 地址:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Report-To',
    '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://<your_server_ip>:5500/__cspreport__"}],"include_subdomains":true}'
  );
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint;"
  );
  next();
});
. . .

report-to指令旨在替换现已弃用的report-uri指令,但大多数浏览器尚不支持它(截至 2020 年 11 月)。因此,为了与当前浏览器兼容,同时确保与未来浏览器版本支持的兼容性,您应该在 CSP 中同时指定report-urireport-to如果支持后者,则会忽略前者:

服务器.js
. . .
app.use(function (req, res, next) {
  res.setHeader(
    'Report-To',
    '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}'
  );
  res.setHeader(
    'Content-Security-Policy-Report-Only',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint; report-uri /__cspreport__;"
  );
  next();
});
. . .

/__cspreport__路由也需要存在于服务器上;将其添加到您的文件中,如下所示:

服务器.js
. . .
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname + '/index.html'));
});

app.post('/__cspreport__', (req, res) => {
  console.log(req.body);
});
. . .

一些浏览器将Content-Type报告负载的发送application/csp-report,而其他浏览器使用application/json. 如果report-to支持指令,则Content-Type应该是application/reports+json.

要考虑所有可能的Content-Type值,您必须在 Express 服务器上设置一些配置:

服务器.js
. . .
app.use(
  bodyParser.json({
    type: ['application/json', 'application/csp-report', 'application/reports+json'],
  })
);
. . .

此时,任何 CSP 违规都会被发送到/__cspreport__路由并随后记录到终端。

您可以通过从不符合当前 CSP 的源中添加资源来尝试,或者修改index.html文件中的内联脚本,如下所示:

索引.html
. . .
<script>
  new Vue({
    el: '#vue',
    render(createElement) {
      return createElement('h1', 'Hello World!');
    },
  });
  console.log("Hello")
</script>
. . .

这将触发违规,因为脚本的哈希现在与您在 CSP 标头中包含的不同。

这是来自浏览器的典型违规报告,使用report-uri

{
  'csp-report': {
    'document-uri': 'http://localhost:5500/',
    referrer: '',
    'violated-directive': 'script-src-elem',
    'effective-directive': 'script-src-elem',
    'original-policy': "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-uri /__cspreport__;",
    disposition: 'report',
    'blocked-uri': 'inline',
    'line-number': 58,
    'source-file': 'http://localhost:5500/',
    'status-code': 200,
    'script-sample': ''
  }
}

本报告的部分是:

  • document-uri:发生违规的页面。
  • referrer: 页面的引用。
  • blocked-uri:违反页面策略的资源(inline在本例中脚本)。
  • line-number: 内联代码开始的行号。
  • violated-directive: 违反的具体指令。script-src-elem在这种情况下,回退到script-src.)
  • original-policy: 页面的完整策略。

如果浏览器支持该report-to指令,则有效负载应具有与以下内容类似的结构。注意它与report-uri有效载荷的不同之处,同时仍然携带相同的信息:

[{
    "age": 16796,
    "body": {
        "blocked-uri": "https://vimeo.com",
        "disposition": "enforce",
        "document-uri": "https://localhost:5500/",
        "effective-directive": "frame-src",
        "line-number": 58,
    'original-policy': "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-uri /__cspreport__;",
        "referrer": "",
        "script-sample": "",
        "sourceFile": "https://localhost:5500/",
        "violated-directive": "frame-src"
    },
    "type": "csp",
    "url": "https://localhost:5500/",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}]

注意:该report-to指令仅在安全上下文中受支持,这意味着您需要使用有效的 HTTPS 证书设置 Express 服务器,否则您将无法测试或使用它。

在本节中,我们成功地在我们的服务器上设置了 CSP 监控,以便我们可以快速检测和修复问题。让我们继续执行下一步中的最终策略来完成本教程。

第 6 步 – 发布最终政策

一旦您确信您的 CSP 设置正确(最好在仅报告模式下将其投入生产几天或几周后),您可以通过将 CSP 标头从 更改Content-Security-Policy-Report-OnlyContent-Security-Policy.

除了报告违规行为外,这还将阻止未经授权的资源在页面上执行,从而为您的访问者带来更安全的体验。

这是server.js文件的最终版本

服务器.js
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();

app.use(function (req, res, next) {
  res.setHeader(
    'Report-To',
    '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"http://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}'
  );
  res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/[email protected]/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint; report-uri /__cspreport__;"
  );
  next();
});

app.use(
  bodyParser.json({
    type: [
      'application/json',
      'application/csp-report',
      'application/reports+json',
    ],
  })
);
app.use(express.static(path.join(__dirname)));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname + '/index.html'));
});

app.post('/__cspreport__', (req, res) => {
  console.log(req.body);
});

const server = app.listen(process.env.PORT || 5500, () => {
  const { port } = server.address();
  console.log(`Server running on PORT ${port}`);
});

浏览器支持所有浏览器都支持

CSP 标头
,但 Internet Explorer 除外,它使用非标准标头。如果您需要支持 IE,则必须在响应头中发出两次 CSP。
X-Content-Security-Policy

最新版本的CSP 规范(级别 3)还引入了一些目前不太受支持的较新指令。示例包括script-src-elemprefetch-src指令。确保在设置这些指令时使用适当的回退,以确保保护在尚未赶上的浏览器中保持活动状态。

结论

在本文中,您已经为 Node.js 应用程序设置了有效的内容安全策略并监控了违规情况。如果您有一个较旧或更复杂的网站,则需要更广泛的策略设置来涵盖所有基础。但是,制定周密的策略是值得的,因为它使攻击者更难利用您的网站窃取用户数据。

您可以在此 GitHub 存储库 中找到本教程的最终代码

有关更多与安全相关的文章,请查看我们的安全主题页面如果您想了解有关使用 Node.js 的更多信息,可以阅读我们的如何在 Node.js 中编写代码系列

觉得文章有用?

点个广告表达一下你的爱意吧 !😁