String secret="foo";
WhatILookFor.securelyWipe(secret);
そして、Javaオプティマイザーによって削除されないことを知っておく必要があります。
文字列を「ワイプ」することはできません。それは不変であり、あなたがそれを変えることができないいくつかの本当に汚くて危険なトリックを除いて。
したがって、最も安全な解決策は、そもそもデータを文字列に入れないことです。代わりに、StringBuilderまたは文字の配列、あるいは不変ではないその他の表現を使用してください。(そして、完了したらそれをクリアします。)
記録のために、文字列のバッキング配列の内容を変更する方法はいくつかあります。たとえば、リフレクションを使用して、文字列のバッキング配列への参照を取り出し、その内容を上書きできます。ただし、これにはJLS状態の動作が指定されていないことを行うことが含まれるため、オプティマイザーが予期しないことを行わないことを保証することはできません。
私の個人的な見解は、許可されていない人が最初にメモリ/メモリダンプにアクセスできないように、アプリケーションプラットフォームをロックダウンする方がよいということです。結局のところ、プラットフォームが適切に保護されていない場合、「悪者」は文字列の内容を消去する前に取得できる可能性があります。このような手順は、少量のセキュリティクリティカルな状態で保証される場合がありますが、処理する「機密」情報がたくさんある場合、通常の文字列と文字列処理を使用できないことは大きな問題になります。
メモリに直接アクセスする必要があります。
文字列への信頼できるアクセス権がなく、文字列がどこかにインターンされているかどうか、または知らないオブジェクトが作成されているかどうかがわからないため、文字列を使用してこれを行うことは実際にはできません。
あなたが本当にこれを必要とするならば、あなたは次のようなことをしなければならないでしょう
public class SecureString implements CharSequence {
char[] data;
public void wipe() {
for(int i = 0; i < data.length; i++) data[i] = '.'; // random char
}
}
そうは言っても、データがまだメモリに残っているのではないかと心配している場合は、攻撃者がすでにデータを取得しているよりも、ある時点でデータがメモリに残っていることを認識しておく必要があります。現実的に身を守る唯一のことは、コアダンプがログファイルにフラッシュされるかどうかです。
オプティマイザーに関しては、操作が最適化されるかどうかは非常に疑わしいです。本当に必要な場合は、次のようにすることができます。
public int wipe() {
// wipe the array to a random value
java.util.Arrays.fill(data, (char)(rand.nextInt(60000));
// compute hash to force optimizer to do the wipe
int hash = 0;
for(int i = 0; i < data.length; i++) {
hash = hash * 31 + (int)data[i];
}
return hash;
}
これにより、コンパイラは強制的にワイプを実行します。実行時間は約2倍になりますが、それ自体はかなり高速な操作であり、複雑さの程度は増しません。
「安全でない」方法を使用して、データをオフヒープに保存します。その後、完了したらゼロにすることができ、JVMによってヒープの周りにプッシュされないことを確認できます。
Unsafeに関する良い投稿は次のとおりです。
http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/
文字列を使用する場合は、メモリダンプに表示されることを心配していると思います。String.replace()
文字列を実行時に使用すると、文字列が変更され、使用後にスコープ外になり、メモリダンプに正しく表示されないように、キー文字を使用することをお勧めします。ただし、機密データには文字列を使用しないことを強くお勧めします。