1

私はこのコードを使用してパスワードを暗号化および復号化します

public class SecureDigester
{
    private static final char digits[] =
           { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
                 'F' };

           private static String byteArrayToHexString(byte[] b)
           {
              StringBuffer hexString = new StringBuffer(b.length);
              for (int i = 0; i < b.length; i++)
              {
                 hexString.append(digits[(b[i] & 0xF0) >> 4]);
                 hexString.append(digits[b[i] & 0x0F]);
              }
              return hexString.toString();
           }

           public static String digest(String plaintext)
           {
              try
              {
                 MessageDigest md = MessageDigest.getInstance("SHA");
                 md.update(plaintext.getBytes("UTF-8"));
                 byte[] mdBytes = md.digest();
                 String hashString = byteArrayToHexString(mdBytes);
                 return hashString;
              } catch (Exception e)
              {
                 throw new RuntimeException(e);
              }
           }

}

私のログインでは、このコードを使用してパスワードを復号化しています。

        String passwordDigest = SecureDigester.digest(password);
        if (!user.getPassword().equals(passwordDigest))
        {
            // authentication failed: bad password
        }

これで、ユーザーのユーザー名とパスワードを指定した電子メールに送信するforgot-password.jspページができました。しかし、以下のコードを使用すると、データベース内の暗号化されたパスワードとは異なる暗号化されたパスワードを受け取りました。

String Email = req.getParameter("email");
User userItem = new UserDAO().findEmail(Email);
SendMailSSL sendEmail = new SendMailSSL();
String password = userItem.getPassword();
String EPassword = SecureDigester.digest(password);
sendEmail.send(userItem.getUsername(), EPassword, userItem.getEmail());

これを解決する方法は?

4

2 に答える 2

4

SHAやMD5のような暗号化ハッシュは一方向ハッシュです。一方向ハッシュを逆にすることはできません。任意の平文から暗号化ハッシュを生成できますが、ハッシュ値のみを指定して元の平文を判別することはできません。

「復号化」コードは、実際にはSHAハッシュを復号化しません。むしろ、ユーザーが入力したばかりのパスワードをハッシュし、そのハッシュを以前に保存したハッシュと比較します。ハッシュが一致する場合、それはパスワードが一致することを意味します。

このようにパスワードをハッシュすることは優れたセキュリティスキームですが、その結果の1つは、ユーザーにパスワードを電子メールで送信できないことです。つまり、パスワードがありません。不可逆的なハッシュがあります。これが、最近のセキュリティの良いWebサイトが、パスワードを忘れた場合に元のパスワードを電子メールで送信しない理由です。代わりに、パスワードをリセットする方法を提供します。パスワードを電子メールで送信できるサイトに出くわした場合、それは大きな危険信号です。

于 2013-01-29T15:49:12.927 に答える
1

SHA1ハッシュとしてパスワードをデータベースに保存しているようです。これは素晴らしいことであり、これを行う必要があります(間違いなくベストプラクティス)。SHA1(またはその他の一方向ハッシュ)を使用することの「欠点」は、ハッシュを元の平文に「復号化」できないことです。これは、次のコードが機能しないことを意味します。

String Email = req.getParameter("email");
User userItem = new UserDAO().findEmail(Email);
SendMailSSL sendEmail = new SendMailSSL();
String password = userItem.getPassword(); // the userItem returns an SHA1 hash
String EPassword = SecureDigester.digest(password); // this just rehashes the hash
sendEmail.send(userItem.getUsername(), EPassword, userItem.getEmail());

このコードの問題は、アプローチの場合ほどではありません。SHA1ハッシュからユーザーのプレーンテキストパスワードを復元する方法がないため(これは良いことです)、パスワードを含む電子メールではなく、パスワードをリセットするためのリンクをユーザーに送信する必要があります。電子メールは安全でないチャネルであり、パスワード(変更する必要のある最初のパスワードを除く)を電子メールで送信しないでください。

この問題には2つのアプローチがあります。

  • ランダムなジブリッシュからユーザーの新しいパスワードを生成し、SHA1でハッシュします。この値をデータベースに保存します。新しいランダムパスワードをユーザーに送信し、次回のログイン時にユーザーにパスワードの変更を強制します。
  • ユーザーがパスワードをリセットするために使用できるリンクを生成します。リンクは推測が難しく、一定の時間が経過すると(つまり、ユーザーに電子メールを送信してから5〜10分以内に)期限切れになる必要があります。これにより、攻撃者が「リセットウィンドウ」を悪用することが非常に困難になります。リセットリンクは毎回ランダムであり、可能であればユーザーに関する識別情報を含まないようにする必要があります。
于 2013-01-29T15:50:09.240 に答える