内容安全战略(CSP):每个Web开发人员都有必要知道的

这是一个全面的内容安全战略(CSP)攻略。假如您是一名web开发者,CSP是一个重要的概念,需求了解,以保护您的用户免受跨站点脚本(XSS)注入进犯。

在本文中,咱们将学习(简直)关于内容安全战略(CSP)的一切内容。即便你曾经从未听说过CSP,也不知道它是什么,我保证,在文章的最后,你会有一个坚实的了解和详细的,一步一步的方案,以保护您的网站和应用程序免受跨站点脚本(XSS)注入进犯。

问题:跨站点脚本怎么注入

大多数Web应用程序从数据库中获取数据,将其刺进到HTML模板并发送到浏览器。进犯者通过网站上的表单提交恶意JavaScript到数据库中。在下一个恳求中,服务器将过错的脚本发送到浏览器,浏览器会以为该脚本来自您的服务器。

让咱们幻想一下,您是一名黑客,想要盗取电子商务网站用户的信用卡号码。

你是怎样办到的

您能够做的一件事是编写一些JavaScript,在用户输入其信用卡详细信息时记录支付页面上的每笔交易。

由于浏览器履行页面上的任何JavaScript,而JavaScript能够读取、写入或修改网站的任何部分,假如您能找到一种办法在电子商务网站上刺进您的糟糕的JavaScript代码,那么用户的信用卡号码就不再安全了。

可是浏览器要履行这个JavaScript,它是网站代码的一部分。

你怎样能在电子商务网站上取得这种糟糕的JavaScript代码,以便用户的浏览器在他们付款时履行它?

你注意到这个电子商务网站上有一个表单,任何人都能够添加对产品的谈论。所以你创立了一个帐户,而不是一个真实的谈论,你在文本区域键入以下代码。

内容安全战略(CSP):每个Web开发人员都有必要知道的

点击提交按钮后,您会看到弹出的警告窗口,显现您刚刚输入的音讯。

内容安全战略(CSP):每个Web开发人员都有必要知道的

怎样会这样?

在你提交谈论后,浏览器将虚伪谈论发送到电子商务网站的后端服务器,后者将其以纯文本形式保存在数据库中。

内容安全战略(CSP):每个Web开发人员都有必要知道的

接下来,在对该恳求的响应中,后端将您重定向到相同的产品页面,该页面刷新并从后端获取相同的虚伪谈论。后端脚本当即从数据库中获取存储的谈论并将其发送到浏览器。

内容安全战略(CSP):每个Web开发人员都有必要知道的

在收到包括虚伪谈论的HTML时,浏览器以为这是您想要履行的脚本,并当即履行它,并向您显现警告框。

更重要的是,由于谈论是揭露的,而且对网站的每个用户都是可见的,因而包括注入脚本的相同HTML将发送给每个其他用户,用相同的警报迎接他们!

您编写了一个精心设计的脚本,记录用户的点击,并宣布一个获取恳求,将一切数据发布到您的其他网站,这将保存一切这些信息,以便您稍后运用。或许,您能够通过访问用户的会话信息来彻底绑架用户的会话,这样您就能够以该用户的身份长途登录。

然后,您以相同的办法将其刺进数据库,在产品页面上添加另一个虚伪谈论。

祝贺您,您成功完成了跨站点脚本进犯!

进犯者能够运用站点脚本漏洞进犯从数据库获取用户提交数据的任何页面。进犯者将向数据库中注入过错的JavaScript代码,这些代码稍后将由网站获取,并在用户访问网站时由用户的浏览器履行。

XSS是最常见的安全漏洞。进犯者能够测验将此脚本注入他们能够提交表单的任何当地,例如文章的标题或正文、产品谈论或谈论。假如网站不阻挠XSS,能够彻底访问网站上的数据。

现在从电子商务网站开发者的视点来思考。怎么缓解这种进犯?

处理方案一:转义HTML字符

防止跨站点脚本进犯的一个简略处理方案是获取一切用户提交的文本,并将其间的任何特别操控字符(如<>等)替换为相应的实体编码。这被称为字符转义。

例如,HTML

<script>alert('hello world')</script>

转换为

&lt;script&gt;alert('hello world')&lt;/script&gt;

当浏览器看到转义的内容时,它会像对待一般文本一样识别并出现它,但不会像对待HTML符号一样对待它。换句话说,它不会履行转义的<script>符号中的代码,这正是咱们想要的。

通常,您需求在HTML的上下文中转义以下字符,以便它们添加任何特别行为。

  1. 小于符号(<)&lt;
  2. 大于符号(>),&gt;
  3. 双引号(“), &quot;
  4. 单引号(’),&#39;
  5. (&),&amp;

通常,您不需求忧虑转义特别字符,由于大多数现代Web框架都会为您处理它。

在许多情况下,保证用户提交的HTML内容被正确地转义需求很长的路要走。

处理方案二:内容安全战略

CSP背后的根本思想是阻挠内联脚本履行,并提供答应的可信内容源列表(脚本,款式表,字体,插件等)。到浏览器。即便进犯者注入了他们的坏脚本,浏览器也不会履行它,由于CSP阻挠了内联脚本的履行。

XSS进犯的底子原因是浏览器能够履行HTML中包括的任何和一切内联JavaScript。假如有一种办法能够告知浏览器不要履行任何内联JavaScript,以及任何从外部域加载的脚本,那会怎样样?

您能够运用HTTP响应上的Content-Security-Policy头来完成这一点,它规则了内容的安全战略。从本质上讲,这个header做了两件事:

  1. 指示浏览器阻挠一切内联脚本履行
  2. 提供一个安全域列表,从那里加载外部资源,防止一切其他来历。

尽管它通常用于脚本,但它也操控其他资源,如款式表,字体,插件等。

完成严厉的CSP能够防止浏览器从任何其他位置获取脚本。这使得很难在你的网站中注入糟糕的JavaScript代码。即便他们以某种办法注入它,浏览器也不会履行它,由于它是内联的。

一切现代浏览器都支持CSP。由于跨站点脚本进犯是由于浏览器上不必要的JavaScript履行而产生的,因而确定一切外部和内联JavaScript对防止XSS进犯大有协助。

当您的网站完成严厉的CSP时,进犯者将无法在网站上运转任何过错的JavaScript。

那么,它是怎么作业的?

这是一个规范CSP头的比如。

Content-Security-Policy: script-src 'self' https://safe-external-site.com; style-src 'self'

在上面的头文件中,术语script-srcstyle-src是分别为JavaScript和款式表指定有用源的指令。

这两个指令都告知浏览器不要履行任何内联JavaScript或款式表。

  1. 脚本战略告知浏览器只运转从同一个域(self)或从域safe-external-site.com获取的脚本。
  2. 款式战略告知它只答应来自相同域的款式表。不答应运用外部款式表。

您也能够在<head>元素下的<meta>符号中提供战略,而不是运用HTTP头。

下面是通过<meta>标签提供的内容安全战略。

<meta http-equiv="Content-Security-Policy" content="script-src 'self' https://safe-external-site.com">

“unsafe-inline”答应您绕过CSP

假如出于某种原因,您有必要答应内联JavaScript或款式,请在相应的指令上运用unsafe-inline值。例如,以下战略答应一切内联JavaScript,因而违反了CSP的根本目的。

Content-Security-Policy: script-src 'self' 'unsafe-inline' https://safe-external-site.com

一些重要的CSP指令

到目前为止,咱们已经看到了script-srcstyle-src,它们为脚本和款式表指定了有用的源。这里还有一些其他重要的特点。

  • default-src:界说获取一切资源的默认战略。当缺少更详细的战略时,浏览器将回退到default-src战略指令。示例:default-src 'self' trusted-domain.com
  • img-src:界说图像的有用来历,例如img-src 'self' img.mydomain.com
  • font-src:界说字体资源的有用来历。
  • object-src:界说插件和外部内容的有用源,如或元素。
  • media-src:界说音频和视频的有用源。

当您确实需求内联款式和款式时,请运用nonce特点

术语nonce指的是只运用一次。

在CSP的上下文中,nonce<script><style>符号上的一个特点,它答应特定的内联scriptstyle元素,一起仍然阻挠一切其他内联脚本和款式。这能够让你防止运用unsafe-inline指令,它答应一切的内联履行,是不安全的。

运用nonce特点能够让您坚持CSP的根本优势,一起答应您履行特定内联元素。

它是怎么作业的?

  • 关于每个恳求,服务器都会创立一个无法猜想的随机base64编码字符串。这是随机数值,例如dGhpcyBpcyBhIG5v==
  • 服务器会将此nonce值刺进到您希望答应的一切内联脚本和款式元素中,作为nonce特点的值。
<script nonce="dGhpcyBpcyBhIG5v==">.. ..</script>
<style nonce="dGhpcyBpcyBhIG5v==">.. ..</style>
  • 服务器还在script-srcstyle-src指令的Content-Security-Policy头中刺进相同的nonce值。
Content-Security-Policy: script-src 'nonce-dGhpcyBpcyBhIG5v=='; style-src 'nonce-dGhpcyBpcyBhIG5v=='

由于进犯者无法猜想令牌,因而他们无法注入过错的JavaScript。

总而言之,特定脚本和款式元素上的nonce特点指示浏览器答应这些元素中的内联履行,一起仍然阻挠一切其他没有nonce特点的内联脚本和款式。

它告知浏览器这些元素不是黑客注入的(由于他们无法猜想nonce值),而是服务器故意刺进的,所以它们能够安全履行。

采用CSP:从陈述开端,但不强制履行CSP违规行为

假如你有一个巨大的遗留代码库,到处都是PHP/HTML文件中的内联脚本,那该怎样办?最重要的是,您不知道有多少当地运用了内联脚本和外部脚本。怎样办?

由于CSP默认情况下阻挠一切内联脚本并阻挠一切外部源,因而您有必要删去/重构一切内联JavaScript和外部源,或许在战略中显式答应它们。

假如您当即启用严厉的战略来阻挠一切内联或外部脚本和款式表,那么您就有麻烦了。浏览器既不会加载外部脚本/款式,也不会履行内联脚本。

有一个高雅的处理方案来处理这个难题。您能够运用仅陈述模式,而不是当即设置严厉的CSP并冒着出产中出现任何溃散的风险。

运用Cotent-Security-Policy-Report-Only头,您能够告知浏览器只陈述,但不履行战略。

因而,浏览器仍将加载外部脚本并履行任何内联JavaScript,但它也将运用report-to指令向战略中界说的端点陈述一切违规。

Content-Security-Policy-Report-Only: script-src 'self'; report-to https://mysite.com/csp-violations

端点能够是应用程序中的一个路由,您能够在其间编写代码来解析违规数据并将其保存到数据库中,或许您能够运用第三方服务,如report-uri.com,它能够在浏览器的表中很好地显现违规数据,并支持过滤和排序。

怎么完成严厉的CSP

  1. Content-Security-Policy-Report-Only头开端,迭代地处理战略。亲近关注违规陈述,并在出现问题时进行修复,直到不再有违规陈述。
  2. 重构代码以删去内联JavaScript,并将其移动到在<script>元素上运用src特点加载的JavaScript文件中。重构包括内联事件处理程序(如onclickjavascript:URI)的HTML。
  3. 关于有必要履行内联脚本或运用内联CSS的当地,在服务器上生成nonce令牌,将其放在脚本和款式元素的nonce特点上。
  4. 彻底测试。在布置到出产环境之前,让您的测试团队了解CSP,并要求他们注意操控台中的任何CSP违规陈述。

无论怎么,将JavaScript与HTML分离是一种最佳实践,由于它能够清理HTML并坚持代码库的组织性。

这里有几个比如,阐明你将进行的更改类型。

  • 将随机数添加到<script><style>元素
<script src="my_script.js"></script>
<script>alert('hello world')</script>
<style>
  body {
      background-color: green;   
  }
</style>

成为:

<script nonce="token" src="my_script.js"></script>
<script nonce="token">alert('hello')</script>
<style nonce="token">
  body {
      background-color: green;   
  }
</style>

重构内联JavaScript处理程序和URI

通常,旧网站能够包括运用onclickonerror回调的事件处理程序。它们简单遭到XSS进犯。重构它,以便从JavaScript代码块添加处理程序。理想情况下,您应该将其移动到单独的JavaScript文件中。

<script>
    function handle() {
      // click handler code
    } 
</script>
<button onclick="handle();">Click Me</button>

成为:

<button id="submit-btn">Click Me</button>
<script nonce="token">
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('submit-btn')
          .addEventListener('click', () => { 
            // click handler code
          });
});
</script>

重要的是要记住,战略是按页面界说的。

原文: Content Security Policy (CSP): Everything You Should Know (writesoftwarewell.com)