java - AES 加密和安全漏洞

标签 java android security aes md5

检查更新#1

此逻辑是身份验证过程的候选者,通过简单的 HTTP 请求完成:

  • 我正在发送:用户名 + 加密用户名(加密用户名实际上是用户名的加密结果,使用 AES 完成,作为 key ,我使用密码的 md5 哈希值)。注意:我不会发送 md5 哈希密码。
  • 在我正在比较的服务器上:加密的用户名与自己的加密用户名(因为在服务器上我可以访问用户的完整信息,所以我计算自己的加密用户名)。

问题:这是一个安全漏洞吗?假设坏人捕获了完整的 HTTP 请求,他可以从这 2 个信息中提取密码吗?

代码详细信息(如果需要):

private static Cipher getCipher(String key, int mode) throws Exception{
     byte[] rawKey = getRawKey(key.getBytes("UTF-8"));
     SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
     Key key2 = skeySpec;
     Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
     cipher.init(mode, key2);
     return cipher;
}

private static byte[] getRawKey(byte[] seed) throws Exception {
/*  BEFORE:
     KeyGenerator kgen = KeyGenerator.getInstance("AES");
     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
     sr.setSeed(seed);
     kgen.init(128, sr); // 192 and 256 bits may not be available
     SecretKey skey = kgen.generateKey();
     byte[] raw = skey.getEncoded();
*/
     byte[] raw = MD5Util.getMD5HashRaw(seed);
     return raw;
}

(注意:我使用密码哈希的原因是代码在平台之间兼容(客户端是Android设备),而注释版本则不兼容)

更新#1

简短回答:

所提出的逻辑甚至不能被视为安全身份验证机制 (为什么?请查看下面迈克尔的回答)

决定使用 Kerberos(而不是 https,因为我不熟悉 + 设置似乎很复杂):

它不是 Kerberos 的真正版本(如 v4 或 v5),它只是我自己的实现,所以我们称其为“与 Kerberos 类似”(我知道,我知道:不要“自行加密”!!! ),

以下是一些详细信息:

  • 它适用于 UDP(现在)
  • 身份验证仅完成一次,方式为:

    • 客户端发送身份 validator 消息(包含:纯文本形式的 [userId] 和带有 [entered_user_password] 的 [something_ecrypted](当前 [something_ecrypted] 仅包含时间戳,将其称为 [authenticator_creation_timestamp]))注意 : 密码未传输
    • 服务器收到消息后,尝试使用 [actual_user_password] 解密 [something_ecrypted] -> 如果成功,则客户端就是它假装的那个人,所以我向他发回一个 OK 响应(如在 Kerberos 中,此响应包含一些内容,就像一个[public_key](一个RSA key ,但用user_password加密)+票证授予票证(称之为[TGT],用只有服务器知道的密码加密,目前它不会过期,这个[TGT]还包含一些东西,比如这 2 个时间戳:[TGT_creation_time_stamp] + [authenticator_creation_timestamp](在身份 validator 消息中收到的时间戳))
    • 收到此 OK 消息后,客户端已获得有效的 [public_key].. 太好了!
  • 针对“回复攻击”的防护并不是 100% 的保证,但我认为它“足够安全”:

    • 在每个下一个 HTTP 请求中,我都会将这两个家伙 [new_request_creation_timestamp](使用上面获取的 [public_key] 加密)+ [TGT](未受影响,如上面收到的那样)附加为 header
    • 在服务器上,我只需要验证 [new_request_creation_timestamp] 和一些数学运算(显然 [TGT] 也需要有效):

      ** 我预计以下变量几乎相等

      delta1 = [TGT_creation_time_stamp] - [authenticator_creation_timestamp]

      delta2 = now()-[new_request_creation_timestamp]

      (实际上我允许它们之间有 5 秒的差异,但根据我的测试,这只是大约 10-20 毫秒的问题,

      ** 因此,初始增量(在为身份 validator 创建 OK 响应时计算)应该在下一次交互中持续存在。

我确实发现这种新方法非常值得信赖,但如果您有意见或发现逻辑上的BUG,请分享..谢谢

最佳答案

是的,这是一个薄弱的安全机制。

  1. 任何捕获发送到服务器的信息的人都可以轻松重放该信息以验证自己的身份(重放攻击)。

  2. 它很容易受到离线密码猜测的影响 - 任何捕获发送到服务器的信息的人都可以非常快速地测试密码列表,以找到您的用户选择的密码(通过使用每个密码的哈希值对观察到的用户名进行加密)依次输入密码)。甚至可以预先计算哈希值,从而进一步加快攻击速度。

基于密码的身份验证协议(protocol)应该能够抵抗重放攻击和离线密码猜测攻击。

简单地使用 HTTPS (TLS) 连接到您的服务器并以明文形式发送用户名和密码通常是更好的解决方案。

响应您的更新 1:

  • 我强烈建议使用 HTTPS。它被广泛使用是有原因的 - 它已经经过了大规模的安全审查,并且被发现(很大程度上)安全 - 比你通过 SO 帖子获得的要好得多。
  • 我没有彻底考虑您的更新方案,但由于它基于 Kerberos,因此也容易受到我上面所述的离线密码猜测攻击。
  • 成功完成身份验证后,不要忘记实际保护您的数据 - 您可能需要派生共享对称 key ,然后对您的数据使用身份验证 + 加密...

关于java - AES 加密和安全漏洞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20325132/

相关文章:

使用 Wildfly 8、Java 1.8.0_45 和 Active Directory 的 Java SSO

java - 安全转换 <?将 Response> 扩展到 <Response>

java - SAX 解析 : how to fetch child nodes

c# - 文本框的 Javascript 注入(inject)攻击预防

perl - 我应该将超长的 UTF-8 字符串转换为最短的正常形式吗?

Javafx Scene.snapshot方法性能低下

java - 从 ArrayList<String> 获取随机项

android - 在Android分页库数据源内部处理Observable

android - 使用定时器/闹钟启动时更新服务

bash - 我的 bash 脚本是否容易受到命令注入(inject)的攻击?