我正在做一个项目,其中,要访问服务,客户端需要通过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的组合,那么这是一次错误的尝试。
我知道这不可扩展,因为每次请求服务时,都必须提取记录,但这是否安全?
从我能想到的: -
答案 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
可以用于进一步的沟通。
攻击者唯一能做的就是阻止您通过操纵传输的请求来验证服务器,以便在服务器上产生失败的身份验证。