为伯恩云盘启用双因素身份验证(2FA)

背景


美国五星上将麦克·阿瑟曾经说过,伯恩云盘不能没有2FA,就像西方不能没有耶路撒冷

在数字化的世界中,数据泄露和网络攻击已经成为了常态,因此我们需要采取主动措施来保护我们的数据和隐私,而不是被动预防

所以,为伯恩云盘启用双因素身份验证(2FA 两步验证)刻不容缓,就像为马伯恩的小站启用HTTPS协议一样。

关键词

伯恩云盘的2FA

Why 2FA?

随着网络攻击的兴起,传统密码不再像以前那样安全。

数据的泄露也越来越常见,大量的用户名和密码被泄露,这得益于许多人在不同的服务上使用相同的账号和密码,当然我之前也是

虽然我可以通过KeePass的password generator来生成复杂到无法破解的密码,但是KeePass的证书文件是存储在伯恩云盘上的,如果伯恩云盘了,那我所有的账号密码可不都得


于是,2FA应运而生。

2FA,全称Two Factor Authentication,中文名叫双重因素认证

字面意来理解,双重因素认证,即认证需要用到两种因素。比如,你在银行 ATM 取钱的时候既要你的银行卡,也需要只有你才知道的六位数密码,这便是双重因素认证。

我们常见的手机验证码它也是属于2FA的一种方式,当我们在进行敏感操作时(修改密码),首先需要知道我们的用户名,然后需要下发一条手机验证码到我们的手机上,目的是为了验证我们对手机的所有权,这也是属于双重因素认证的一种方式。

中国大陆由于实名制的关系,几乎所有网站注册都需要使用手机号,而国内用户也没有使用手机令牌的习惯,因此,国内最常见的 2FA 就是手机短信验证码。

但国外的服务就不一样了,比如谷歌或者微软的服务,我们可以选择使用Authenticator手机令牌,它使用到的技术叫做 TOTP(Time-based One-time Password,中文名:基于时间的一次性口令),简单来说就是,当我们将账户和验证软件绑定之后,在一定时间内,验证软件会生成一串数字(一般是六位数),只要将这串数字输入到目标网站,即可完成认证。

庆幸的是,伯恩云盘恰巧就支持TOTP认证,所以我们可以白嫖一下微软的authenticator。(当然,谷歌的authenticator也是可以白嫖的)。

如何在伯恩云盘(nextcloud)中启用2FA?

  • 点击个人头像,找到设置——应用:

  • 找到 Two-Factor TOTP Provider,并选择启用:

  • 在nextcloud端启用TOTP

  • 找到TOTP的应用提供者,例如谷歌或者微软,进行扫码登记:(以Microsoft authenticator为例)

  • 验证账户:

大功告成,你以为这种就完了?

是的,用户的操作部分已经完了,优秀的产品总是可以通过简单便捷的操作完成复杂的功能。

TOTP的原理

为什么authenticator这个应用生产的一次性代码能和我们的服务器上的相关联呢?

刚好我有一个测试网站:2FA % TOTP测试

我将二维码的信息公开到红框内,可以看到这个二维码其实是用来做auth验证的,包含了secret和issuer的信息。

js
otpauth://totp/Passcode?secret=6shyg3uens2sh5slhey3dmh47skvgq5y&issuer=xiaomaTest

启用2FA的过程

当我们想要启用2FA的时候,首先我们需要扫描服务器提供的二维码,也就是上图的二维码,服务器会给我们颁发一个secret,通过和当前时间的计算(HMAC-SHA1算法),得出6位验证数字:

核心代码如下:

js
    function updateCode() {
      const T = Math.floor(Date.now() / 1000 / 30)
      // 用户密钥
      const K = arrayToBinary(Array.from(new Uint8Array(base32Decode('6shyg3uens2sh5slhey3dmh47skvgq5y'.toUpperCase(), 'RFC4648'))))

      /**
      * 数字转 Int64 字节流
      * @param {number} num 
      * @returns 
      */
      function intToBytes(num) {
        const bytes = [];

        for (let i = 7; i >= 0; i--) {
          bytes[i] = num & 255;
          num = num >> 8;
        }

        return bytes;
      }

      /**
       * @param {string} binaryStr
       */
      function binaryToArray(binaryStr) {
        return binaryStr.split('').map(char => char.charCodeAt())
      }

      function arrayToBinary(array) {
        return array.map(char => String.fromCodePoint(char)).join('')
      }

      function arrayToHex(array) {
        return array.map(char => char.toString(16)).join('')
      }

      const T1 = arrayToBinary(intToBytes(T))
      
      // 计算 HMAC-SHA1,密钥为 K,消息为 T
      const HS = binaryToArray(CryptoJS.HmacSHA1(CryptoJS.enc.Latin1.parse(T1), CryptoJS.enc.Latin1.parse(K)).toString(CryptoJS.enc.Latin1))

      // 取出最后个字节的第 4 位
      const offset = HS[19] & 0xf

      // 将从 offset 开始的四个字节按大端组装为整数
      let bytes = (HS[offset] & 0x7f /** 这里是为了忽略符号位 */) << 24
        | HS[offset + 1] << 16
        | HS[offset + 2] << 8
        | HS[offset + 3]

      // 整数转字符串,然后取出后六位
      let code = bytes.toString().slice(-6);

      // 不足 6 位数则补 0
      for (let i = 0; i > 6 - code.length; i++) {
        code = '0' + code;
      }

      code.split('').forEach((c, i) => {
        $("#code-box").children()[i].innerHTML = c
      })
    }

我们手机验证器的secret和服务器的secret是一致的,只要保证它们的时间一致,就可以生成有时效性且相同的6位验证码。

这样即使我们的密码泄漏了,也不用担心数据被泄露,因为二次验证可以有效的保护我们的数据。

结束语

有的没的。

如何为Android应用抓取HTTPS网络包
China WoW