2021年のShiroを知りませんか?-4。パスワードの暗号化にMD5 +ソルト+ハッシュを使用します

I.はじめに

前回の記事では、カスタムレルムを使用してデータを取得する方法を紹介しましたが、データの取得は実際のデータベースやnosqlからではなく、メソッドをラップし、このメソッドからデータベース内のデータを取得するふりをします。ユーザー情報、次にSimpleAccountを返しました。このオブジェクトには、ユーザー名とパスワードが含まれています。当時、パスワードはプレーンテキストで返されていました。これは明らかに安全ではありません。データソースが危険にさらされると、すべてのユーザー情報が漏洩します。そこで、ここでは、一般的に使用されるパスワード暗号化戦略を紹介します。

2.一般的に使用される暗号化戦略

日々の開発でさまざまな暗号化アルゴリズムを使用した可能性がありますが、これらのアルゴリズムの利点とその特徴は何ですか?これは、一般的に使用されるいくつかの暗号化アルゴリズムの簡単な紹介です。

1.MD5

  1. MD5とはMD5
    は、SM2などの一般的に使用されるアルゴリズムとは大きく異なります。通常、使用する暗号化アルゴリズムは、対称および非対称アルゴリズムに基づく暗号化方法などの暗号文を解読できますが、MD5は機能しません。MD5典型的な機能は、は不可逆的です。つまり、暗号化した情報を逆に復号化することはできなくなります。インターネット上にはMD5オンライン復号化Webサイトがたくさんあると言う人もいるかもしれません。これらは、実際には復号化されたMD5暗号化シークレットではないことに注意してください。暗号文を1つずつ照合してクラッキングを実現する徹底的な方法。このブルートフォースクラッキングは実際には非常に簡単に回避できますが、これにはMD5の別の機能が含まれます。つまり、固定プレーンテキストが複数回暗号化されます。結果はすべて同じです。生成されるMD5アルゴリズムは、常に16進数の32ビット(256ビット)文字列です。
  2. MD5の適用シナリオ
    ①ログイン時のパスワード暗号化などの暗号化シナリオに適用します。
    ②署名に適用され、2つのファイルが同じファイルであるかどうかを判断します。MD5で暗号化された同じファイルの暗号文は同じである必要があります。これにより、ファイルが改ざんされるのを防ぐことができます。

2.AES

  1. AESとはAES
    は一般的に使用される暗号化アルゴリズムです。これは対称暗号化アルゴリズムです。対称暗号化アルゴリズムとは何ですか?暗号化と復号化の両方に同じ秘密鍵が必要です。一般的に使用されるAESAES128、AES192、およびAES256です。これらは何ですか。これらの3つのAESは、実際には異なるキー長を参照します.3つのAESに対応するキー長は、それぞれ128ビット、192ビット、および256ビットで、バイト単位で16、24、および32です。たとえば、次のような秘密鍵:String str = "1234567812345678"の場合、この秘密鍵を使用するAESは当然、AES128が使用されます。

  2. AESの使用シナリオ
    実際のプロジェクトでは、AES暗号化は通常、フロントエンドとバックエンドのデータのやり取りに使用されるため、機密情報の漏洩を回避できます。ただし、通常、AES暗号化は単なる暗号化ではありません。 AES。暗号化テキストは相互作用の前にBase64暗号化されます。これにより、情報送信のセキュリティが確保されますが、100%のセキュリティはありません。暗号化テキストが解決できる限り、クラッキングのリスクがあり、リスクはすべてそれです。は相対的であり、私たちにできることは比較的安全であることだけです。

3. MD5 + salt + hashを使用してログインを実現します

MD5暗号化では、ブルートフォース方式を使用してブルートフォースクラッキングを実現できるため、ユーザーはパスワードを設定するときに単純なパスワードを使用できません。単純なパスワードは簡単に使い果たされますが、ユーザーは使用時にそのような認識がありません。そのため、ユーザーのパスワードに「塩」を追加して、パスワードをより塩辛くして、パスワードが簡単に解読されないようにする必要があります。いわゆるソルトは、実際には、パスワード用にランダムに生成された文字列の文字列をスプライスすることです。さらに、MD5 + saltによって生成された16進値をハッシュすることもできます。これにより、パスワードがより安全になります。データベースが侵害されても、saltとパスワードが取得され、ハッシュの数は検出されません。もちろん、このような状況に遭遇することはめったにありません。

1.ShiroのMD5を使用してデータを暗号化する方法

したがって、Shiroが提供するMD5の使用方法は、次のコードを見るとわかります。

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Md5Hash md5Hash = new Md5Hash("123");
        System.out.println(md5Hash.toHex());
        Md5Hash md5Hash1 = new Md5Hash("123","12345&8");
        System.out.println(md5Hash1.toHex());
        Md5Hash md5Hash2 = new Md5Hash("123","12345&8",1024);
        System.out.println(md5Hash2.toHex());

    }
}

上記のプログラムの出力は次のとおりです。

202cb962ac59075b964b07152d234b70
19d11f5191d12b1c224a7d535e1cb650
cc24303e7e1827dbb9742d1f4efeb0ec

Process finished with exit code 0

上記の例によると、鮮明に見ることができます。最初の例は暗号化にMD5のみを使用するデータであり、2番目の部分は「salt」が追加されたMD5暗号化であり、3番目の部分は最初の部分にあります。値はハッシュされます。実際、このアイデアによれば、ソルトのハッシュ、ソルトのMD5暗号化、ソルトのBase64またはAESの使用など、さまざまな方法でパスワードを暗号化できます。はい、多くの暗号化を組み合わせることができますが、実際には不要であり、絶対的なセキュリティはありませんが、通常はMD5 +「ソルト」+ハッシュを使用します。

2. MD5 + salt + hashを使用してログインを実現します

Shiroが実装したログインシナリオでこの暗号化方式を使用する方法を見てみましょう。前の記事で述べたように、パスワード検証の場所にパスワードマッチャーがあります。デフォルトのパスワードマッチャーは比較と同じです。直接比較にequalsを使用したくない場合は、このパスワードマッチャーを置き換える必要があります。では、このパスワードマッチャーをどのように置き換えるのでしょうか。

1.パスワードマッチャーはどこにありますか

次の図に示すように、パスワードの検証はここで行われることはすでに述べました。

ここに画像の説明を挿入
このメソッドの最初の行はパスワードマッチャーです。パスワードマッチャーはこのクラスの属性であるため、パスワードマッチャーを変更する場合は、この属性に必要なパスワードマッチャーを設定して置換を実現できます。

2.マッチングマッチャーを変更する場所

パスワードマッチャーがどこにあるかはすでにわかっているので、このパスワードマッチャーが属するクラスでそれを置き換えますか?もちろん、それは私たちによって書かれたものではありません。実際の置き換え場所は、私たちが書いたカスタムレルムで行う必要があります。 、通常、セキュリティマネージャのレルムを設定します。レルムを設定する前に、パスワードマッチャーを変更する必要があります。また、使用する暗号化アルゴリズムをレルムに通知する必要があります。次に、対応するコードは次のようになります

public class TestAuthenticator2 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        //定义安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //定义一个支持MD5+盐+hash散列的密码匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //告诉密码匹配器密文是哪种加密方式
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //告诉密码匹配器,密码被散列的次数,这个一般定义为1024的倍数,默认一次
        hashedCredentialsMatcher.setHashIterations(1024);
        //定义自己的realm
        SecondRealm secondRealm = new SecondRealm();
        //为realm设置密码匹配器
        secondRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        //为安全管理器设置realm
        defaultSecurityManager.setRealm(secondRealm);
        //模拟用户登录场景
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhaoyun","123");
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        try {
    
    
            Subject subject = SecurityUtils.getSubject();
            subject.login(usernamePasswordToken);
            System.out.println("登录成功");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

データベースにMD5 + salt + hashによって実装された暗号文が格納されていることをセキュリティ管理者に伝えたので、レルムは以前と同じように誤って記述されます。

3.カスタムレルム

パスワードを暗号化しない場合、シミュレートしたレルムはユーザー名とパスワードをプレーンテキストで取得してパスワードマッチャーに返します。次に、MD5 + salt + hashを使用してパスワード暗号化を実装します。前の情報は肯定的なWillを返します。エラーを報告し、それをどのように書くか、次のコードを参照してください

public class SecondRealm extends AuthorizingRealm {
    
    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken;
        String userName = usernamePasswordToken.getUsername();
        //获取数据库中的用户信息
//        SimpleAccount simpleAccount = new SimpleAccount("zhaoyun","202cb962ac59075b964b07152d234b70","df",this.getName());
        SimpleAuthenticationInfo simpleAuthenticationInfo = getSimpleInfo();
        //验证用户名与token用户名是否相同
        if(simpleAuthenticationInfo.getPrincipals().asList().contains(userName)){
    
    
            return simpleAuthenticationInfo;
        }else{
    
    
            return  null;
        }
    }

    private SimpleAuthenticationInfo getSimpleInfo(){
    
    
        Md5Hash md5Hash = new Md5Hash("123");
        Md5Hash md5Hash1 = new Md5Hash("123","12345&8");
        Md5Hash md5Hash2 = new Md5Hash("123","12345&8",1024);

        return new SimpleAuthenticationInfo("zhaoyun",md5Hash2, ByteSource.Util.bytes("12345&8"),this.getName());
    }
}

前の例では、AuthenticatingRealmを継承するカスタムレルムを実装しました。この例では、AuthorizingRealmを継承しています。これら2つのレルムの1つは認証用で、もう1つは承認(最初の認証)用です。承認に使用されるAuthorizingRealmはAhthenticatingRealmのサブクラスであるため、AuthorizingRealmを直接継承できるのは正しいことです。上記のコードと同様に、このクラスを継承するには、認証と承認のために2つのコードを書き直す必要があります。承認のこの部分はまだ関与していません。今のところそれについては話さないでください。認証の部分については引き続き見ていきます。
このメソッドSimpleAuthenticationInfo()によると、3つのMd5Hashオブジェクトが書き込まれていることがわかります。最初のオブジェクトはMd5のみを使用し、2番目はランダムソルトを使用し、ランダムソルトはランダムな文字列のセットです。 MD5 + salt + hashingによって1024回生成された暗号文が使用されます。
注意深い学生は、レルムのパスワードマッチャーを設定したときに、ランダムソルトが何であるかを連に伝えず、パスワードマッチャーの暗号文のみを伝えたことがわかります。暗号化方法とハッシュする必要がある回数。

4.パスワードマッチャーは、ランダムソルトが何であるかをどのように知るのですか?

実際には非常に簡単です。ユーザー名の確認が完了すると、SimpleAuthenticatingInfoクラスのオブジェクトであるアカウント情報が返されます。このオブジェクトにはパスワードが含まれており、ソルトされています。パスワードマッチャーに到達すると、次のようになります。ソルトの値は、ユーザーがログインするときにソルトを直接運ぶ必要なしに動的に取得されます。さらに、ユーザーがソルトを使用してログインすることは非常に安全ではないため、パスワードマッチャーのソルトを設定する必要はありません。

5. MD5 + salt + hashを使用して正常にログインします

上記のコードを実行すると、次のような結果が得られます。

登录成功

Process finished with exit code 0

興味のある大物はもっと試すことができます、ここに他のパスワード使用シナリオのリストはありません。

4.まとめ

この記事では、主にShiroでログインするときのMD5のアプリケーションシナリオを紹介します。MD5+ salt + hashを使用して、パスワードのセキュリティを大幅に確保します。実際、日常の開発では、パスワードも追加されます。この種の、私がしばらく前に行っていたプロジェクトのように、フロントエンドとバックエンドの相互作用は、パラメーターを暗号化するときに二重暗号化にAES + Base64を使用します。

おすすめ

転載: blog.csdn.net/m0_46897923/article/details/114906453