审查RMI上的身份验证方法



我正在做一个项目,其中,要访问服务,客户端需要通过RMI对自己进行身份验证(客户端有用户名和密码)。我希望在不使用SSL的情况下实现这一点(因此,修改和嗅探是主要威胁)。

这是客户端每次访问服务时发送的"令牌"。

class Token {
    String username;
    byte[] encryptedText;
}

Encrypted Text变量包含密码和时间戳的组合,使用AES-256 CBC将密码本身作为密钥进行加密。例如:

encryptedText[0] = AES(20) //encrypt length of password 
encryptedText[1] = AES(30) //encrypt length of TimeStamp
encryptedText[2-21] = AES(password) //encrypted password
encryptedText[22-51] = AES(timestamp) //encrypted timestamp

服务器在接收到此令牌时检索用户名的密码,并尝试用密码作为密钥解密加密文本。如果结果不是密码和最近的TimeStamp的组合,则是错误的尝试。

我知道这是不可扩展的,因为每次请求服务时,都必须提取一条记录,但这安全吗?

根据我的想法:-

  • 阻止嗅探(加密)
  • 防止修改攻击(不会导致正确的身份验证)
  • 防止重放攻击(非最近的时间戳是身份验证失败)

我假设AES()不仅仅是指分组密码的伪随机排列,而是指具有操作模式和填充的分组密码

如果可以区分坏的填充和好的填充,那么就可以通过填充预言机攻击来恢复密码。这是非常可能的,因为当出现BadPaddingException时,响应可能会提前完成,并且无法进行进一步的计算。

主要的两个问题是你是

  • 未验证密文本身,以及
  • 用于加密明文的密码包含在明文中(可以恢复)

这种伪加密代码更好:

// salt and masterHash can be cached for multiple requests
salt = SecureRandom().nextBytes(8 bytes)
// adjust iterations (65336) according to appropriate performance:
masterHash = pbkdf2(password, salt, 65336)
iv = SecureRandom().nextBytes(16 bytes)
sessionKey = SecureRandom().nextBytes(16 bytes)
encKey = hmacSha256(masterHash, "enc") // crop according to intended AES key size
macKey = hmacSha256(masterHash, "mac")
ciphertext = AES(encKey, iv, sessionKey + ts.length + ts)
tag = hmacSha256(macKey, username + salt + iv + ciphertext)
return salt + iv + ciphertext + tag

这里+表示级联,AES表示在具有PKCS#7填充的CBC模式中的AES。

接收机必须首先导出macKey,然后计算tag,然后检查发送的tag是否与计算的tag匹配。如果是,则解密密文。如果这起作用,那么sessionKey可以用于进一步的通信。

攻击者唯一能做的就是通过操纵传输的请求来阻止您对服务器进行身份验证,从而在服务器上产生失败的身份验证。

相关内容

最新更新