【问题标题】:One time password security risk一次性密码安全风险
【发布时间】:2011-10-10 19:45:21
【问题描述】:

我们正在开发一个网络应用程序,用户必须输入一次性密码(我们通过电子邮件发送给用户)才能完成操作。但是,如果恶意用户开发了一个机器人并猜测了我们生成一次性密码的模式,他可以输入一些随机的电子邮件 ID,甚至不看电子邮件就可以确认交易。这样他就可以用错误的确认来攻击系统。有人可以告诉我们人们是如何处理这个问题的吗?

谢谢

【问题讨论】:

  • 不要使用可预测的一次性密码生成器。
  • 不是开玩笑,只是不要以任何形式生成密码。
  • 生成不可预知的一次性密码。

标签: java security web


【解决方案1】:

只使用没有模式的随机密码。优点是如果在邮件中可点击密码,您可以将密码设置得更长,因为用户不必输入密码。

【讨论】:

    【解决方案2】:

    如果您的随机一次性密码与常规密码具有相同的熵,这应该与任何其他密码解决方案一样好。

    这是一个密码生成示例 sn-p,它应该是相当不可预测的:

    import java.security.SecureRandom;
    import java.util.Random;
    
    class Test {
    
        public static String generatePassword() {
            String chars = "abcdefghijklmnopqrstuvwxyz"
                         + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                         + "0123456789!@%$%&^?|~'\"#+="
                         + "\\*/.,:;[]()-_<>";
    
            final int PW_LENGTH = 20;
            Random rnd = new SecureRandom();
            StringBuilder pass = new StringBuilder();
            for (int i = 0; i < PW_LENGTH; i++)
                pass.append(chars.charAt(rnd.nextInt(chars.length())));
            return pass.toString();
        }
    
        public static void main(String[] args) {
            System.out.println(generatePassword());
            System.out.println(generatePassword());
            System.out.println(generatePassword());
        }
    }
    

    输出:

    Qp';Md#93Dxh\0|%%Ny7
    oqvntn2).~W@%P'EM*AS
    WEo2sz2Sm~a'm=Ss&amp;Lu[

    【讨论】:

    • 我完全同意你的看法。但这里的问题是,我们希望用户在我们的站点中输入密码。所以我们可以使用这么大的密码。想象一下,我们只使用 6 个字符长的 [a-zA-Z0-9],你认为它安全吗?如果不完全安全,那么实施“每个 IP 地址不超过 100 个请求”之类的策略是否正确?
    • 6 位字母/数字密码听起来是个坏主意……不过我很难判断。
    • @Gopal 不是用户不必输入的“一次性”密码吗?它要么是复制/粘贴的,要么是嵌入在 URL 中的。由于它只能使用一次,因此在他们单击链接后它可能会出现在日志文件或其他任何内容中都无关紧要。它只工作一次。
    【解决方案3】:

    我从您的问题描述中猜测,您生成的“一次性密码”实际上是某种形式的粗略加密,您可以在其中反转过程以确定他们指的是哪个帐户。

    这是错误的方法,一次性密码需要是随机的,因此无法根据电子邮件地址计算密码。您需要将一次性密码(最好是经过哈希处理的)与帐户信息一起存储在数据库中,并使用该密码进行查找。

    【讨论】:

      【解决方案4】:

      使用高熵源生成密码 - 在 unix 中尝试 /dev/urandom - 这将有效地为您提供一次性密码。

      【讨论】:

        【解决方案5】:

        不要这样做。向他们发送一个 URL 链接,其中包含一个巨大的密码(安全票证)作为 URL 参数,并安排您的结束,以便如果该参数存在且正确(i)他们已登录并且(ii ) UUID 的有效性立即或在发送后的一两天内终止。根据您的容器,可能需要做一些事情,但它更安全。我为此使用 java.util.UUID,既好又长。

        【讨论】:

        • EJP,感谢您的回复。实际上,我们也有计划向用户发送 OTP 短信。如果我们生成一个巨大的密钥,它会激怒用户。此外,还有几家银行会生成 OTP 作为交易密码。他们对此有何信心?最后他们是金融机构,他们需要更多地担心这个吗?你能解释一下吗?
        • @Gopal 如果您在链接中生成一个巨大的密钥, 而他们所要做的就是单击它,这究竟会如何“激怒用户”? 没有输入。我不知道银行怎么可能对长度不足的 OTP 充满信心。我不是。
        • 如果我不清楚,请原谅。我的意思是我们尝试向用户的手机发送带有 OTP 的短信。
        • @Gopal 但在你的问题中你说它是通过电子邮件发送的,而不是短信。电子邮件效果更好,因为您可以拥有一个包含密码的链接,他们只需点击即可,无需输入。
        【解决方案6】:

        您是对的,您的方案中有一个很大的安全漏洞,但您发现了错误的漏洞!

        您的问题是您通过电子邮件将其发送出去 - 电子邮件不安全。

        至于猜测应该是统计上不可能的问题,只要你使用足够长的密码。您可能希望在人们猜错 100 次后将其锁定。

        我见过的一个技巧是向用户询问 Paypal 或银行帐号。然后,您为随机金额存入一些存款。所以他们看到的存款是 34 美分、91 美分和 82 美分。然后他们使用这些数字作为密码!很聪明吧?

        【讨论】:

          【解决方案7】:

          实现一个在计算上无法猜测的一次性密码。

          例如,使用一个随机字符串生成器来生成一个长度为 15 个字符的字符串,其中使用了一个大写字母、小写字母和数字池。

          这会产生 62^15 种可能的组合,这对于暴力破解程序来说是极其困难的。

          【讨论】:

            【解决方案8】:

            使用 6 位随机数作为 OTP 不会带来安全风险只要您在第一次使用后使 OTP 失效。在一次尝试中猜出一个 6 位数字几乎是不可能的。而且由于您只能尝试一次,因此也无需担心蛮力。只要确保你生成一个真正的随机数,例如使用 SecureRandom。

            所以,要采取的步骤:

            1. 列表项
            2. 生成 6 位随机数 OTP
            3. 将其与帐户相关联(例如,用户输入电子邮件和 OTP)
            4. 在给定用户电子邮件的每次身份验证尝试中,使 OTP 无效,无论登录是否成功

            使用 Java,您可以使用以下方法生成 OTP:

            public static final String getOTP(int length) {
            
                Random r = new SecureRandom();
                return String.valueOf(r.nextInt((int)Math.pow(10, length)));
            }
            

            希望这是有道理的。

            【讨论】:

              猜你喜欢
              • 2011-08-27
              • 2013-03-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-06-25
              • 1970-01-01
              • 1970-01-01
              • 2011-09-14
              相关资源
              最近更新 更多