检查RMI上的身份验证方法

时间:2015-10-28 18:20:12

标签: java security authentication cryptography rmi

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

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

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

加密文本变量包含密码和时间戳的组合,使用密码本身作为密钥,使用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的组合,那么这是一次错误的尝试。

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

从我能想到的: -

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

1 个答案:

答案 0 :(得分:1)

我假设AES()并不仅仅意味着分组密码的伪随机排列,而是具有操作模式和填充的分组密码。< / em>的

如果可以区分错误的填充和良好的填充,则可以通过padding oracle attack恢复密码。这很有可能,因为当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可以用于进一步的沟通。

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