Submarine

本页为译文。如与英文版有出入,以英文版为准。 英文版

你的数据如何受到保护

我们不要求你信任我们。本页准确说明哪些内容被加密、我们的服务器能看到和不能看到什么,以及你如何亲自验证每一项说法。

一分钟了解

  • 你的服务器、登录凭据、密钥和笔记存放在你设备上的一个文件里,并使用 AES-256-GCM 加密。少数只针对本设备的选择,例如应用的外观和与 RDP 服务器共享的文件夹,以未加密的形式保存在应用的设置中,并且从不同步。
  • 加密所用的密钥由你的配置文件密码通过 Argon2id 生成。Argon2id 是一种有意设计得很慢的方法,让猜测密码的代价很高。密码从不保存,也从不发送到任何地方。
  • 如果你开启同步,每个条目在上传前都会先在你的设备上加密。服务器保存的是它无法解密的数据。
  • 服务器确实能看到你数据的外围信息:你的邮箱地址,你在何时、从哪个 IP 地址同步,你每种条目各有多少个、各有多大,你的配置文件名称,以及共享配置文件的共享名称和成员的邮箱地址。
  • 应用没有广告、没有统计分析,也没有崩溃报告。

服务器无法读取

  • 你条目中的内容:名称、地址、端口、用户名、密码、私钥及其密码短语、隧道、笔记、命令、文件夹名称
  • 哪个登录凭据或密钥属于哪台服务器
  • 是谁修改了某个条目
  • 你的配置文件密码、共享密码短语,以及能打开你配置文件的密钥

服务器能看到

  • 你的邮箱地址,以及你登录时的账户密码(服务器只保存它的 bcrypt 哈希值)
  • 登录和同步时的 IP 地址和时间
  • 一个配置文件中每种条目各有多少个、它们的大小,以及每个条目在何时被哪台设备(以随机 ID 标识)修改
  • 你的配置文件名称
  • 对于共享配置文件:共享名称、成员的邮箱地址及其角色

同步时会发生什么

从不离开你的设备
配置文件密码Argon2id配置文件密钥AES-256-GCM加密条目
HTTPS同步服务器保存加密条目和上面列出的信息
密码和密钥都留在你的设备上。发送出去的只有加密条目,以及它们的相关信息。

1. 在你的设备上

每个配置文件都保存为一个单独的文件,里面是一个小型数据库,存有你的服务器、登录凭据、SSH 密钥、笔记和设置。整个数据库先压缩,再用 AES-256-GCM 加密。每次保存文件时都会使用一个新的随机 nonce;而且文件会先写入一个临时副本,因此即使程序崩溃,也不会留下只写了一半的文件。

密钥由你的配置文件密码通过 Argon2id 生成,参数为:内存 64 MiB、3 轮迭代、4 条并行通道,并且每个配置文件都有各自的随机盐值。这些参数固定写在应用中,因此即使文件被改动,也无法削弱它们。

密码从不写入磁盘,也从不发送到任何地方。密钥生成后,应用核心中的那份密码副本会被清除;当你锁定配置文件时,密钥也会被清除。锁定还会关闭所有连接,并取消仍在进行中的登录。如果你忘了密码,这个配置文件就无法打开。也没有重置的办法,因为任何地方都没有保存能打开它的东西。

快速解锁是可选功能,默认关闭。在 Windows 上,它使用 Windows Hello 和 TPM;在 Android 上,它使用指纹传感器和 Android Keystore。系统保管的是配置文件的密钥,绝不是你的密码,而且这个密钥从不同步。在 Android 上,系统对本应用数据的云备份是关闭的。

在 Windows 上,当“远程桌面连接”打开一台保存了密码的服务器时,应用会通过一个临时的 .rdp 文件把密码交给它。文件中的密码使用 Windows DPAPI 针对你的 Windows 用户加密;“远程桌面连接”一读取完,文件就会被删除(最迟 30 秒后删除;如果程序崩溃留下了这个文件,会在下次启动时清除)。

2. 云同步(Cloud sync)

在你登录之前,同步是关闭的。每个配置文件都有自己的随机 256 位数据密钥,它保存在加密的配置文件内部。上传前,每个条目(一台服务器、一个登录凭据、一个密钥、一条笔记……)都会用这个密钥单独加密,使用 AES-256-GCM 和一个新的随机 nonce。

除了加密条目本身,服务器还会收到每个条目的随机 ID、条目类型、一个时间戳,以及一个表示该条目是否已删除的标记。时间戳中包含做出更改的那台设备的随机 ID。从加密条目的大小,可以大致看出条目本身有多大。服务器还会保存每个配置文件的名称。已知主机密钥、命令历史、监控设置,以及只针对本设备的选择,从不同步。

以下是服务器为一个条目保存的内容 (示例)

{
  "uuid": "6f1c2e0a9b7d4c3e8a5f0d1b2c3e4f50",
  "entity_type": "servers",
  "updated_at": "001761043562118:00000:9f3a61c2d4e5b7a8",
  "deleted": false,
  "blob": "4e8a1f0c2b9d3e7a5c6f8b1d0a2e4c6b8d0f1a3c5e7b9d1f…"
}

3. 在新设备上打开配置文件

要在另一台设备上打开已同步的配置文件,那台设备需要该配置文件的数据密钥。因此,服务器还会多保存一条记录:经过加密的数据密钥。加密它的密钥由你的配置文件密码生成,使用相同的 Argon2id 参数。服务器无法打开它。

万一攻击者窃取了服务器的数据,这也是他们主要能尝试的事:离线猜测你的配置文件密码。每猜一次都要完整运行一次 Argon2id,因此,一个不在别处使用的长密码可以保护好你的数据。

4. 你的账户密码

你的同步账户有自己的密码,与配置文件密码分开。你登录时,它会通过 HTTPS 发送到服务器,服务器只保存它的 bcrypt 哈希值。输错 5 次密码后,密码登录会暂停 15 分钟。

该服务位于 Cloudflare 之后,由 Cloudflare 为它处理 HTTPS 连接。因此,和服务器一样,Cloudflare 在你登录时也可能看到你的账户密码;但对于你的条目,它只能看到加密后的形式。

切勿把配置文件密码用作账户密码。这样一来,服务器或 Cloudflare 能看到的任何内容,都打不开你的配置文件。

5. 共享配置文件

为了共享配置文件,每个账户都有一个 X25519 密钥对。私钥用一个由你的共享密码短语生成的密钥加密(同样使用 Argon2id),而这个密码短语从不离开你的设备。共享配置文件的每个成员,都会收到一份用其本人公钥封装的配置文件数据密钥。

邀请他人时,应用会使用服务器为该邮箱地址提供的公钥。如果某个成员的密钥之后发生了变化,应用会告诉你,并显示一个指纹,供你与对方核对。服务器知道共享配置文件的名称以及谁是成员,但不知道其中的内容。

6. 如果服务器怀有恶意

好的安全性,不只看服务器本应做什么。下面列出了完全控制服务器的人能做和不能做的事。

他们无法

  • 读取你的条目,或在不被发现的情况下修改其中的内容
  • 在没有你的配置文件密码的情况下,打开存储的配置文件密钥副本
  • 得知你的配置文件密码或共享密码短语,因为应用从不发送它们
  • 更改你设备上的应用:应用没有自动更新,只会提示有新版本

他们可以

  • 离线尝试猜测较弱的配置文件密码,每猜一次都要运行一次缓慢的 Argon2id
  • 在你下次登录时截获你的账户密码
  • 删除条目、恢复旧版本,或扣留更改。在同步删除任何内容之前,应用会在你的设备上保留一份配置文件副本
  • 在你邀请他人加入共享配置文件时,提供错误的公钥
  • 看到上面表格中列出的信息

7. 应用的全部网络连接

你自己的服务器,以及你为它们设置的代理和跳板机。同步服务器,仅在你已登录时连接。还有 GitHub,用于检查是否有新版本:在配置文件列表打开时,以及你点击“Check for updates”(检查更新)时,应用会查询 GitHub 上公开的发布版本列表。该请求只包含应用的名称和版本号。

应用中没有统计分析、崩溃报告或广告代码。同步时,应用只信任它内置的证书颁发机构列表,并且从不跟随重定向,因此无法被悄悄地指向别的服务器。

8. 远程桌面会从你的设备获得什么

剪贴板。你粘贴到 RDP 或 VNC 标签页中的文本会发送到那台服务器;在你粘贴之前,不会向它提供任何内容。开启 Share the clipboard(共享剪贴板)时(默认开启,每台服务器都有单独的开关),在远程桌面上复制的文本会被放到本设备的剪贴板上。只传输文本,从不传输文件,而且 VNC 只能传输纯 ASCII 文本。

文件:只有在电脑上使用内置 RDP 客户端,并且你为该服务器选择了一个文件夹或驱动器时,才会共享文件;你也可以设为只读。服务器看到的是 \\tsclient 下的一个驱动器,看不到你电脑上的其他任何内容。它请求的每个路径都会经过检查:不允许 ..,途中也不跟随任何链接,因此你所选范围之外的任何内容都无法访问。

这些选择保存在本设备上,从不同步,因此与你共享配置文件的人都无法开启它们。

亲自验证

这些说法,你都不必只听我们的。下面是一些验证方法,由浅入深。

  1. 阅读代码

    应用是开源的。本页中的链接直接指向实际完成这些工作的代码行,对应本页所描述的版本(c9dec31)。

  2. 观察网络连接

    使用防火墙或网络监控工具。你会看到你自己的服务器、仅在你登录期间出现的同步服务器,以及配置文件列表打开时访问的 api.github.com。除此之外,再无其他。

  3. 查看服务器保存的内容

    进阶:从应用的数据文件夹(cloud_token.json)中取出你的登录令牌,带上 X-Auth-Token 请求头向 API 请求你的数据:GET /api/sync/profiles,或者用空的记录列表发送 POST /api/sync。返回的只有 ID、类型、时间、标记和加密文本。完成后,请在应用中退出登录,以结束该会话。

  4. 查看通信内容

    进阶:在你的电脑上运行一个小型代理,把请求转发给真正的服务器,然后把应用的同步服务器设为 http://127.0.0.1 加上代理的端口。应用只允许对你自己的电脑使用明文 HTTP。你会看到应用发送了什么,也会看到你的条目是加密的。(在系统中添加代理证书不起作用,因为应用使用自己的证书颁发机构列表。)

  5. 解密你自己的数据

    进阶:有了你的密码,你就可以用任何支持 Argon2id 和 AES-GCM 的工具,按照下表中的参数打开你自己的数据。没有密码,谁都打不开。

  6. 校验下载文件

    将校验和与发布版本中的 SHA256SUMS 进行比对(从 0.4 版开始提供),用 apksigner 检查 Android 应用的证书,或者从源代码自行构建应用。

供你自己的工具使用的参数

密钥派生Argon2id,版本 0x13,内存 64 MiB,3 轮迭代,4 条并行通道,32 字节密钥,16 字节随机盐值
本地配置文件“OMNV” · 版本 1 · 盐值(16 字节)· nonce(12 字节)· 用 AES-256-GCM 加密的、经 zstd 压缩的 SQLite 数据库,附带 16 字节标签
同步的条目hex(nonce(12 字节)· AES-256-GCM 密文和标签),使用配置文件的 256 位数据密钥
配置文件密钥的存储副本hex(0x02 · 盐值(16 字节)· nonce(12 字节)· 用 AES-256-GCM 加密的 32 字节数据密钥),使用由你的配置文件密码生成的密钥
共享X25519、HKDF-SHA256、AES-256-GCM

本页不承诺什么

  • Submarine 尚未经过独立的安全审计。迄今为止的审查都由作者本人完成。
  • 弱密码或重复使用的密码是最薄弱的环节。请使用一个长且独一无二的配置文件密码,并使用一个与之不同的账户密码。
  • Telnet 和普通 VNC 在设计上就不加密。应用会对它们加以标注,并且可以让它们经由 SSH 服务器连接。通过普通 VNC 时,你粘贴的或服务器复制的剪贴板文本,同样会以未加密的形式在网络上传输。
  • 内置 RDP 客户端是实验性功能(它基于 IronRDP 的某个提交构建,而不是正式发布版本),在你为某台服务器选择它之前是关闭的。
  • 本页描述的是提交 c9dec31 对应的应用版本。代码如有变化,本页也会随之更新。