Javaでパスワードを操作するために文字列にchar[]配列を使用する
1概要
この記事では、Javaで
String
の代わりに
char[]
配列を使用してパスワードを表現する理由について説明します。
このチュートリアルでは、パスワードを実際に保存する方法ではなく、メモリ内でパスワードを操作する方法に焦点を当てていることに注意してください。
-
パスワードの形式を制御することはできません(例:
パスワードは、
String
)の形式でサードパーティAPIから取得されます。
パスワードを操作するために
java.lang.String
型のオブジェクトを使用することは明らかに思われますが、代わりに
char[]
を使用することがJavaチーム自身によって推奨されています。 **
たとえば、
javax.swing
のhttps://docs.oracle.com/javase/8/docs/api/javax/swing/JPasswordField.html[
JPasswordField
]を見ると、メソッド
getText
String
を返す()
はJava 2以降廃止され、
char[]
を返す
getPassword()
メソッドに置き換えられました。
それでは、その理由がいくつかある大きな理由を探りましょう。
2文字列は不変です
Javaの
__String
は不変なので、高レベルのAPIを使用して変更することはできません。
String
オブジェクトを変更すると、新しい
String__が生成され、古いオブジェクトがメモリに保持されます。
したがって、
String
に格納されているパスワードは、ガベージコレクタがそれをクリアするまでメモリ内で使用可能になります。いつ発生するかを制御することはできませんが、
Strings
は再利用のために文字列プールに保持されるため、この期間は通常のオブジェクトよりもかなり長くなる可能性があります。
その結果、メモリダンプにアクセスできる人はだれでもメモリからパスワードを取得できます。
-
String
の代わりに
char[]
配列を使うと、意図した作業を終えた後に明示的にデータを消去することができます。これにより、ガベージコレクションが行われる前でもパスワードがメモリから削除されるようになります。**
それでは、コードスニペットを見てみましょう。これは、今説明した内容を示しています。
最初の
String
:
System.out.print("Original String password value: ");
System.out.println(stringPassword);
System.out.println("Original String password hashCode: "
+ Integer.toHexString(stringPassword.hashCode()));
String newString = "** ** ** ** ** ** ** ** ";
stringPassword.replace(stringPassword, newString);
System.out.print("String password value after trying to replace it: ");
System.out.println(stringPassword);
System.out.println(
"hashCode after trying to replace the original String: "
+ Integer.toHexString(stringPassword.hashCode()));
出力は次のようになります。
Original String password value: password
Original String password hashCode: 4889ba9b
String value after trying to replace it: password
hashCode after trying to replace the original String: 4889ba9b
今
char[]
の場合:
char[]charPassword = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.print("Original char password value: ");
System.out.println(charPassword);
System.out.println(
"Original char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
Arrays.fill(charPassword, '** ');
System.out.print("Changed char password value: ");
System.out.println(charPassword);
System.out.println(
"Changed char password hashCode: "
+ Integer.toHexString(charPassword.hashCode()));
出力は以下のとおりです。
Original char password value: password
Original char password hashCode: 7cc355be
Changed char password value: ** ** ** ** ** ** ** **
Changed char password hashCode: 7cc355be
ご覧のとおり、元の
String
の内容を置き換えようとした後も、値は同じままであり、
hashCode()
メソッドは同じアプリケーションの実行で異なる値を返しませんでした。つまり、元の
String
はそのまま残りました。
そして
char[]
配列については、同じオブジェクトのデータを変更することができました。
3誤ってパスワードを印刷することができます
char[]
配列でパスワードを操作することのもう1つの利点は、コンソール、モニター、またはその他多かれ少なかれ不安定な場所でのパスワードの誤ったロギングを防ぐことです。
次のコードをチェックしましょう。
String passwordString = "password";
char[]passwordArray = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
System.out.println("Printing String password -> " + passwordString);
System.out.println("Printing char[]password -> " + passwordArray);
出力では:
Printing String password -> password
Printing char[]password ->[[email protected]----
前者の場合はコンテンツ自体が印刷されますが、後者の場合はデータがそれほど有用ではないため、__char[]__の脆弱性は少なくなります。
[[summary]]
=== ** 4結論**
このクイック記事では、パスワードの収集に____String____sを使用しない理由と、代わりに__char[]__配列を使用する理由について説明しました。
いつものように、コードスニペットはhttps://github.com/eugenp/tutorials/tree/master/java-strings[over on GitHub]にあります。