Javaでパスワードを操作するために文字列にchar[]配列を使用する

Javaでパスワードを操作するために文字列でchar []配列を使用しますか?

1. 概要

この記事では、JavaでStringの代わりにchar[]配列を使用してパスワードを表す必要がある理由を説明します。

このチュートリアルは、通常は永続層で処理される実際のパスワードの保存方法ではなく、メモリ内のパスワードを操作する方法に焦点を当てていることに注意してください。

また、パスワードの形式を制御できないことも想定しています(例: パスワードは、Stringの形式でサードパーティのAPIから取得されます。 パスワードの操作にタイプjava.lang.Stringのオブジェクトを使用することは明らかなようですが、代わりにchar[]を使用することをJavaチーム自身が推奨しています。

たとえば、javax.swingJPasswordFieldを見ると、Stringを返すメソッドgetText()はJava 2以降廃止され、%に置き換えられていることがわかります。 char[]を返す(t4)sメソッド。

それでは、それが当てはまるいくつかの強力な理由を探りましょう。

2. 文字列は不変です

JavaのStringsは不変です。つまり、高レベルの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[]配列でパスワードを操作することの別の利点は、コンソール、モニター、またはその他の多かれ少なかれ安全でない場所にパスワードが誤って記録されるのを防ぐことです。

次のコードを確認してみましょう。

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[]の脆弱性が低くなります。

4. 結論

この簡単な記事では、パスワードの収集にStringsを使用しない理由と、代わりにchar[]配列を使用する必要がある理由をいくつか強調しました。

いつものように、コードスニペットはover on GitHubで見つけることができます。