提高 Web 应用安全性的三个步骤
我最近与我工作中的 Slack 小组分享了以下二维码:
专业提示:切勿在未先使用此类服务进行检查的情况下随意扫描二维码
这个二维码并非恶意代码,它只是链接到我的新播客网站(https://dotnetcore.show/
),我很高兴地说,所有同事都通过了。也就是说,我没有看到任何来自我工作地点附近 IP 地址的新访问请求。
我认为这证明了我即将在文章中提出的观点。那就是:我们开发人员是开发领域的专家,我们对开发的看法很重要。
现实世界的例子
促使我发表这篇文章的原因是Feedify及其所有客户遭遇黑客攻击。以下是我最初看到这篇报道的链接:https://www.bleepingcomputer.com/news/security/feedify-hacked-with-magecart-information-stealing-script/
读了这篇博文后,我在推特上对 Web 应用的安全性发表了自己的看法
不幸的是,我在这篇吐槽中针对了 Feedify,但他们远非第一个遭受此类攻击的公司。今年早些时候,英国政府不同部门的许多网站都曾被注入加密矿工:
在这两个例子中,第三方脚本都遭到入侵,并且另一个第三方(第六方?)的 JS 被注入其中。或者换一种写法:
- 我的电子商务网站包含来自 Feedify 的脚本
- Feedifys 脚本已被破解,并且已经嵌入了一些其他脚本
- 我的电子商务网站现在包含受感染的脚本。
但如何才能阻止这种情况发生呢?其实很简单,最多只需三步。
停止使用unsafe-eval
Feedifys 脚本最初包含的方式如下:
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'https://cdn.feedify.net/getjs/feedbackembed-min-1-0.min.js';
document.getElementByTagName('head')[0].appendChild(s);
这应该立刻引起警觉。我们为什么要通过 JS 添加脚本?难道我们不能通过添加
<script type='text/javascript'
src='https://cdn.feedify.net/getjs/feedbackembed-min-1-0.min.js'>
</script>
这是公认的做法。实际上,第一个代码片段就是这么做的,只不过是在运行时而不是设计时。
第一个片段有什么问题?
除了速度慢(必须下载页面并在将新闻脚本添加到元素之前解析所有 JS head
)之外,它还非常不安全。
通过像这样将脚本注入页面,在页面渲染完成之前,您无法检查实际添加了哪些内容。这也意味着您允许浏览器中的 JS 引擎加载并执行来自外部源的脚本,而无需您进行任何检查。
使用第二段代码片段加载的脚本也是如此。但有两个很大的区别:
- 第二个片段是你应该怎么做
- 您可以在运行时使用 SRI 检查脚本是否已正确加载
子资源完整性检查基本上就是告诉浏览器对下载的脚本进行哈希值检查。这需要脚本作者提供脚本的哈希值,但你可以轻松地在命令行或使用类似这样的服务生成一个。
如果传递的 JS 文件的哈希值与提供的哈希值检查不通过,浏览器会在控制台中引发错误并拒绝解析传递的脚本。
由于 Feedify 提供的原始脚本已被更改,因此其哈希值无法通过 SRI 检查。
为 JS 文件添加 SRI 检查非常简单(显然,每个脚本的哈希值会有所不同):
<script type='text/javascript'
src='https://cdn.feedify.net/getjs/feedbackembed-min-1-0.min.js'
integrity='sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E='>
</script>
我在这里使用了 jquery 3.1 的 SRI,因为 Feedify 脚本已经从网络上消失了
云服务供应商
内容安全策略 (CSP)是一个 HTTP 标头,用于指示浏览器允许从哪里加载资源。由于它是一个 HTTP 标头,因此它会在页面 HTML 之前传递,并设置当前会话的规则。
如果该域未在 CSP 中列出,则对该域的所有请求都会引发错误并被阻止。
设置 CSP 需要更多精力。这是因为它来自服务器,而不是 HTML 本身。不过所有 Web 服务器都支持添加自定义标头,所以设置起来并不难。
困难的是怎样才能做到正确。
由于现代 Web 应用会从网络各处加载资源,因此您需要将应用加载的每个域名都列入白名单。由于规则适用于所有资源类型(脚本、图片、框架、CSS 等),因此每种资源类型都有各自的规则。这意味着脚本的 CSP 规则应该与 CSS 的 CSP 规则有所不同。
例如,以下是https://dotnetcore.show/的 CSP 规则的修订版本:
upgrade-insecure-requests;
default-src 'self';
connect-src 'self' https://cdn.jsdelivr.net https://api.unsplash.com;
script-src 'self' https://cdnjs.cloudflare.com https://code.jquery.com;
对于浏览器来说,读取结果如下:
- 通过 http 发出的每个请求都应自动升级到 https
- 除非其他规则另有规定,否则仅允许来自以下来源的资源:
- 仅允许从以下位置加载脚本:
在生成请求之前,浏览器会阻止任何其他内容。这也包括从这些脚本中请求的资源。
被入侵的 Feedify 脚本包含一个被注入的 MageCart 脚本使用的请求。该请求被发送至info-stat[.]ws
(我在“。”字符周围添加了方括号,这样您的浏览器就不会将其变成可点击的链接)
如果 CSP 将 Feedify CDN 域名列入白名单,但未将 info-stat 域名列入白名单,则会导致对该域名的请求失败,并在控制台中记录错误。这些错误可能在开发、质量保证和用户验收 (UAT) 环境中被发现,因此受影响的 Web 应用的开发人员可能会修复这些错误。
然而,这需要使用包含脚本的标准方式(即删除上面指出的不安全的评估)。
最后
这是该帖子主观且略有争议的观点。
此次攻击共涉及 4000 个站点。
这意味着 4000 个开发团队(假设每个站点都是由一个单独的团队创建的)要么不知道使用不安全评估的安全问题,要么不知道可以使用 CSP 来保护他们的网站。
如果是这样的话,那就意味着大量的开发团队要么不知道这些安全措施
...
或者他们确实知道,但当决策者决定不投入时间在安全问题上时,他们并没有给予足够的反击。
我们必须牢记,我们是开发领域的专家。我们之所以被聘用,正是因为我们是这方面的专家。因此,我们有责任了解这些情况,并在当权者决定不投资安全时,尽可能(甚至更加强硬地)予以反击。
当出现违规或安全问题时,真正需要我们承担责任的,不是决策者。简单地提出这些问题,记录下来,然后默默地处理,并不是解决问题的办法。
将自己置于陷入安全漏洞的用户的位置,想象一下您的身份被盗会是什么感觉 - 更糟糕的是,您的一生积蓄被盗 - 因为某些开发人员不想在提出安全漏洞的可能性时感到不舒服。
你想成为那样的人吗?我知道我不会。
文章来源:https://dev.to/dotnetcoreblog/ Three-steps-for-increasing-the-security-of-your-web-apps-3clg