安全是一个时不时出现的话题。 从一开始这不是问题,但是一旦发生坏事,通常就应该归咎于此。 软件很复杂,机器的人为编程还远远不够完美,用户也可能没有遵循最佳实践。 那么我们如何创建一个安全的系统呢?
网络是最不安全的地方之一。 具有潜在安全风险的计算机相互连接。 可以接收任意数据的服务器。 从未知来源执行代码的客户端。 尽管我们无法控制服务器的安全性,但我们必须做一些保护客户端的事情。 即使JavaScript可以被视为一种安全的脚本语言,但是任何ActiveX,Flash或Silverlight插件的代码绝对不是。 此外,即使JavaScript本身已被沙箱化,它也可能以用户将触发不安全动作的方式使用。
在本教程中,我们将看到实际的网络安全模型。 我们将探讨构建安全Web应用程序的最佳做法和一般准则。 我们将学习什么是跨域资源共享策略以及如何控制它。 最后,我们还将讨论沙盒(外部)内容。
安全准则
最重要的准则之一与HTML直接无关:使用HTTPS! 与HTML的关系当然在于我们的超文本文档的分发中。 尽管如此,我们必须意识到,使用HTTPS传输文档和使用HTTPS传输资源是两件事。 绝对有必要检查所有包含的资源是否真的使用https://
方案。
另一个重要的准则与用户定义的内容有关。 一旦允许用户在表单上输入数据,就需要小心。 我们不仅需要确保Web服务器受到保护以免受常见攻击(例如SQL注入)的侵害,还需要确保在执行代码中未谨慎使用存储的数据。 例如,我们应该转义字符串以不包含任何HTML。 单独使用HTML并不是恶意的,但它可以触发脚本执行或资源获取。 允许用户编写HTML的一种方法是将某些标记和属性列入白名单,该HTML无需修改即可放在输出页面上。 其他元素将被转义。
我们JavaScript还应该最大程度地减少对第三方库的曝光和信任。 当然,我们使用立即调用函数表达式(IIFE)来防止全局上下文受到污染。 但是,另一个原因是不要(可能)泄漏关键的内部状态,然后其他脚本可能会随意或偶然地更改这些状态。
(function () {
// Standard code here.
})();
对我们自己来说,依靠'use strict';
当然是一种好习惯'use strict';
和传达的利益。 但是,限制正在运行的脚本并不会阻止我们将API与可能损坏的数据一起使用。 用户或其他程序可能会根据不受我们影响的条件来更改或查看localStorage
中的Cookie和内容。 因此,我们应该始终执行一些完整性检查,这为我们提供了尽快检测完整性缺陷的提示。
最后,我们应该确保仅使用受信任的第三方资源。 使用我们站点内其他服务器上的脚本可以对页面进行更改或破坏用户的隐私。
跨域资源共享
跨域资源共享(CORS)的概念很简单。 除非起源明确允许,否则浏览器不允许嵌入来自不同来源的特殊资源。 特殊资源可以是,例如Web字体或通过XMLHttpRequest
请求的任何内容。 默认情况下,跨域AJAX请求是禁止的,因为它们能够执行会带来很多脚本安全问题的高级请求。
来源基本上是通过使用的协议,主机和端口组合定义的。 因此, https ://a.com与https://a.com不同,后者与https://a.com:8080不同。 它们与http://b.com都不同。
通过在响应中包含某个标头,可以允许客户端使用资源。 然后,浏览器确定是否允许当前网站使用该资源。 来源通常是通过当前网站的域名确定的。
让我们看一个说明性的例子。 在下文中,我们假设我们的页面位于foo.com
。 我们从bar.com
托管的页面请求JSON数据。 对于JSON请求,我们使用XMLHttpRequest
,如下所示。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://bar.com/users');
xhr.addEventListener('load', function (ev) {
if (xhr.status === 200) {
var result = JSON.parse(xhr.responseText);
// ...
}
}, false);
xhr.send();
浏览器已经通过将Origin
头添加到请求中来预期启用CORS响应的可能性:
Origin: http://foo.com
现在,服务器必须提供正确的响应。 我们不仅希望传输正确的JSON,而且更重要的是,我们需要特定于CORS的标头。 可以使用通配符。 例如,以下示例将授予对任何请求使用请求的资源的权利。
Access-Control-Allow-Origin: *
CORS也可以用作JSONP解决方法的替代方法。 JSONP使用脚本发出跨域AJAX请求,从而产生JSON响应。 在CORS之前,通常禁止跨域调用,但是始终可以接受来自不同域的脚本。 在大多数API中,通过提供特殊的查询参数(命名回调函数)来触发JSONP响应。
假设对http://bar.com/api
的调用导致以下JSON响应:
{ "name": "example", "factor": 5, "active": true }
对例如http://bar.com/api?jsonp=setResult
的JSONP调用将为我们提供:
setResult({ "name": "example", "factor": 5, "active": true });
由于JSONP的结果仅由<script>
元素可见,因此隐含GET请求方法。 不可能使用其他任何东西。 CORS在这方面为我们提供了更多的自由,因此我们还可以确定其他参数。 通过允许我们自由使用标准化的XMLHttpRequest
对象,可以启用所有功能。
理想的解决方案只能是针对旧版浏览器使用JSONP,而对于较新的浏览器则采用CORS。 这样可以防止许多跨站点脚本(XSS)问题源于受感染的外部站点。 从外部页面嵌入脚本一直是一项冒险的业务。 更好的后备方法是将JSON请求从我们的服务器重定向到目标计算机。 这样,我们与(受信任的)服务器进行通信,该服务器从目标服务器获取响应,评估其合理性并返回(有效)结果。
沙箱标志
每个document
都有其自己的window
。 访问此window
通常是当前浏览上下文window
的代理,这将驱动我们看到的选项卡。 使用多个选项创建浏览上下文,例如父上下文,创建者和初始页面。 除这些选项外,还设置了安全标志。 这些标志设置了上下文的功能和限制。 实际上,可以防止某些行为,例如运行脚本或打开新选项卡。
我们如何设置新上下文的安全标志? 我们通过分配给元素的属性来设置上下文,这需要创建一个新的上下文。 当前,即使iframe
元素也具有这样的属性,即使标准框架也适用于先前的描述。 但是,标准框架被认为已弃用,因此并没有得到很好的支持。 即使HTML5标准提到了它们,也不应再使用它们。
有很多标志可用。 最重要的是:
-
allow-top-navigation
(允许更改顶部上下文) -
allow-plugins
(启用embed
,object
……) -
allow-same-origin
(allow-same-origin
访问相同来源的内容) -
allow-forms
(可以提交表格) -
allow-popups
(不会阻止弹出窗口/新上下文) -
allow-pointer-lock
(启用指针锁定API) -
allow-scripts
(允许脚本执行)
<iframe>
使用sandbox
属性进入沙箱模式。 如果未指定此属性,则众所周知。 使用此属性,一切都被禁止。 因此,前面提到的标志启用了某些功能。
让我们仔细看看allow-same-origin
标志。 默认情况下, iframe
的政策确实宽松。 如果我们未指定sandbox
属性,则仅允许读取来自同一域的嵌入式页面,例如,给定域的cookie或浏览器的本地存储。 当然也存在其他风险,这就是为什么我们通常要提供sandbox
属性。
下图以简单图表形式显示了默认行为。 虽然允许第二个iframe
访问先前声明的内容,但第一个iframe
不允许访问。 原因是不同的域,以黄色突出显示。
那么,这张图片如何随着sandbox
属性发生变化? 仍然禁止来自其他域的内容。 因此,我们仅查看来自相同来源的内容的其他可能性。 默认情况下,即使来自相同来源的内容也被视为来自不同来源。
可以为上下文控制或设置更多功能,但是不幸的是,这些功能是通过其自身的属性来传输的。 一个很好的例子是allowfullscreen
属性。 同样,它仅在iframe
上可用。 原则上,它允许应用程序进入全屏模式。
此外,我们应该注意<iframe>
元素的seamless
属性。 此属性启用父文档在所包含文档上的样式。 与srcdoc
属性结合使用时,它特别强大,它使我们可以直接提供iframe
的源,而无需HTTP请求或使用数据URI。 这样,我们可以非常轻松地允许用户输入内容,而不必担心脚本的执行。
下面显示了在沙盒环境中显示用户内容的示例。
沙盒iframe可用于许多任务。 例如,如果我们要安全地评估脚本,则可以将要评估的内容传递给位于iframe
内的特殊处理程序。 处理程序将调用eval
函数。 内联框架被沙盒化,仅允许脚本编写,其他都没有。 无法打开弹出窗口,无法使用导航,并且我们的整个DOM是分开的。
确切的实现还需要文档之间HTML5消息传递。 我们使用postMessage
方法发送评估请求,并通过message
事件监听响应。
我们还可以使用内容安全策略(CSP)将当前页面的一部分沙盒化。 此属性通常通过页面的HTTP标头进行传输,但是HTML使我们能够在<meta>
标记中进行设置。
一个例子如下。 我们需要使用正确的http-equiv
值。 内容是针对该页面的一系列定义。
不同的定义(称为策略)也接受通配符。 确切的目的和外观在很大程度上取决于所使用的策略。
结论
Web安全是可能的,即使它很难实现并且依赖于许多(通常是无法控制的)外部参数。 如果我们可以最小化这些外部参数,例如插入的内容或脚本,那么我们通常情况良好。 大多数攻击媒介只能从脚本中使用。
我们已经看到(内联)框架和超链接可以使用沙箱标记进行调整。 我们自己的资源仅应在考虑CORS的情况下进行部署。
翻译自: https://code.tutsplus.com/tutorials/html5-mastery-web-security--cms-24846