JVMにおいて、「2つのクラスは、同一のクラスローダでロードされ、同一の完全修飾名を持つとき、同一のクラス(そして同一の型)である」[JVMSpec 1999]。同じ名前であってもパッケージ名が異なれば異なるクラスである。また、完全修飾名が同一であっても、異なるクラスローダによってロードされていれば、異なるクラスである。
たとえばequals()メソッドを実装する場合、与えられたオブジェクトのクラス型と2つのオブジェクトのクラス型の同一性チェックが必要となるであろう。この比較を正しく行わないと、異なるクラスの2つのオブジェクトを同じクラスのオブジェクトであるとみなしてしまう可能性がある。このような比較を行う際には、クラス名を比較してはならない。
上記のような問題のあるコードは、どのような関数を実行しているかにもよるが、mix-and-match攻撃を受ける可能性がある。攻撃者は、対象として狙うクラスと同じ完全修飾名を持ったクラスを使用するかもしれない。クラス名の比較だけに基づいて保護すべきリソースへのアクセスを制御していると、本来許可されるべきでないクラスにリソースへのアクセスが許可されてしまうかもしれない。
逆に、同一のコードベースに由来する2つのクラスを同一のものとみなすことは間違いにつながる。デスクトップアプリケーションでは大抵の場合、同一のコードベースに由来する2つのクラスは同一であるが、J2EEサーブレットコンテナの場合そうではない。コンテナは、複数のクラスローダを使うことで、JVMを再起動することなく、必要なアプリケーションを動的に呼び出すことができる。このような状況では、同一のコードベースに由来するクラスの2つのオブジェクトが、JVMにとっては異なるクラスのオブジェクトとして扱われることがある。同一のコードベースに由来する2つのオブジェクトを比較する場合、equals()メソッドはtrueを返さないことがあることに注意。
違反コード
以下の違反コード例では、オブジェクト auth のクラス名を文字列「com.application.auth.DefaultAuthenticationHandler」と比較し、その結果に応じて処理を分岐させている。
// オブジェクト auth が必要な/期待されるクラスオブジェクトであるか調べる if (auth.getClass().getName().equals( "com.application.auth.DefaultAuthenticationHandler")) { // ... }
完全修飾名を比較するのは不十分である。なぜなら、同じ完全修飾名を持つ異なるクラスが、異なるクラスローダによって1つのJVMにロードされる可能性があるからである。
適合コード
以下の適合コードでは、単にクラス名を比較するのではなく、authのクラスオブジェクトを、現在のクラスローダがロードしたクラスのクラスオブジェクトと比較している。
// オブジェクト auth が必要な/期待されるクラスオブジェクトであるか調べる if (auth.getClass() == this.getClass().getClassLoader().loadClass( "com.application.auth.DefaultAuthenticationHandler")) { // ... }
loadClass()メソッドは(クラス名やそれを規定するクラスローダを含む)現在の名前空間から、指定された名前のクラスを返し、2つのクラスオブジェクトの比較が正しく行われる。
違反コード
以下の違反コード例では、xとyそれぞれのクラスオブジェクトの名前をequals()メソッドで比較している。ここでも、xとyがそれぞれ異なるクラスローダによってロードされたものであれば、異なるクラスなのに名前は同じということがありうる。
// オブジェクト x と y のクラス名が同じかどうかを調べる if (x.getClass().getName().equals(y.getClass().getName())) { // 2つのオブジェクトは同じクラス }
適合コード
以下の適合コードでは、2つのオブジェクトのクラスを正しく比較している。
// オブジェクト x と y が同じクラスかどうか調べる if (x.getClass() == y.getClass()) { // オブジェクトが同じクラスだったときのコード }
リスク評価
クラスをその名前だけで比較すると、悪意あるクラスによるセキュリティチェックの回避や保護すべきリソースへのアクセスを許してしまう可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
OBJ09-J | 高 | 低 | 低 | P9 | L2 |
関連ガイドライン
MITRE CWE | CWE-486. Comparison of classes by name |
参考文献
[Christudas 2005] | Internals of Java Class Loading |
[JVMSpec 1999] | §2.8.1, Class Names |
[McGraw 1998] | Twelve rules for Developing More Secure Java Code |
[Wheeler 2003] | Java Secure Programming for Linux and UNIX HOWTO |
翻訳元
これは以下のページを翻訳したものです。
OBJ09-J. Compare classes and not class names (revision 97)