在《是时候放弃插件密码管理器,改用密码管理器插件了》一文中,我们谈到插件密码管理器的安全性不够。
我们做了一个演示:将恶意JS代码注入到Github一个无需登录的网页中,通过引诱用户点击关闭广告,偷取用户Github密码。
Talk is cheap. Show me the video.
为了演示效果,将登录框、LastPass填充框都设置成了半透明。在实际攻击中,可以设置为很低的透明度,肉眼不可见。
这个演示没有利用任何浏览器漏洞。如果利用合适的漏洞,无需用户点击就能自动偷取密码。
互联网上绝大多数网页都包含大量第三方内容,特别是广告,很难保证所有内容都是安全的。一旦第三方内容含有恶意代码,插件密码管理器就可能存在泄密风险。
神锁离线版的用户很早就强烈要求提供Windows版,将神锁离线版的安全保护能力带到Windows上。不过,桌面平台没有完善的沙盒保护,恶意软件不仅可以读取app存储的数据,还能通过Keylogger或者扫描内存数据等方法偷取主密码。而且,桌面平台没有普遍配置安全芯片,密钥管理远远不如智能手机安全。
Independent Security Evaluators去年发布的一份研究报告发现,桌面端密码管理器可以通过扫描内存找到主密码。《华盛顿邮报》报道相关事情并公开了一个演示视频。
安全研究员 Adrian Bednarek提取1Password主密码的视频
桌面端上常见的密码管理器技术方案有两种:
1.桌面客户端
大约在十几年前,PBKDF算法开始成熟,第二代密码管理器允许用户设置主密码,将主密码转换为密钥来加密保护用户的数据,这为密码管理带来了真正的保护。直到今天,大多数密码管理器仍然基于这一技术。
2.插件密码管理器
桌面端软件通常都可以记住密码,输入一次密码后,用户很少需要再次输入。而运行在浏览器中的网站则经常需要用户输入密码,所以在电脑端,用户大多时候是在登录网页时会用到密码管理器。
插件密码管理器是基于浏览器插件技术实现的密码管理器客户端,通常与其他平台客户端保持云端同步。它不仅具备桌面客户端的主要功能,而且能辅助填充网页中的密码框,因此深受用户喜爱。
不建议使用浏览器自带的密码管理器,它们大多属于第一代密码管理器——有管理,无保护。
我们经过深入调研后发现,这两种技术方案在安全性上都不理想。因此没有采用它们,而是独创设计了扫码远程加密填充方案,让用户在电脑端浏览器上也能安全地填充密码。
大多数插件密码管理器,都基于浏览器插件接口实现完整的客户端,包括:用户交互界面、自动填充、加密解密、密码数据库存储和云端同步数据库等模块。
除了桌面平台本身缺少完善的沙盒保护和安全芯片等这些不足之处外,基于浏览器平台的插件密码管理器,还面临更多严重的安全威胁:
桌面客户端可以采用一些系统底层技术,防止Keylogger程序偷取主密码,但是基于Web技术的插件密码管理器程序,无法访问操作系统的底层接口,完全依赖浏览器的密码输入框,无法防范Keylogger
攻击。
数据来源:CVE Details
浏览器天然联网的特性,让很多漏洞更容易被黑客远程利用。基于浏览器平台的插件密码管理器也很容易被攻击。黑客不论是在操作系统上植入恶意程序,还是攻破浏览器的保护,都很容易破解插件密码管理器。
安全研究员Martin Vigo曾在Even the LastPass Will be Stolen, Deal with It!中演示了破解LastPass插件的方法,其中基于插件客户端的方法就有4种。
浏览器的插件开发接口基于Web技术,非常开放灵活。恶意程序通过 Web DOM/JS(Document Object Model/Javascript),几乎可以访问和控制页面中的任何内容。著名安全研究员 Sean Cassidy 在他的博文Browser Extension Password Managers Should Not Be Used中认为无法避免插件密码管理器的风险。
在研究技术方案过程中,我们逐步探索出这样的设计逻辑:
浏览器插件可以方便解析必要信息,例如网页中是否有登录框、当前网址;帮助用户自动填充密码时,也可以使用DOM/JS技术,将用户名和密码填入文本框中。所以,基于插件技术才能更好地帮助用户。
浏览器插件平台在安全上的诸多风险难以克服,因此索性就不做密码管理,直接将插件作为神锁离线版app在浏览器中的延伸。插件不管理也不保存用户密码,不暴露这个攻击面,不给黑客留下攻击的机会。
相当于基于插件技术实现一个远程自动填充框架,而不是一个密码管理器。
自动填充的原理是:先从网页中获取需要填充密码的相关信息(网址等),再从神锁离线版app中选择对应账号。App没有网络权限,不能访问网络,那如何将网页中得到的信息传输到app中呢?我们没有给神锁离线版app增加网络权限,而是改变了信息的传输方式:
a. 插件将网页信息编码成二维码,展示在屏幕上
b. 神锁离线版app扫码获取信息,无需使用网络
同样,没有网络权限的神锁离线版又怎样将用户所选的账号密码发送到插件呢?
是否可以使用电脑上的摄像头扫码手机app呢?使用电脑摄像头扫码虽然可行,但操作起来实在不方便。
智能手机都安装有手机浏览器,可以通过浏览器运行云端的H5网页程序把数据发送到插件。发送的数据作为H5网页的参数输入,H5网页也能方便查看源代码,用户完全可以自行审计整个数据传输的安全性。
《是时候放弃插件密码管理器,改用密码管理器插件了》一文介绍了插件的使用方法。其设计原理如下:
架构图
序列图
a. 生成ECC密钥对
b. 使用ECDH算法生成共享密钥
c. 使用共享密钥加密用户名、密码等信息
通过app端到插件端的ECDH密钥协商,实现了端到端加密,确保用户密码不会由于云端传输而被黑客甚至内部员工偷取。
使用神锁离线版自动填充时,用户需要在手机上操作两次。和插件密码管理器不同的是,桌面或者网页中的恶意程序无法攻击手机App。
典型的Chrome浏览器插件有4大组件:
Background Script
背景脚本负责处理事件和消息UI Elements
包括插件icon上的popup,以及其他界面元素Content Script
可以访问网页中的内容Options Page
允许用户设置一些选项参数等每个组件都隔离在独立的进程中运行,提升安全性。组件之间使用插件平台提供的消息机制通信。
神锁离线版插件的UI Elements
和Options Page
比较简单,这就不讨论了。Content Script
和Background Script
的工作原理如下:
Content Script
主要负责检测页面中的登录框,以及将接收到的用户名和密码填充到登录框中。它提供了两方面的安全防护:
自动填充虽然方便,但也暴露了一个攻击面,黑客可能利用自动填充偷取用户密码。今年的一篇论文Revisiting Security Vulnerabilities in Commercial Password Managers,重点研究了一些密码管理器自动填充的防欺诈能力,发现它们普遍做得都不够好。而神锁离线版App的高级防欺诈能力可以有效防范这些欺诈。
神锁离线版插件继承了app已有的防欺诈能力,Content Script
结合登录页面的信息,还提供了更多的欺诈检测能力:
为什么登录域名应该与当前网页域名一致?
互联网平台的账号管理服务,内容一般比较精简,不会包含第三方内容,执行更加严格的安全审计流程,甚至由专业的独立团队负责。
业务网页以功能为主,内容丰富,包含很多第三方资源,甚至大量第三方广告。开发流程也不像账号管理那样严格,很难保证页面中所有内容的安全,存在盗号风险。
目前来说,ECC算法是很安全的,暴力破解非常困难。而另一方面,量子计算已经显示出未来破解ECC算法的潜力。无论是为了防范哪种风险,都很有必要限制ECC密钥的暴露时间,所以我们给二维码设置了2分钟的有效期,2分钟后自动关闭扫码框。神锁离线版App再扫描2分钟之前的二维码,会提示过期,不会执行自动填充操作。
2分钟时间一般够用户拿出手机扫码填充,而无需手忙脚乱;即使将来量子计算破解ECC算法成熟了,预计也很难在2分钟以内完成破解,传统的计算机就更不可能破解了。
Background Script
负责密钥管理和接收app发送过来的加密密码,这是远程自动填充框架的核心。因此我们做了很多的安全设计,包括:
密钥管理和云端通信都在插件后台进程中运行,与前端页面完全隔离。
这意味着页面中的恶意JS代码无法通过DOM接口访问到后台进程中的加密数据。
某些密码管理器大量泄露用户密码的原因之一就是对数据请求没有限制,恶意代码可以模拟网页登录,偷取大量网站用户的密码。
为此,我们设计了请求限速算法,限制创建密钥对和二维码的速度,直接拒绝明显超出正常操作的请求。
采用非对称高强度椭圆曲线算法,协商加密密钥,实现对填充数据的端到端(神锁离线版app端到插件端)二次加密,即使是内部员工也无法偷看填充密码。
通常可以选择的ECC曲线有P-256、P-384、P-521等,兼顾安全性和兼容性,我们选择了ECC P-384。
const curve = {name: "ECDH", namedCurve: "P-384"};
page.keyPair = await window.crypto.subtle.generateKey(curve, false, ["deriveKey"]);
在调用Webcrypto
API生成密钥时,设置extractable
参数 false,禁止提取私钥。
恶意程序即使突破了浏览器的进程隔离,也仍然无法读取不可导出的私钥,除非它还能更进一步突破浏览器的密钥管理保护。
不存储、不重用ECC密钥对。不仅每个页面会生成独立的密钥对,而且同一个页面每次打开扫码框都会重新生成。
结合Content Script
的2分钟二维码有效期限制,极大提升了破解成本。黑客即使破解某次加密,也无法破解另一次填充。
插件接收到云端发送过来的ECC公钥和加密数据后,接下来:
采用标准的ECDH
算法,生成共享的AES-256-GCM
密钥。
const curve = {name: "ECDH", namedCurve: "P-384"};
const publicKey = await window.crypto.subtle.importKey('spki', keyBytes, curve, true, []);
const ecdh = {name: "ECDH", public: publicKey};
const aes = {name: "AES-GCM", length: 256};
const secretKey = await window.crypto.subtle.deriveKey(ecdh, page.keyPair.privateKey, aes, true, ["encrypt", "decrypt"]);
解析出AES-256-GCM
的IV(Initial Vector)
参数和密文后,调用webcrypto
API得到原文。
const ivBytes = Uint8Array.from(window.atob(encrypted.iv), c => c.charCodeAt(0));
const cipherBytes = Uint8Array.from(window.atob(encrypted.cipher), c => c.charCodeAt(0));
const aesParams = {name: "AES-GCM", iv: ivBytes};
const bytes = await window.crypto.subtle.decrypt(aesParams, secretKey, cipherBytes);
选用AES-256-GCM
模式,在解密时还可以校验数据是否被篡改过。相比AES-CBC
等其他模式,进一步提升安全性。
当然,网络通信必须全部采用HTTPS/WSS协议,再增加一层安全防护。
大多数插件密码管理器是一个完整的云同步客户端,神锁离线版对浏览器的支持,拆解成了两个协同工作的组件:
将功能分解且分散在不同的终端,有效减小了攻击面,能够更有效地保护用户数据安全。
攻击面 | 神锁离线版App | 神锁离线版插件 | 插件密码管理器 |
---|---|---|---|
网络 | N | Y | Y |
持久存储 | Y | N | Y |
交互界面 | Y | Y | Y |
Web DOM | N | Y | Y |
插件密码管理器会暴露4个攻击面,而神锁离线版App会暴露2个,插件暴露3个。
神锁离线版App和插件将两个风险最大的攻击面彻底分离——存储数据不联网、联网不存储数据。
那么,相比插件密码管理器,神锁离线版插件在各个攻击面上做了哪些改进呢?
1.网络攻击
神锁离线版插件虽然也无法彻底杜绝恶意代码、插件等偷取正在填充的密码,但是不会泄漏所有密码,因为它们保存在更安全的手机系统中,不会受桌面端的影响。
2.持久存储
Windows上运行的很多其他程序,都可以读取Chrome浏览器的存储数据,插件密码管理器存储的数据也在其中,包括加密的密码数据库,插件密码管理器登录服务的cookie,以及其他重要数据。
如果用户选择保存主密码,恶意程序就可以解密出所有密码。如果没有保存,恶意程序需要的也仅仅剩一个主密码了。虽然主密码应该很长、很复杂、唯一,但很多用户仍然会使用弱密码作为主密码,仍然会重用主密码,恶意程序还可以通过Keylogger
技术偷取用户输入的主密码。
当然,这还是比Chrome自带的密码管理器要安全很多,毕竟它连主密码都不要。
神锁离线版插件没有暴露这个攻击面。
3.交互界面
Sean Cassidy 在LostPass中展示了一项技术:利用像素级模仿密码管理器界面,偷取用户主密码。
钓鱼攻击往往利用容易忽略或难以分辨的细节,误导用户将密码输入到恶意程序/网页中。与浏览器集成度越高的插件,往往越容易被恶意程序钓鱼。我们都知道,制作这种像素级完全一致的界面并没有技术上的障碍。
浏览器没有为插件提供很多特别的界面支持,不能让插件密码管理器的界面显得特别,不能帮助用户分辨和防范针对密码管理器的钓鱼攻击。这就尴尬了:
本来应该防范钓鱼的密码管理器,也可以被钓鱼!
神锁离线版插件和App一样,没有账号,无需注册,无需登录,无需主密码,无鱼可钓。
4.Web DOM
这是浏览器插件独有的攻击面。开头演示的视频,就是利用浏览器的DOM编程接口,操纵了插件密码管理器展示的界面,偷取了用户密码。如果可以利用合适的漏洞,甚至都不需要用户操作,偷密码于无形之中。
使用神锁离线版插件填充密码,需要用户手动扫码,所以用户必然知道自己正在登录网站。恶意程序不可能在用户没有意识的情况下,发动攻击,自动偷取密码。
论文《Revisiting Security Vulnerabilities in Commercial Password Managers》中使用了多种欺诈方法攻击多款流行的密码管理器,没有一款可以躲过所有的欺诈。
神锁离线版插件增强的防欺诈,再结合App端的高级防欺诈,可以有效识别出论文中提到的各种欺诈。
查看插件manifest.json
,可以看到神锁离线版插件要求的权限很少,不能读取用户浏览历史记录,不能监控网络通信。所以,神锁离线版插件既不能偷取用户这些数据,也不会因为被黑客攻破而泄露用户隐私。
同样在manifest.json
中,很多插件密码管理器会声明连接的服务域名,还有不受自己控制的第三方域名。服务商要确保很多个服务/域名的安全,甚至是第三方服务的安全,难度可以想像。
神锁离线版不会连接第三方服务,也仅仅开放一个连接域名,相比要安全很多。
神锁离线版支持桌面浏览器,安全设计主要表现在这几个方面:
插件不保存任何用户密码,密码仍然全部存储在更安全的手机端app——采用了第四代安全存储设计。
超过95%的安全事故都涉及网络,神锁离线版App仍然保持离线,没有暴露这个最大的攻击面,不受网络相关攻击的影响。
用户在手机端选择要填充的密码,密码被加密后传输到插件,插件解密密码并填充到登录框中。神锁离线版插件采用了以下技术,确保传输的密码安全:
AES-256-GCM
高强度加密,且防数据篡改大家知道,HTTPS/TLS也广泛采用ECDH/AES来确保数据安全,大多数密码管理器云端同步都会基于HTTPS/TLS。而神锁离线版插件实现的ECDH/AES算法比HTTPS/TLS更安全,下一篇再做详细对比分析。
神锁离线版一向非常重视防欺诈能力,在插件上同样延续了这个优良传统,做了不少新设计:
无法杜绝Web DOM的攻击面,这给恶意程序留下了很多欺诈机会,但神锁离线版app管理的密码无论如何都不会凭空飞到桌面浏览器中。用户手动扫码这个操作,既让用户明确意识到密码会发送到桌面浏览器,又限制了发送密码的速度。程序可以每秒执行数百万次,手动扫码是不可能的。即使用户不小心上当受骗,这个设计也有助于限制泄密的数量和速度。
在手机上选择账号填充时,App会清晰地展示当前正在填充的网址、是否需要填充密码等信息。如果用户选择填充的账号存在泄密风险,还会弹框提醒。例如,用户打开了一个像素级复刻的钓鱼网站faceb00k.com
,在手机端选择facebook
账号填充时,App就会提醒用户这个是钓鱼网站。
特别指出:通过插件填充密码,无法避免密码被恶意插件或者网页中的恶意JS脚本通过网页DOM读取。对此,技术上还没有办法杜绝,即使是用户手动输入密码,也同样无法避免。
领取专属 10元无门槛券
私享最新 技术干货