注册过程
与API之间的通讯请使用tls,尽可能在客户端中包含tls公钥。 注册步骤:
- 用户输入邮箱、密码。再次输入密码来确认密码。如果不同,无法进行下一步。
- 客户端和服务端将邮箱长度限制在190个字符。
- 密码必须长于8,并且评分大于等于1(使用
ZXCVBN password strength estimator library v4.4.2
评分) - 直到输入8位密码才启用密码评分。否则显示“密码太短”。这是为了防止像
€cc
这样的密码:评分为1,但是太短。
||
:拼接 ⊕
:排他性或位操作
用户UI显示细则:
规则 | 描述 |
---|---|
Length < 8 | Too short |
Score 0 and Length >= 8 | Too weak |
Score 1 and Length >= 8 | Weak |
Score 2 and Length >= 8 | Medium |
Score 3 and Length >= 8 | Good |
Score 4 and Length >= 8 | Strong |
在密码处理(Password Processing Function)中,我们使用PBKDF2标准。 尽管不是最新的,但这有广泛的支持与较快的速度。
客户端使用
CSPRNG
生成一个128bits(16字节)的随机主密钥(Master Key)。 例如:网页端可以使用WebCrypto的接口Crypto.getRandomValues()
。除此之外,客户端还要生成一个128bits的客户端随机值(Client Random Value)
生成盐
Salt = SHA-256( “mega.nz” || “Padding” || Client Random Value )
。mega.nz
、Padding
加起来长度为200。 Mega重复使用P
使长度为200,这有助于使所有的盐计算花费相同的计算时间,以减少计时攻击。 研究报告Method to Protect Passwords in Databases for Web Applications
推荐将用户ID(例如邮箱地址)包含在盐计算中。但是Mega允许用户修改邮箱 (这会导致用户修改邮箱时需要重新计算与加密)。 此外,服务台需要能够根据用户的要求更改电子邮件,但如果盐的计算和密码处理方法是基于一个已经被覆盖的旧电子邮件,这将锁定用户的账户。这不利于可用性。对于密码处理方法,迭代次数被设定为
100000
次。 这个迭代次数是为了在中低端移动设备上获得合理的性能,因为MEGA有iOS、Android、Windows Phone应用程序和web客户端。派生密钥(derived key)的长度将被设置为256比特(32字节)。
Derived Key = PBKDF2-HMAC-SHA-512( Password , Salt , Iterations , Length )
。派生密钥的左半部分128bits被称为派生加密密钥(Derived Encryption Key),它将用来加密主密钥(Master Key)
Encrypted Master Key = AES-ECB( Derived Encryption Key , Master Key )
。派生密钥的右半部分128bits被称为派生认证密钥(Derived Authentication Key),它被用于在更多的敏感数据(如加密密钥、会话ID等)被发送之前,与API一起用来验证用户的登录。
客户端计算出哈希认证密钥。
Hashed Authentication Key = SHA-256( Derived Authentication Key )
。哈希认证密钥仅包含SHA-256输出的前128bits(16字节),来减少API使用的储存空间。客户端注册将向服务器端发送:姓、名、邮箱、客户端随机值
Client Random Value (128 bits / 16 Bytes)
、加密的主密钥Encrypted Master Key (128 bits / 16 Bytes)
、哈希认证密钥Hashed Authentication Key (128 bits / 16 Bytes)
。服务器会按原样存储所有这些信息。请注意,盐不会被发送到API,因为这总是从客户端的随机值中计算出来的,原因将在后面解释。服务器端将使用
CSPRNG
生成一个随机token(128bits)用于确认邮箱。Confirm Link = “https://mega.nz/#confirm” || Base64UrlEncode( “ConfirmCodeV2” || Email Confirmation Token || Email )
在点击电子邮件中的确认链接后,客户端将把
#confirm
标识符后的Base64 URL编码数据发送至服务器端,服务器端可以对其进行解码。如果该API请求成功,客户端将被带到登录页面,再次登录,其中的电子邮件字段可以预先填充,但需要手动输入密码。如果用户在其他浏览器中打开链接,则需要再次登录。在用户第一次登录后,直接进入密钥生成步骤,生成了以下密钥: 一对RSA密钥,2048比特(用于共享文件夹/文件)。 一个Ed25519密钥对,256比特(作为信任根用于用户指纹验证和其他密钥的签署。这对密钥被称为签名密钥)。 一对256位的Curve25519密钥(用于MEGAchat)。
私人密钥由主密钥使用AES-ECB加密并由API存储。MEGA无法通过任何方式获得明文私钥
登录过程
用户输入邮箱和密码到本地客户端界面。邮箱被发送到服务器端。
如果邮箱属于有效的用户账户,服务器端将发送回盐
SHA-256( “mega.nz” || “Padding” || Client Random Value )
。mega.nz
、Padding
加起来长度为200。如果数据库中不存在该邮箱,服务器端将返回盐
SHA-256( Email || “mega.nz” || “Padding” || Server Random Value )
。mega.nz
、Padding
加起来长度为200。Server Random Value (128 bits)
由CSPRNG随机生成,并静态储存在服务器给所有邮箱不存在数据库的请求使用。 这可以防止垃圾邮件发送者的电子邮件枚举,以找到有效的电子邮件,并且每年都会改变。由于盐是通过使用哈希函数计算有效登录和无效登录,这可以防止定时攻击。 还有一个由API为这个响应引入的随机延迟,在0到50毫秒之间。50毫秒是在所有数据库记录中搜索而找不到结果的最长时间。这有助于通过测量数据库响应的延迟,不向攻击者透露电子邮件是否有效。 从用户那里收到的电子邮件必须是一个有效的电子邮件,并且最大190个字符,否则请求被拒绝。这也防止了API对大量数据进行哈希运算,并防止DOS攻击。这个请求也有速率限制。客户端计算派生密钥(Derived Key)
Derived Key = PBKDF2-HMAC-SHA-512( Password , Salt , Iterations , Length )
Derived Encryption Key
是Derived Key
前半部分,128比特.Authentication Key
是Derived Key
的右半部分,128比特。客户端向API发送:邮箱、认真密钥(Authentication Key)。
服务器端计算哈希认证密钥:
Hashed Authentication Key = SHA-256( Authentication Key )
服务器端将哈希认证密钥的前128位与存储在数据库中的用户的认证密钥进行核对。如果匹配,用户被认为是登录成功,因此服务器端发送回他们的加密的主密钥(Encrypted Master Key)、加密的私人RSA密钥(Encrypted Private RSA Key)、加密的会话ID(Encrypted Session ID)等,客户端可以正常进行。 服务器端不存储用户发送的未哈希的认证密钥(Authentication Key)。它只存储哈希认证密钥(Hashed Authentication Key),以防止 “传递哈希值(pass-the-hash)“的攻击(在数据库泄露的情况下,攻击者只需传递哈希认证密钥(Hashed Authentication Key)就能获得认证,并像真正的用户进行操作)。服务器总是对从客户处收到的认证密钥(Authentication Key)进行哈希处理,以防止这种攻击手段。 如果哈希认证密钥与数据库中的结果不匹配,服务器端返回登录失败。服务器端通过使用双HMAC验证,避免了这里的定时攻击。当登录正确时,服务器将回应加密的主密钥、加密的RSA私钥和加密的会话标识符(Encrypted Session Identifier)。
客户端将使用派生加密密钥(Derived Encryption Key)对加密的主密钥进行解密。然后,主密钥将被用于解密RSA私钥。然后,RSA私钥将被用来解密会话标识符。会话标识符是由API在每个登录会话中生成的随机字符串(token),它被加密到用户的RSA公钥。 在所有后续的API请求中,用户必须通过TLS连接向API发送其未加密的会话标识符。如果用户没有发送正确的会话标识符或没有正确解密,他们将无法下载任何用户账户数据,如联系信息、加密文件和文件属性。