“在互联网上,没人知道你是一条狗”。知名国际大厂也未必像他们说的一样保护我们的数据安全:
备受舆论压力的大厂都这样,那管理所有密码的密码管理器能放心吗?神锁离线版插件声称采用了端到端加密技术,连内部员工都无法偷取用户密码,是不是真的呢?
来,我们告诉你怎么亲手验证我们的安全技术!
神锁离线版可能是唯一一个能告诉用户怎样验证安全技术的密码管理器。
不用太担心不懂技术细节,只需要有一点耐心,就可以和我们一起动手做实验!
比萨斜塔 来自 Saffron Blaze
首先,本次实验的目的是验证:
回顾一下神锁离线版插件架构和原理:
我们在app中选择要填充的账号后,用户名和密码是怎么从手机发送到插件的呢?
插件实现端到端加密(End-to-end encryption, E2EE)的关键在于借助ECDH算法,可以在插件和app(下图中Alice和Bob)之间建立共享的加密密钥,确保通信安全。
主要步骤:
实验条件:安装并使用神锁离线版app和插件。
以 Edge 浏览器为例,先设置断点,以便截获传输数据进行分析。步骤如下:
1.从浏览器菜单中,找到 扩展
,打开插件管理界面
2.在插件管理中找到神锁离线版,点击 背景页
链接,打开浏览器调试窗口
3.设置截获数据的断点:
这里稍微麻烦一点,点击4次,分别选择:
onServerMessage
函数的定义,在左边行号上点击,设置红色的断点。1. 浏览器中打开登录网页 http://www.stealmylogin.com/demo.html ,会看到扫码填充框
2. 使用神锁离线版app扫码,app从二维码中可以得到正在填充的网站域名和插件公钥 实验中不要使用真实账号密码,以防泄密给第三方网站。
3. 选择账号后,app会打开手机浏览器开始填充。点击浏览器的地址栏,复制地址并记录下来。地址有点长,大概是这个样子:
https://app-link.bluespace.tech:8081/remote-
fill/index.html#a=&t=1609300964&host=www.stealmylogin.com&to=15579832-e41c-4b17-8615-
b6507a02dd4b&key=MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELzVA%2B9qJXZJShDcwWxo5%2FWWQTOGi%2FuaR
Ai1%2BHrcLWw6vISQmzusRptXE%2BCTSVi2HWxQ3BQjCDDd%2FPqTyATgkeUyv3GbfBBXVw2q8LjVpt1wnlrFG7
29QsnExYVqgI5WP&iv=v6DyQ%2Bmx16mt71Ab&cipher=1Ug43zUPuRkQn74m1309FL0J5BNGcqT5FHcwubzYnp
BLAscF%2Bn78RfmurjiWIgOP3cbZ1%2F5Kz%2Fa9sjWyZozdUv1HXmo3u0k3%2F16KkPGuWaaTsHt8uCV7tQP0M
NIs84fxr4REnBY%3D
简单讲解一下,#
符号前面是网页地址,后面是传递给网页程序的数据项目,以&
分隔,每个项目格式是名字
=数据
。整理其中的数据项目:
t=1609300964
是填充的时间,用于检测是否过期host=www.stealmylogin.com
是当前正在填充的网站to=15579832-e41c-4b17-8615-b6507a02dd4b
是插件的接收地址,每次填充都随机生成key
是app密钥对的公钥,可以和插件的私钥一起生成加密密钥iv
是AES-GCM加密参数,随机初始向量(Initial Vector)cipher
是加密后的密文4. 很快插件背景页就会在断点捕获到传输过来的数据,大概是这个样子:
message
上,查看捕获的消息,大概是这个样子: {
to: "15579832-e41c-4b17-8615-b6507a02dd4b",
from: "a3ae6e09-8b2c-43bf-a61b-08f4022adfc5",
ts: "1609300964",
id: "83072ef7-11fe-49fe-bac3-787f92881bbf",
data: "{
"key":"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELzVA+9qJXZJShDcwWxo5/WWQTOGi/uaRAi1+HrcLWw6vISQmzusRptXE+CTSVi2HWxQ3BQjCDDd/PqTyATgkeUyv3GbfBBXVw2q8LjVpt1wnlrFG729QsnExYVqgI5WP",
"iv":"v6DyQ+mx16mt71Ab",
"cipher":"1Ug43zUPuRkQn74m1309FL0J5BNGcqT5FHcwubzYnpBLAscF+n78RfmurjiWIgOP3cbZ1/5Kz/a9sjWyZozdUv1HXmo3u0k3/16KkPGuWaaTsHt8uCV7tQP0MNIs84fxr4REnBY="
}"
}
这个消息内容也要记录下来分析(记录的时候,可以像上面一样调整顺序换行)。
收集到所有数据后,我们就可以进行数据分析了。
先对比手机端发送的数据和插件接收到的数据:
数据项目 | 浏览器发送 | 插件接收 | 一致 |
---|---|---|---|
时间 | t=1609300964 | ts: "1609300964" | Y |
接收地址 | to=15579832-...-b6507a02dd4b | to: "15579832-...-b6507a02dd4b" | Y |
ECC公钥 | key=MHY...5WP | "key":"MHY...5WP" | Y1 |
加密IV | iv=v6DyQ%2Bmx16mt71Ab | "iv":"v6DyQ+mx16mt71Ab" | Y1 |
密文 | cipher=1Ug...BY%3D | "cipher":"1Ug...BY=" | Y1 |
填充网站 | host=www.stealmylogin.com | NA | N |
消息ID | NA | id: "83072ef7-...-787f92881bbf" | N |
发送地址 | NA | from: "a3ae6e09-...-08f4022adfc5" | N |
1 /
, +
, =
等特殊字符在网页地址中会被替换为 %2F
%2B
%3D
↩ ↩ ↩
host=www.stealmylogin.com
没有发送给插件。这个数据项只用于在手机浏览器中向用户展示,云端并不知道用户当前填充的网站,隐私无忧。要验证这两点,需要查看
https://app-link.bluespace.tech:8081/remote-fill/index.html
中script.js
的源代码,后面有为程序员准备的详解
数据就这些了,对于第一个目标,我们只需把它们和密码对比一下,就很容易确认有没有偷偷发送给云端。
但是还不能完全确认:会不会在传输的数据中夹带密钥,让云端有能力解密出传输的数据呢?
接下来我们要验证有没有带私货给云端解密。
图片来自 Metinegrioglu
发送的其他数据都很简单,只有加密三元组:公钥key,加密IV和密文数据,看起来很奇怪,也比较长,会不会夹带密钥呢?
key
公钥是否夹带了额外数据?
验证方法:截获的公钥长度是不是160个字符?
知识点:
spki
格式编码,长度是120字节。示例:
截获的数据 MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELzVA+9qJXZJShDcwWxo5/WWQTOGi/uaRAi1+HrcLWw6vISQmzusRptXE+CTSVi2HWxQ3BQjCDDd/PqTyATgkeUyv3GbfBBXVw2q8LjVpt1wnlrFG729QsnExYVqgI5WP
与公钥长度一致,没有夹带额外数据。
iv
是否夹带了额外数据?
验证方法:截获的iv
长度是不是16个字符?
知识点:
IV
是完全随机的12字节二进制数据。示例:
截获的数据 v6DyQ+mx16mt71Ab
正好是16个字符,没有夹带额外数据。
如果我们多做几次实验,会发现即使是同一个账号,每次IV
也是不一样的。
程序员在调试的时候,还可以把密钥打印出来和IV对比,看看是不是一样的。
3. cipher
密文是否夹带了额外数据?
验证方法:是否能够成功填充密码?
知识点:
AES-256-GCM
算法,可以帮助检测密文数据的完整性。如果密文有改动,解密就会失败。程序员在调试的时候,看到 decryptMessage 函数执行没有出错就可以证明没有夹带额外数据了。
进行这3个数据项的检验,就可以判定是否夹带了额外数据。
前面讲解了验证方法,但是没有详细程序实现,显然不是程序员的菜。接下来讲解程序实现中的关键点。
插件和网页发送程序的源代码都没有最小化和混淆,清晰可读,非常方便程序员们帮忙审计。
查看 https://app-link.bluespace.tech:8081/remote-fill/index.html
网页源码很容易找到主要代码 script.js
。
const params = new URLSearchParams(window.location.hash);
const timestamp = params.get('t');
const host = params.get('host');
const to = params.get('to');
const key = params.get('key');
const iv = params.get('iv');
const cipher = params.get('cipher');
向网页传递参数使用#(window.location.hash)
分隔,而不是?
,可以防止我们的app开发者写了bug导致泄漏用户信息,因为#
后面的数据,不会传递到云端。
2. 将解析出来的数据 t
, to
, key
, iv
, cipher
组装成一个Json对象的消息。
const data = JSON.stringify({key: key, iv: iv, cipher: cipher});
const uuid = uuidv4();
const request = {to: to, from: uuid, ts: timestamp, id: uuidv4(), data: data};
这里可以确认,host
不会发送到云端,不会泄漏用户隐私。
3. 再接下来就是使用AJAX将组装的消息发送到云端。
数据通过websocket接收,入口是 onmessage
事件,数据处理就是断点的函数 onServerMessage
,核心解密部分是crypto.js
中的 decryptMessage
函数:
importPublicKeyText = (Base64Text) => window.crypto.subtle.importKey(this.publicKeyFormat, Base64.decode(Base64Text), this.curve, true, []);
deriveKey = (publicKey, privateKey) => window.crypto.subtle.deriveKey({name: "ECDH", public: publicKey}, privateKey, {name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
decrypt = (ivBytes, cipherBytes, secretKey) => window.crypto.subtle.decrypt({name: "AES-GCM", iv: ivBytes}, secretKey, cipherBytes);
decryptMessage = async function(keyPair, data) {
const encrypted = JSON.parse(data);
const publicKey = await this.importPublicKeyText(encrypted.key);
const secretKey = await this.deriveKey(publicKey, keyPair.privateKey);
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 bytes = await this.decrypt(ivBytes, cipherBytes, secretKey);
return new TextDecoder().decode(bytes);
};
主要三个操作:
importPublicKeyText
导入 spki
格式的公钥;deriveKey
调用 ECDH
算法生成256位的AES密钥;decrypt
使用 AES-GCM
模式解密出原文。GCM是一种特别的AES模式,可以校验数据的完整性,防止篡改。尽管密码学和网络安全都是很专业的技术领域,我们仍然希望尽可能让更多人了解和验证我们使用的安全技术。在设计神锁离线插件时,我们不仅会努力创造最安全的技术,同时还会尽力尝试为用户提供验证技术的方法。
如果没有相关专业知识,可能还是会留下一些疑问。不过我们相信,通过这样详细的验证方法讲解,足以让具备一定相关知识的技术人员能够弄清楚每个细节。
大家都已经知道,加密 ≠ 安全,所谓的军事级别加密,只是营销口号,忽悠外行。 密码管理器的安全关键在于:安全设计。
神锁离线版插件的加密传输有多安全?比银行都在使用的HTTPS还安全。
原创声明,本文系作者授权云+社区发表,未经许可,不得转载。
如有侵权,请联系 yunjia_community@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。