第三方JavaScript管理备忘单¶
简介¶
标签(又称营销标签、分析标签等)是网页上小段的JavaScript代码。当JavaScript被禁用时,它们也可以是HTML图像元素。它们存在的理由是收集网络用户行为和浏览上下文的数据,供网页所有者用于营销。
第三方供应商JavaScript标签(以下简称标签)可分为两种类型:
- 用户界面标签。
- 分析标签。
用户界面标签必须在客户端执行,因为它们会改变DOM;例如显示对话框或图像,或改变文本等。
分析标签将信息发送回营销信息数据库;这些信息包括用户刚刚执行的操作、浏览器元数据、位置信息、页面元数据等。分析标签的理由是从用户的浏览器DOM向供应商提供数据,以进行某种形式的营销分析。这些数据可以是DOM中可用的任何内容。这些数据用于用户导航和点击流分析,识别用户以确定要显示进一步内容等,以及各种营销分析功能。
术语宿主指用户访问的原始网站,例如购物或新闻网站,它包含或检索并执行第三方JavaScript标签,用于对用户行为进行营销分析。
主要风险¶
最大的风险是第三方JavaScript服务器被攻陷,恶意JavaScript被注入到原始标签JavaScript中。这在2018年发生过,可能更早。
在Web应用程序中调用第三方JS代码尤其需要考虑3个风险:
- 对客户端应用程序更改的失控,
- 在客户端系统上执行任意代码,
- 向第三方披露或泄露敏感信息。
风险1:对客户端应用程序更改的失控¶
此风险源于这样一个事实:通常无法保证第三方托管的代码与开发人员和测试人员所看到的保持一致:新功能可能随时推送到第三方代码中,从而可能破坏接口或数据流,并影响应用程序对其用户/客户的可用性。
典型的防御措施包括但不限于:内部脚本镜像(以防止第三方篡改)、子资源完整性(以实现浏览器级别的拦截)和第三方代码的安全传输(以防止传输中被修改)。有关更多详细信息,请参见下文。
风险2:在客户端系统上执行任意代码¶
此风险源于以下事实:第三方JavaScript代码在集成到网站/应用程序之前很少被调用方审查。当客户端访问托管网站/应用程序时,此第三方代码会执行,从而授予第三方与用户相同的权限(类似于XSS攻击)。
在进入生产环境之前执行的任何测试都会失去部分有效性,包括AST测试
(IAST、RAST、SAST、DAST等)。
虽然人们普遍认为第三方故意注入恶意代码的可能性很低,但在组织服务器受到攻击后(例如:雅虎,2014年1月),仍然存在恶意注入第三方代码的案例。
因此,仍然应该评估此风险,特别是当第三方没有提供任何文档表明它正在执行比调用组织本身更好或至少等同的安全措施时。另一个例子是,托管第三方JavaScript代码的域名过期,因为维护该域名的公司破产或开发人员放弃了该项目。恶意行为者随后可以重新注册该域名并发布恶意代码。
典型的防御措施包括但不限于:
- 内部脚本镜像(以防止第三方篡改),
- 子资源完整性(以实现浏览器级别的拦截),
- 第三方代码的安全传输(以防止传输中被修改)以及各种类型的沙盒化。有关更多详细信息,请参见下文。
- ...
风险3:向第三方披露敏感信息¶
当网站/应用程序中调用第三方脚本时,浏览器会直接联系第三方服务器。默认情况下,请求包含所有常规HTTP头。除了浏览器的原始IP地址外,第三方还会获取其他数据,例如引用者(在非HTTPS请求中)以及第三方之前设置的任何Cookie,例如访问调用第三方脚本的其他组织的网站时。
在许多情况下,这授予第三方对组织的用户/客户/客户信息的首要访问权限。此外,如果第三方与其他实体共享脚本,它还会从所有其他实体收集次要数据,从而知道组织访客是谁,以及他们与哪些其他组织互动。
一个典型案例是当前主要新闻/出版网站调用第三方代码(通常用于广告引擎、统计和JavaScript API)的情况:任何访问这些网站的用户也会将访问情况告知第三方。在许多情况下,第三方还会知道每个用户具体点击了哪些新闻文章(通过HTTP referrer字段泄露),从而可以建立更深入的个性化档案。
典型的防御措施包括但不限于:内部脚本镜像(以防止HTTP请求泄露给第三方)。用户可以通过随机点击泄露网站/应用程序(例如新闻网站)上的链接来减少其分析,以减少画像。有关更多详细信息,请参见下文。
第三方JavaScript部署架构¶
标签有三种基本的部署机制。这些机制可以相互组合。
页面上的供应商JavaScript¶
这是指供应商向宿主提供JavaScript,宿主将其放置在宿主页面上。为了安全,宿主公司必须审查代码是否存在任何漏洞,例如XSS攻击或恶意行为(例如将敏感数据从DOM发送到恶意网站)。这通常很困难,因为JavaScript通常是混淆的。
<!-- Some host, e.g. foobar.com, HTML code here -->
<html>
<head></head>
<body>
...
<script type="text/javascript">/* 3rd party vendor javascript here */</script>
</body>
</html>
向供应商请求JavaScript¶
这是指宿主页面上的一行或几行代码直接从供应商网站请求JavaScript文件或URL。创建宿主页面时,开发人员会包含供应商提供的代码行,这些代码行将请求供应商JavaScript。每次访问页面时,都会向供应商网站发出JavaScript请求,然后JavaScript在用户浏览器上执行。
<!-- Some host, e.g. foobar.com, HTML code here -->`
<html>
<head></head>
<body>
...
<!-- 3rd party vendor javascript -->
<script src="https://analytics.vendor.com/v1.1/script.js"></script>
<!-- /3rd party vendor javascript -->
</body>
</html>
通过标签管理器向供应商间接请求¶
这是指宿主页面上的一行或几行代码从标签聚合器或标签管理器网站请求JavaScript文件或URL;而不是从JavaScript供应商网站请求。标签聚合器或标签管理器网站返回宿主公司已配置返回的任何第三方JavaScript文件。对标签管理器网站的每个文件或URL请求可以返回来自多个供应商的大量其他JavaScript文件。
从聚合器或管理器返回的实际内容(即特定的JavaScript文件以及它们具体做什么)可以由宿主网站员工使用为非技术用户(例如业务的营销部分)托管在标签管理器网站上的图形用户界面动态更改。
更改可以是:
- 对于相同的请求,从第三方供应商获取不同的JavaScript文件。
- 更改读取哪些DOM对象数据以及何时读取,以发送给供应商。
标签管理器开发人员用户界面将生成实现所需功能的代码,基本上确定从浏览器DOM获取哪些数据以及何时获取。标签管理器始终向浏览器返回一个容器JavaScript文件,它基本上是一组JavaScript函数,由用户界面生成的代码使用以实现所需功能。
类似于为开发人员提供函数和全局数据的Java框架,容器JavaScript在浏览器上执行,允许业务用户使用标签管理器开发人员用户界面指定高级功能,而无需了解JavaScript。
<!-- Some host, e.g. foobar.com, HTML code here -->
<html>
<head></head>
<body>
...
<!-- Tag Manager -->
<script>(function(w, d, s, l, i){
w[l] = w[l] || [];
w[l].push({'tm.start':new Date().getTime(), event:'tm.js'});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async=true;
j.src='https://tagmanager.com/tm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'TM-FOOBARID');</script>
<!-- /Tag Manager -->
</body>
</html>`
请求标签的安全问题¶
前面描述的机制很难做到安全,因为只有通过代理请求或访问GUI并查看配置才能看到代码。JavaScript通常是混淆的,所以即使看到它通常也没有用。它还可以即时部署,因为浏览器发出的每个新页面请求都会执行对聚合器的请求,聚合器从第三方供应商获取JavaScript。因此,一旦供应商上的任何JavaScript文件发生更改,或在聚合器上被修改,来自任何浏览器的下一次调用都将获取更改后的JavaScript。管理此风险的一种方法是使用下述的“子资源完整性”标准。
服务器直接数据层¶
标签管理器开发人员用户界面可用于创建可从浏览器DOM中任何位置获取数据并将其存储在页面上任何位置的JavaScript。这可能会导致漏洞,因为该界面可用于生成代码,从DOM(例如URL参数)获取未经验证的数据,并将其存储在页面上可执行JavaScript的某个位置。
使生成的代码安全的最hao方法是将其限制为从宿主定义的数据层获取DOM数据。
数据层可以是:
- 一个DIV对象,其属性值包含第三方所需的营销或用户行为数据
- 一组具有相同数据的JSON对象。每个变量或属性都包含某个DOM元素的值或用户操作的描述。数据层是所有供应商在该页面所需值的完整集合。数据层由宿主开发人员创建。
当业务定义的特定事件发生时,该事件的JavaScript处理程序会将数据层中的值直接发送到标签管理器服务器。然后,标签管理器服务器将数据发送给任何应接收它的第三方或多方。事件处理程序代码由宿主开发人员使用标签管理器开发人员用户界面创建。事件处理程序代码在每次页面加载时从标签管理器服务器加载。
这是一种安全的技术,因为只有您的JavaScript在用户的浏览器上执行,并且只有您决定的数据才发送给供应商。
这需要宿主、聚合器或标签管理器以及供应商之间的合作。
宿主开发人员必须与供应商合作,以便了解供应商进行分析所需的数据类型。然后,宿主程序员确定哪个DOM元素将包含该数据。
宿主开发人员必须与标签管理器或聚合器合作,以商定向聚合器发送数据的协议:例如URL、参数、格式等。
标签管理器或聚合器必须与供应商合作,以商定向供应商发送数据的协议:例如URL、参数、格式等。供应商是否有API?
安全防御考虑¶
服务器直接数据层¶
服务器直接机制是第三方JavaScript管理、部署和执行的一个良好安全标准。宿主页面的良好实践是创建DOM对象的数据层。
数据层可以对值执行任何验证,特别是来自向用户暴露的DOM对象(如URL参数和输入字段)的值,如果这些值是营销分析所必需的。
公司标准文档的一个示例声明是:“标签JavaScript只能访问宿主数据层中的值。标签JavaScript永远不能访问URL参数。”
作为宿主页面开发人员,您必须与第三方供应商或标签管理器商定数据层中哪个属性将具有哪个值,以便他们可以创建JavaScript来读取该值。
用户界面标签无法使用数据层架构实现安全,因为它们的功能(或其中之一)是改变客户端上的用户界面,而不是发送有关用户操作的数据。
分析标签可以使用数据层架构实现安全,因为唯一需要的操作是将数据从数据层发送到第三方。只执行第一方代码;首先填充数据层(通常在页面加载时);然后事件处理程序JavaScript将该页面所需的任何数据发送到第三方数据库或标签管理器。
这也是一个非常可扩展的解决方案。大型电子商务网站可以轻松拥有数十万个URL和参数组合,其中不同的URL和参数集包含在不同的营销分析活动中。营销逻辑可能在一个页面上包含30或40个不同的供应商标签。
例如,用户在特定城市、特定地点、特定日期的页面上的操作应发送数据层元素1、2和3。用户在其他城市页面上的操作应仅发送数据层元素2和3。由于控制每个页面上发送数据层数据的事件处理程序代码由宿主开发人员或营销技术人员使用标签管理器开发人员界面控制,因此关于何时以及哪些数据层元素发送到标签管理器服务器的业务逻辑可以几分钟内更改和部署。不需要与第三方互动;它们继续获取它们期望的数据,但现在数据来自宿主营销技术人员选择的不同上下文。
更改第三方供应商只需要更改标签管理器服务器上的数据分发规则,宿主代码无需更改。数据也只直接发送到标签管理器,因此执行速度快。事件处理程序JavaScript无需连接到多个第三方网站。
间接请求¶
对于提供GUI配置JavaScript的标签管理器/聚合器网站的间接请求,它们也可能实现:
- 技术控制,例如只允许JavaScript访问数据层值,不允许访问其他DOM元素。
- 限制在宿主网站上部署的标签类型,例如禁用自定义HTML标签和JavaScript代码。
宿主公司还应验证标签管理器网站的安全实践,例如对宿主公司的标签配置的访问控制。它也可以是双因素认证。
让营销人员决定从哪里获取他们想要的数据可能会导致XSS,因为他们可能会从URL参数中获取数据,并将其放入页面上可脚本化位置的变量中。
沙盒化内容¶
这两个工具都可以被网站用来沙盒化/清理DOM数据。
- DOMPurify是一个快速、宽容的HTML、MathML和SVG XSS净化器。DOMPurify默认安全,但提供了大量的可配置性和钩子。
- MentalJS是一个JavaScript解析器和沙盒。它通过在变量和访问器后面添加“$”后缀来允许JavaScript代码。
子资源完整性¶
子资源完整性将确保只有经过审查的代码才能执行。开发人员为供应商JavaScript生成完整性元数据,并将其添加到脚本元素中,如下所示:
<script src="https://analytics.vendor.com/v1.1/script.js"
integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC7CGiSNE64QUbHNPhzk8Xhm0djE6QqTpL0HzTUxk"
crossorigin="anonymous">
</script>
重要的是要知道,为了使SRI工作,供应商宿主需要启用CORS。此外,最好定期监控供应商JavaScript的变化。因为有时当供应商决定更新时,您可能会得到安全但不工作的第三方代码。
保持JavaScript库更新¶
OWASP Top 10 2013 A9描述了使用已知漏洞组件的问题。这包括JavaScript库。JavaScript库必须保持更新,因为旧版本可能存在已知漏洞,这通常会导致网站容易受到跨站脚本攻击。有几种工具可以帮助识别此类库。其中一个免费开源工具是RetireJS。
使用iframe进行沙盒化¶
您还可以将供应商JavaScript放入来自不同域(例如静态数据宿主)的iframe中。它将作为一个“牢笼”,供应商JavaScript将无法直接访问宿主页面的DOM和Cookie。
宿主主页面和沙盒iframe可以通过postMessage机制相互通信。
此外,iframe可以通过iframe sandbox属性进行安全加固。
对于高风险应用程序,除了iframe沙盒化之外,请考虑使用内容安全策略(CSP)。CSP使得抵御XSS更加强大。
<!-- Some host, e.g. somehost.com, HTML code here -->
<html>
<head></head>
<body>
...
<!-- Include iframe with 3rd party vendor javascript -->
<iframe
src="https://somehost-static.net/analytics.html"
sandbox="allow-same-origin allow-scripts">
</iframe>
</body>
</html>
<!-- somehost-static.net/analytics.html -->
<html>
<head></head>
<body>
...
<script>
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
if (event.origin !== "https://somehost.com:443") {
return;
} else {
// Make some DOM here and initialize other
//data required for 3rd party code
}
}
</script>
<!-- 3rd party vendor javascript -->
<script src="https://analytics.vendor.com/v1.1/script.js"></script>
<!-- /3rd party vendor javascript -->
</body>
</html>
虚拟iframe容器¶
该技术创建了与主页面异步运行的iFrame。它还提供自己的容器JavaScript,该JavaScript根据营销标签要求自动动态实现受保护的iFrame。
供应商协议¶
您可以与第三方签订协议或要求其提供证据,证明他们已实施安全编码和一般的公司服务器访问安全。但特别是,您需要确定对其源代码的监控和控制,以防止和检测对该JavaScript的恶意更改。
MarTechSec¶
营销技术安全
这指的是降低营销JavaScript风险的所有方面。控制措施包括:
- 用于降低风险的合同控制;与任何营销技术公司签订的合同应包含要求提供代码安全和代码完整性监控证据的条款。
- 用于风险转移的合同控制:与任何营销技术公司签订的合同可以包含对提供恶意JavaScript的处罚条款。
- 用于防止恶意JavaScript执行的技术控制;虚拟iframe。
- 用于恶意JavaScript识别的技术控制;子资源完整性。
- 技术控制包括渗透测试要求中客户端JavaScript的恶意行为。
MarSecOps¶
营销安全运营
这指的是维护某些技术控制的操作要求。这涉及营销团队、营销技术提供商和运行或运营团队之间可能的合作和信息交换,以更新页面控制中的信息(SRI哈希更改、带有SRI的页面更改)、虚拟iFrame中的策略、标签管理器配置、数据层更改等。
对于任何包含非简单营销标签的网站,最完整和预防性的控制是:
-
一个调用营销服务器或标签管理器API的数据层,这样只有您的代码在您的页面上执行(控制反转)。
-
虚拟框架容器。
在营销团队所要求的变更速度下,或在没有大量专用资源的情况下,实施技术控制的MarSecOps要求可能会使数据层和子资源完整性控制变得不切实际。