効果的なjavaは言う:
//潜在的なセキュリティホール!
static public final Thing [] VALUES = {...};
誰かがセキュリティホールとは何か教えてもらえますか?
効果的なjavaは言う:
//潜在的なセキュリティホール!
static public final Thing [] VALUES = {...};
誰かがセキュリティホールとは何か教えてもらえますか?
フィールドの宣言static final public
は通常、クラス定数の特徴です。プリミティブ型(ints、doublesなど)や、文字列や。などの不変クラスにはまったく問題ありませんjava.awt.Color
。配列の場合、問題は、配列参照が一定であっても、配列の要素を変更できることです。また、フィールドであるため、変更は保護されておらず、制御されておらず、通常は歓迎されません。
これに対抗するために、配列フィールドの可視性をプライベートまたはパッケージプライベートに制限できるため、疑わしい変更を探すときに考慮すべきコードの本体が少なくなります。あるいは、多くの場合、配列を一緒に廃止して、「リスト」または他の適切なコレクションタイプを使用することをお勧めします。コレクションを使用すると、すべての更新がメソッドを経由するため、更新を許可するかどうかを制御できます。を使用してコレクションをラップすることにより、更新を防ぐことができますCollections.unmodifiableList()
。ただし、コレクションが不変であっても、コレクションに格納されている型も不変であることを確認する必要があります。そうしないと、想定される定数に対する一方的な変更のリスクが再び発生します。
これが潜在的なセキュリティホールであり、カプセル化が不十分であるだけではない理由を理解するには、次の例を検討してください。
public class SafeSites {
// a trusted class with permission to create network connections
public static final String[] ALLOWED_URLS = new String[] {
"http://amazon.com", "http://cnn.com"};
// this method allows untrusted code to connect to allowed sites (only)
public static void doRequest(String url) {
for (String allowed : ALLOWED_URLS) {
if (url.equals(allowed)) {
// send a request ...
}
}
}
}
public class Untrusted {
// An untrusted class that is executed in a security sandbox.
public void naughtyBoy() {
SafeSites.ALLOWED_URLS[0] = "http://myporn.com";
SafeSites.doRequest("http://myporn.com");
}
}
ご覧のとおり、final配列を誤って使用すると、信頼できないコードが、信頼できるコード/サンドボックスが課そうとしている制限を覆す可能性があります。この場合、これは明らかにセキュリティの問題です。
コードがセキュリティクリティカルなアプリケーションの一部でない場合は、この問題を無視できます。しかし、IMOこれは悪い考えです。将来のある時点で、あなた(または他の誰か)がセキュリティが懸念される状況でコードを再利用する可能性があります。とにかく、これが作者がパブリックファイナルアレイをセキュリティ問題と呼ぶ理由です。
琥珀はコメントでこれを言いました:
ソースコードやバイトコードをどちらの方法でも読み取ることができれば、プライベート以上のセキュリティホールはありません...
本当じゃない。
「悪者」がソースコード/バイトコードを使用して、private
が存在し、配列を参照していると判断できるという事実は、セキュリティを破るのに十分ではありません。悪者はまた、リフレクションを使用するために必要な権限を持つJVMにコードを挿入する必要があります。この権限は、(適切に実装された)セキュリティサンドボックスで実行されている信頼できないコードには使用できません。
ゼロ以外の長さの配列は常に可変であるため、クラスがパブリック静的最終配列フィールド、またはそのようなフィールドを返すアクセサーを持つことは誤りであることに注意してください。 クラスにそのようなフィールドまたはアクセサーがある場合、クライアントは配列の内容を変更できます。
-効果的なJava、第2版。(70ページ)
外部クラスは配列の内容を変更できますが、これはおそらくクラスのユーザーに実行させたいことではありません(メソッドを介して実行させたい)。作者がセキュリティではなくカプセル化に違反していることを意味しているようです。
この行を宣言している人は、finalとしてマークされているため、他のクラスは配列の内容を変更できないと思うかもしれませんが、これは正しくありません。finalは、属性の再割り当てを停止するだけです。
この宣言では、クライアントはThing [0]、Thing [1]など(つまり、配列内の要素)を変更できます。
それは単に公的ものと私的なもの全体を意味すると考えてください。ローカル変数をプライベートとして宣言してから、直接アクセスするのではなく、getメソッドとsetメソッドを使用することをお勧めします。プログラムの外部でそれらを混乱させるのを少し難しくします。私の知る限りそれについて。
なぜなら、finalキーワードは参照値のみを保証し(たとえば、メモリの場所として想定)、その中のコンテンツは保証しないからです。