16

リフレクションを使用してスクラブStringを使用すると、パスワードStringに使用するのと同じくらい安全になりますか?char[]

セキュリティの観点から、パスワードの保存/受け渡しに使用するのがベスト プラクティスと一般的に考えられていchar[]ます。これは、ガベージ コレクションによってパスワードがクリーンアップされ、メモリが再利用されるよりもかなり前に、コード内でできるだけ早く内容をゼロにできるためです (すべてのトレースをワイプ)、メモリ攻撃の時間枠を制限します。

ただし、char[]は ほど便利ではないため、必要に応じて をString「スクラブ」して、 と同じくらい安全にすることができれば便利です。StringStringchar[]

以下は、リフレクションを使用して のフィールドをゼロにするメソッドですString

この方法は「OK」であり、パスワードStringと同じくらい安全にするという目標を達成していますか?char[]

public static void scrub(String str) throws NoSuchFieldException, IllegalAccessException {
    Field valueField = String.class.getDeclaredField("value");
    Field offsetField = String.class.getDeclaredField("offset");
    Field countField = String.class.getDeclaredField("count");
    Field hashField = String.class.getDeclaredField("hash");
    valueField.setAccessible(true);
    offsetField.setAccessible(true);
    countField.setAccessible(true);
    hashField.setAccessible(true);
    char[] value = (char[]) valueField.get(str);
    // overwrite the relevant array contents with null chars
    Arrays.fill(value, offsetField.getInt(str), countField.getInt(str), '\0');
    countField.set(str, 0); // scrub password length too
    hashField.set(str, 0); // the hash could be used to crack a password
    valueField.setAccessible(false);
    offsetField.setAccessible(false);
    countField.setAccessible(false);
    hashField.setAccessible(false);
}

簡単なテストを次に示します。

String str = "password";
scrub(str);
System.out.println('"' + str + '"');

出力:

""

注:パスワードはString定数ではないため、このメソッドを呼び出しても、インターンされた文字列に悪影響を及ぼさないと考えることができます。

また、簡単にするために、このメソッドはかなり「未加工」の状態のままにしています。私がそれを使用する場合、スローされた例外を宣言 (try/catch/ignoring) したり、繰り返されるコードをリファクタリングしたりしません。

4

2 に答える 2

7

潜在的な安全上の懸念が 2 つあります。

  1. String は、バッキング配列を他の String と共有する場合があります。たとえば、 がより大きなStringを呼び出すことによって作成された場合。したがって、配列全体をゼロにすると、パスワードを含まない他の文字列の状態が上書きされる可能性があります。substringStringvalue

    解決策は、パスワード文字列で使用されるバッキング アレイの部分だけをゼロにすることです。

  2. JLS ( 17.5.3final ) は、リフレクションを使用して変数 を変更した場合の影響は未定義であると警告しています。

    ただし、これのコンテキストは Java メモリ モデルであり、コンパイラが積極的にfinal変数をキャッシュすることが許可されているという事実です。この場合:

    • String がスレッドに限定されていることが予想されます。

    • これらの変数を再度使用するべきではありません。

これらのどちらも実際の問題であるとは思いません... の過度に積極的なゼロ化をモジュロ修正しvalueます。


しかし、本当の懸念はヴェロキラプトルです。:-)


あなたが実際にこのようにパスワードをザッピングすることを気にかけているとは、私は困惑しています。考えてみると、何者かがプロセス メモリを読み取ったり、コア ダンプやスワップ ファイルを読み取ってパスワードを取得したりする可能性を防ぐことができます。しかし、誰かがそれを行うことができる場合、システムのセキュリティはすでに侵害されている必要があります...なぜなら、それらのものにはrootアクセス(または同等のもの)が必要になる可能性が高いからです。アクセス権があれば、アプリケーションがパスワードを消去する前にroot、プログラムを「デバッグ」してパスワードを取得できます。

于 2013-06-17T15:45:43.077 に答える