导语:本文将发布我最近新发现的如何利用第三方脚本进行的隐私数据收集。具体过程就是通过登录Facebook以及其他类似的社交登录API,从网站中找到个人标识符,对用户进行跟踪。
到目前为止,我已经陆续发布了如何通过网络跟踪器从网页、浏览器密码管理器和表单输入中盗取信息的文章。
今天,我会继续发布我最近新发现的如何利用第三方脚本进行的隐私数据收集。具体过程就是通过登录Facebook以及其他类似的社交登录API,从网站中找到个人标识符,对用户进行跟踪。具体来说,我发现了两种类型的漏洞[1]:
1.有7个第三方网站访问并滥用了Facebook用户的数据;
2.有一个第三方使用自己的Facebook“应用程序”来跟踪网络上的用户;
漏洞1:第三方利用了Facebook官方授予其网站的访问权限
当用户点击“登录Facebook”时,他们会被进行这样的提示:你所访问的网站有权访问你Facebook的某些个人资料信息[2]。即使在Facebook最近锁定该功能后,网站也可以在不触发Facebook人工审核的情况下,请求用户的电子邮件地址和公开个人资料,如姓名、年龄范围、性别、地区和个人资料照片。一旦用户允许第三方网站访问这些信息,任何嵌入页面的第三方Javascript(如上图中的tracker.com)也可以检索用户的Facebook信息,就好像它们是第一方( the first party)[3](比如Facebook本身)一样。
出于安全考虑,有时用户会把登录密码设置的很复杂。所以Facebook登录和其他社交登录系统就会通过减少要记住的密码数量来简化用户的帐户创建过程。但是社交登录也会带来风险,比如,这段时间闹得沸沸扬扬的剑桥分析公司,就被发现利用性格测试应用程序收集用户数据,该应用程序使用的就是Facebook的登录功能。除此之外,我还发现了其他的风险,比如,当用户授予网站访问其社交媒体资料时,他们不仅信任了该网站,而且还信任该网站上嵌入的第三方。
我目前总共发现了有7个脚本使用了第一方的Facebook访问收集Facebook的用户数据[4]。这些脚本目前已嵌入在排名前100万个站点中的434个中。我会在附录1中详细介绍如何发现这些脚本的?这些脚本中的大多数会获取用户ID,以及电子邮件和用户名等附加配置文件信息,目前我还无法确定第一方是否知道这种特定的数据访问[5]。
通过Facebook API收集的用户ID特定于某些网站(Facebook赋予权限的),虽然这将限制跨站点跟踪的可能性,但是这些应用程序范围的用户ID可用于检索全局Facebook ID,用户的个人资料照片和其他公共个人资料信息,这些信息可用于识别和跟踪网站和设备上的用户[6]。
上图表明它们在滥用浏览器自动填写来收集用户的电子邮件地址,另外Opentag标签管理器加载的脚本包含访问Facebook API并将用户ID发送至https://c.lytics.io/c/1299?fbstatus=[…]&fbuid=[…]&[…]形式的代码片段。此片段似乎是lytics.github.io网站上的一个示例代码片段的修改版本,原代码片段不但可以捕捉Facebook事件,似乎还为第一方提供了收集Facebook用户标识和登录状态的说明。
尽管我观察到这些脚本可以用来查询Facebook API并保存用户的Facebook ID,但由于其代码经过了混淆以及测量方法的限制,我们无法验证这些代码是否发送到其服务器。
第三方脚本可以直接从Facebook API获取数据,上面的代码片段来自OpenTag脚本,它会将用户的Facebook ID泄漏到Lytics,Lytics是一个个性化的营销和客户数据平台。为了讲解的方便,我添加了注释,并进行了简化,原始脚本在这里可用。该脚本会持续检查Facebook API的存在(通过window.FB获得)。一旦用户登录到Facebook,跟踪的脚本就可以悄无声息地查询用户的登录状态。对登录状态查询的响应包含用户的Facebook ID,然后脚本从响应中解析ID并将其发送回远程服务器。
虽然我还不能总结全这些追踪者如何使用他们收集的信息,但可以检查他们的广告销售材料,了解他们如何使用这些信息。OnAudience,Tealium AudienceStream,Lytics和ProPS都提供某种形式的客户数据平台,它们都会收集数据并协助黑客将数据转化为利润。Forter为电子商务网站提供基于身份的欺诈预防,Augur提供跨设备跟踪和消费者识别服务,目前我还无法确定拥有ntvk1.ru域名的公司。
漏洞2:通过Facebook登录服务跟踪网络用户
一些第三方使用Facebook登录功能在许多网站上对用户进行身份验证,比如Disqus,Disqus是一家第三方社会化评论系统,主要为网站主提供评论托管服务。然而,隐藏的第三方追踪器也可以使用Facebook登录,来匿名化用户,从而进行有针对性的广告推送。这是一种侵犯隐私的行为,因为它未经用户同意。但前提是,这些隐藏的跟踪器是怎么发现用户登录Facebook的呢?我想这个跟踪器直接嵌入在用户直接访问的第一方。这个猜测是我在Bandsintown所发现的,更糟糕的是,攻击者这样做是为了让恶意网站嵌入Bandsintown的iframe来识别用户。
Bandsintown为用户提供的数据是非常全面的,许多歌手都在使用Bandsintown来管理演出日期和各种活动,该服务能够自动帮助歌手在其Facebook主页发布演出信息,不仅大大简化了信息从歌手传递到歌迷的流程,而且能够为演唱会的推广时间提供建议。
而对于粉丝来说,要想追随他们的偶像,用户需要登录Facebook,并让Bandsintown Facebook应用程序访问他们的个人资料、城市、喜好、电子邮件地址和音乐活动。此时,Bandsintown可以访问必要的身份验证令牌来访问Facebook帐户信息。
另外Bandsintown提供了一种名为“Amplified”的广告服务,该服务出现在许多顶级音乐相关网站上,包括lyrics.com,songlyrics.com和lyricsmania.com。当Bandsintown用户浏览嵌入Bandsintown的“Amplified”的广告服务时,广告脚本嵌入一个不可见的iframe,该iframe使用先前建立的认证令牌连接到Bandsintown的Facebook应用程序,并获取用户的Facebook ID。然后,iframe将用户标识传递回嵌入脚本。
我们发现由Bandsintown注入的iframe会将用户的信息不加区分地传递给嵌入脚本。因此,任何恶意网站都可能使用他们的iframe来识别访问者。目前,我已经向Bandsintown通报了此漏洞,并确认该漏洞现在已经修复。
总结
Facebook数据对第三方的意外曝光,并不是由于Facebook的登录功能出现了问题。相反,这是由于在如今的网络中,第一方和第三方脚本之间缺乏安全界限。尽管如此,Facebook和其他社交登录提供商还是可以采取一些措施来防止,比如对API的使用进行严格审核,审核它们访问社交登录数据的方式。Facebook还可以通过应用程序范围的用户id来禁用配置文件图片和全局Facebook id。其实,Facebook在四年前就宣布匿名登录了。
在开头提到的那几篇文章中,我曾列出了三个站点(fiverr.com, bhphotovideo.com和mongodb.com),它们嵌入了与上面给出的URL模式匹配的脚本。即使这些脚本来自相同或类似的url,第三方脚本在加载不同站点时可能包含不同的内容。经过分析,嵌入fiverr.com和bhphotovideo.com的Forter脚本不包括访问Facebook数据的功能。在mongodb.com上,我们只看到了一个Augur脚本的存在。我已经发布了一个经过更新的网站列表,这里面的API已经确认了访问Facebook数据的功能。
另外,我曾在以前的文章中列出了Lytics脚本(https://c.lytics.io/static/io.min.js)来作为Facebook API访问的原因。尽管此脚本用于将Facebook用户ID发送给Lytics(c.lytics.io),但访问Facebook API的代码是在OpenTag脚本中提供的,如上所述。负责访问Facebook用户数据的OpenTag脚本中的代码片段可能由第一方配置,因此我认为第一方可能不知道数据被访问这回事。
附录1
[1]我在文章中使用了术语“漏洞”来指当今网络中由于不安全的设计实践而产生的问题,而不是平常所理解的计算机安全方面的漏洞。
[2]在这篇文章中,虽然我是以Facebook登录为例的,但我描述的漏洞可能存在于大多数社交公司和移动设备上。事实上,比如,Google Plus API和俄罗斯社交媒体网站VK也可以获取用户标识符的脚本。
[3]当用户在使用Facebook的Javascript SDK的网站上完成Facebook登录过程时,SDK会在页面中存储身份验证令牌。当用户导航到新页面时,SDK将使用浏览器的Facebook cookie自动重新建立认证令牌,所有对SDK的第三方查询都会自动使用此令牌。
[4]为了更好地理解第三方与第一方的集成程度,我根据他们在登录初始化阶段向Facebook提供的第一方应用程序ID(或AppId)的使用对脚本进行了分类,以确定该网站。如果在第三方库中包含网站的应用程序ID和初始化代码表明集成更紧密,第一方可能需要配置第三方脚本以表示他们访问Facebook SDK。虽然应用程序ID并不是什么秘密,但我认为缺乏应用程序ID则意味着松散的集成,因为这样第一方可能不知道访问。事实上,上文中的所有脚本在嵌入简单的测试页面时都采用相同的操作,先前没有任何业务关系。
[5]以下迹象可能表明第一方对Facebook数据了访问:
1)第三方主动发起Facebook登录过程而不是被动地等待登录发生;
2)第三方包括它所嵌入的网站的唯一App ID,上面列出的七个脚本既不启动登录过程,也不包含网站的应用程序ID。
不过,很难确定第一方和第三方之间的确切关系。
[6]通过查询Facebook的Graph API或者检索用户的个人资料照片(甚至不需要验证),就可以将应用程序范围的ID解析为真实的用户个人资料信息。当安全研究人员将这个漏洞反馈给Facebook时,Facebook回复如下:
“这是我们在开发产品时,有意设置的行为。虽然我们并不认为这是一个安全漏洞,但我们确实要采取控制措施来监控和缓解滥用行为。”
据报道,拥有类似控制功能的Facebook界面曾获取了20亿Facebook用户的公开个人资料数据。请注意,尽管研究人员发现的终端不再公开运行,但以下终端仍然会重定向到用户的个人资料页面: https://www.facebook.com/[app_scoped_ID]。
附录2:研究分析的方法
为了研究社交登录API的滥用情况,我扩展了OpenWPM以模拟用户已经在所有网站上进行了身份验证并给予Facebook登录SDK的完全权限。我添加了一些工具(比如“windows . fb”)来监视Facebook SDK界面的使用,另外,由于我没有以其他方式将用户的身份注入页面,因此任何被泄漏的个人数据都必须从我的spoofed API中查询。
我在2017年6月从Alexa 100万个网站上抓取了500万个网站,并采用以下抽样策略:访问所有前15000个网站,我随机抽取了Alexa的排名范围在15000到100000中的15000个网站,以及Alexa的排名范围在100000到1000000中的20000个网站。这个抽样组合使我们能够观察到攻击者对高流量和低流量网站的攻击区别。在这5万个网站中,我们访问了6个页面,即首页和从首页的内部链接随机抽取的一组其他5个页面。
为了模仿用户登录,我们创建了自己的`window.FB`对象并复制了Facebook SDK 2.8版的接口。被欺骗的API都具有以下属性:
1.对于通常返回个人信息的方法调用,我会欺骗返回值,就好像用户已经登录并调用了必要的回调函数参数。
其中包括用于事件`auth.login` ,`auth.authResponseChange`, `auth.statusChange`和`FB.getAuthResponse()`的 `FB.api()`, `FB.init(), `FB.getLoginStatus()`,和FB.Event.subscribe()` 。
另外对于Graph API (' FB.api '),它支持真正的Facebook SDK支持的大部分配置文件数据字段。这样我就能解析请求的字段并以真实Graph API返回的相同格式,返回一个数据对象。
2.对于不返回个人信息的方法调用,我只需调用一个无操作函数并忽略任何回调参数。如果网站调用了一个我无法完全复制的方法,这有助于最大限度地减少用户的跟踪。
3.一旦文档加载完成,我就会触发`window.fbAsyncInit`。这个函数通常由Facebook SDK调用。
因此,无论是否存在真正的Facebook SDK,欺骗性的`window.FB`对象都会被注入到每个页面加载的每一个框架中。然后,使用OpenWPM的Javascript通话监控来监控对API的访问。监控对象包括所有的HTTP请求和响应数据,就连HTTP POST有效载荷都会被检查,以检测任何伪造的配置文件数据(包括被散列或编码的数据)是否发生泄漏。
对于`window.FB`和HTTP数据的调用,我都会在执行时存储Javascript堆栈跟踪。通过使用这个堆栈跟踪就可以了解哪些API脚本被访问以及他们何时发送数据。对于某些脚本,我只负责捕获API访问权限,而不负责泄漏。因此在这些情况下,我通过手动调试脚本以确定数据是仅在本地使用还是在传输之前就被混淆,不过这方面我目前还做的不够好。
附录3:第三方如何伪装成第一方访问Facebook API
我还发现了许多与Facebook API交互的第三方脚本,这些脚本似乎会第一方运行[4]。这些公司提供一系列服务,例如集合多个社交登录选项,监控社交媒体参与度以并聚合客户数据。比如BlueConic提供了一个Facebook配置文件传输服务,该服务将用户的Facebook个人信息复制到BlueConic的数据平台上。其他第三方服务包括:Zummy、Social Miner、Limespot (personalizer.io)、Kissmetrics、Gigya和Webtrends。不过,Limespot已经通知我,他们在2017年11月就停用了相关功能。