115 账号共享之路

115 的离线下载功能确实强悍,但是 500 元一年的会员价格也不便宜。于是我就与三个朋友一起合买了一年会员,准备四人共享使用。但是 115 的单点登录却给共享带来了很多限制,于是我们探索了诸多共享方案,期间历程就便成了这篇博文。

1. 115 的限制

  • 单点登录

    115 在所有客户端,包括网页端,PC 端(本质就是网页端)和手机端都实行单点登录。这就意味着,只要有任何一个客户端通过账号密码登录成功,之前的所有登录都会失效,无论是什么端。

  • 115 浏览器

    在网页端只能通过手机端扫码才能登陆,在 115 浏览器上可以通过账号密码登录,但是初次登录依然需要手机接收验证码。不过整体来说就 115 服务的使用上,115 浏览器还是要优于 Chrome:在 115 浏览器上下载 115 资源可以支持多线程下载和断点续传;且在 115 浏览器上打开磁力链接可以直接启动 115 离线下载。但是 115 浏览器 Chromium 版本还停留在 54,且标签页开的一多就卡顿,所以也只能当做 115 客户端用。

2. 瞎搞阶段

一开始我们四人并没有想出如何破解 115 的单点登录限制。因此临时的共享方案是“二级离线下载”。具体如下:

  • 我们在校内有一台公用电脑,24 小时开机并保持 115 登录状态。
  • 任何人有下载需求时,就通过远程桌面连接公用电脑,将资源下载到公用电脑上。
  • 公用电脑下载结束后,利用校园的百兆内网,通过 FTP 传回自己的电脑。

这当然有诸多限制:

  • 在公网环境下,无论是远程桌面控制内网的公用电脑,还是 FTP 从内网公用电脑取下载资源都比较困难。
  • 远程桌面是抢占式的,也就是说一个人在使用过程中会被另一个登录的人挤下去。
  • “二级离线下载”永远还是要多一步,非常麻烦。

为了解决上述问题,我们也付出了一些努力:

  • 通过内网穿透,在公网也能轻松访问公用电脑。但是我的服务器水管太小,用 FTP 取回资源的速度太慢。
  • 为了解决远程桌面抢占式的问题,我们在公用电脑上搭建了一个状态服务器,可以随时显示当前公用电脑有没有被使用。接着制作了一个远程桌面的脚本,先取公用电脑状态,只有空闲时才会继续启用远程桌面。

虽然通过上面两个 workaround 解决了部分问题,但是水管太小,操作麻烦的本质问题还是没有得到解决,再继续下去只是在点错的技能树继续错下去而已。

3. 利用 Cookies 共享账号

其实很多人应该看到这里应该会嘲笑我,因为用 Cookies 来共享账号应该是非常容易想到的事情。

确实,当时我的第一个想法也是利用 Cookies,但是由于学艺不精,我测试时是通过 document.cookie 提取 Cookies。这当然会失败,当时愚蠢的我就这么放弃了 Cookies 的方法,而走了上面的歪路。

具体为何失败,以及转机是什么,之后再聊。

3.1. 基本原理

115 的用来记录用户登录状态的 Cookies 是 Session 级别的。也就是说,一旦浏览器被关闭,这些 Cookies 就会被删除。

重点在于删除而不是失效,也就是说说被删除的 Cookies 是有效的。于是我们只需要在成功登陆之后,将 Cookies 保存下来,并在需要共享的浏览器上套用这些 Cookies 就好了。并且 Session 级别的 Cookies 是没有过期时间的,所以理论上只要服务器不做相关验证,我们可以永久维持登录状态。

3.2. 转机

上面提到的转机就是这个 Chrome 插件:EditThisCookie

这个插件主要就是为 Chrome Extension Cookies API 提供了 GUI 界面,从而使开发者可以很方便地通过 Chrome 扩展的能力编辑 Cookies。

稍加尝试就会发现,通过 EditThisCookie 提取的 Cookies,或者说通过 Chrome Extension Cookies API 提取的 Cookies 和 document.cookie 提取的 Cookies 完全不同。

我们以 115 为例:

  • 通过 document.cookie 提取的 Cookies:

    cookies from document.cookie

  • 通过 EditThisCookie 提取的 Cookies:

    Cookies from EditThisCookie

这里实际上保存登录状态的三个 Cookies:UIDCIDSEID 在前者都找不到,反而一些无关紧要的 Cookies 都能获取到。这是因为在一些关键的 Cookies 上,通常会多设置一个 flag 叫 HttpOnly

HttpOnly flag

根据 MDN 的解释,为避免跨域脚本 (XSS) 攻击,通过 JavaScript 的 document.cookie 无法访问带有 HttpOnly 标记的 Cookies,它们只会在 HTTP 请求是被发送给服务端。

因此可以很清楚的看到,在 115.com 域下共有 7 个 Cookies,其中 4 个被设置了 HttpOnly,因此 document.cookie 只能获取到另外 3 个;而 Chrome Extension Cookie API 则可以获取所有 Cookies。

3.3. SyncMyCookie 诞生

虽然使用 EditThisCookie 已经能够轻松的导入和导出 Cookies,实现分享账号。但是每次更新登录状态时都需将 JSON 格式的 Cookies 信息分享给别人,且对于 Session 级别的 Cookies,每次打开浏览器都必须重新导入一次,不够方便。

为了解决上面的问题,我编写了 Chrome 插件 SyncMyCookie

image-20190123231220452

它的工作原理也非常简单,使用 Chrome Extension Cookies API 从浏览器提取指定域名下的所有 Cookies,并将这些 Cookies 经过 AES-128-CBC 加密后保存在 GitHub Gist 中。这里 GitHub Gist 只是充当一个存储作用。

在此基础上,SyncMyCookie 提供了两个自动化功能:

  • Auto Merge:可以在浏览器启动时自动将指定的 Cookies 合并进浏览器,特别适合 Session 级别的 Cookies。
  • Auto Push:在指定的 Cookies 发生变化时,自动推送保存。

4. 总结

使用 SyncMyCookie 共享 115 账号基本做到了我能想象地最好体验:

  • 我在自己的 115 浏览器安装插件并设置自动推送 115 的 Cookies
  • 共享账号的朋友在 115 浏览器安装插件并设置自动合并 115 的 Cookies
  • 每个人都可以满速下载,随意使用任何功能。

SyncMyCookie 也可以随意同步任何在浏览器提供服务,并使用 Cookies 记录登录状态的应用。简单测试了一下 Bilibili、爱奇艺、优酷、腾讯等视频网站都是可以使用的。