パスワードやIPアドレス、暗号化鍵等センシティブな情報をハードコードすると、それらの情報を攻撃者に晒してしまう可能性がある。クラスファイルにアクセスできる者であれば誰でも、クラスファイルを逆コンパイルし、センシティブな情報を取り出すことができる。したがって、プログラムにセンシティブな情報をハードコードしてはならない。
また、センシティブな情報をハードコードしてしまうと、その変更に応じてコードを管理する必要が増す。たとえば、実運用中のプログラムにハードコードしたパスワードを変更するには、パッチを配布が必要となる[Chess 2007]。
違反コード
以下の違反コード例では、String クラスのオブジェクトにサーバのIPアドレスをハードコードしている。
class IPaddress { String ipAddress = new String("172.16.254.1"); public static void main(String[] args) { //.. } }
悪意あるユーザは、javap コマンドを使ってクラスファイルを逆アセンブルし、ハードコードされたIPアドレスを見つけることができる(javap -c IPaddress)。逆アセンブルの結果、サーバのIPアドレス 172.16.254.1 が平文で出力される。
Compiled from "IPaddress.java" class IPaddress extends java.lang.Object{ java.lang.String ipAddress; IPaddress(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/String 8: dup 9: ldc #3; //String 172.16.254.1 11: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V 14: putfield #5; //Field ipAddress:Ljava/lang/String; 17: return public static void main(java.lang.String[]); Code: 0: return }
適合コード
以下の適合コードは、セキュアなディレクトリに保存されたファイルからサーバのIPアドレスを取得している。IPアドレスを使用後ただちにメモリから消去することで、情報が外部に漏えいする可能性をさらに低減している。
class IPaddress { public static void main(String[] args) throws IOException { char[] ipAddress = new char[100]; BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream("serveripaddress.txt"))); // サーバのIPアドレスを読み取り、char 型配列に格納し、 // 読み取ったバイト数を返す int n = br.read(ipAddress); // サーバのIPアドレスを検証する // IPアドレスを使用し終わったらすぐに、 // 明示的にサーバのIPアドレスを消去する for (int i = n - 1; i >= 0; i--) { ipAddress[i] = 0; } br.close(); } }
センシティブな情報であるIPアドレスがプログラムの外部に晒される時間をさらに制限するには、BufferedReader をダイレクトかつネイティブな入出力(NIO)バッファに置き換えるとよい。バッファの内容は使用後ただちに消去される。
違反コード (ハードコードされたデータベースのパスワード)
以下の違反コード例では、SQL接続要求にユーザ名とパスワードフィールドがハードコードされている。
public final Connection getConnection() throws SQLException { return DriverManager.getConnection( "jdbc:mysql://localhost/dbName", "username", "password"); }
1引数および2引数の java.sql.DriverManager.getConnection() メソッドも誤用する危険があることに注意。
適合コード
以下の適合コードでは、セキュアなディレクトリに保存された設定ファイルからユーザ名とパスワードを読み取っている。
public final Connection getConnection() throws SQLException { String username; String password; // ユーザ名とパスワードは実行時にセキュアな設定ファイルから取得される return DriverManager.getConnection( "jdbc:mysql://localhost/dbName", username, password); }
プログラムの実行時にユーザ名とパスワードの入力をユーザに促すという方法もよい。
可能であれば、パスワードのようなセンシティブな情報は文字列ではなく文字配列に保存すべきである。JVMは不要になった文字列を保持し続けることがあるからである。しかし、このコード例では、DriverManager.getConnection() が必要とするため文字列を用いている。
リスク評価
センシティブな情報をハードコードすると、攻撃者に情報を晒してしまう可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MSC03-J | 高 | 中 | 中 | P12 | L1 |
関連する脆弱性
Apache Geronimoをベースに開発された WAS CE の脆弱性について、GERONIMO-2925 および GERONIMO-1135 に記されている。WAS CE は、AES暗号を使ってパスワードを暗号化しているが、この鍵はハードコードされており、すべてのWAS CE サーバが共通に使用している。つまり、ソフトウェアをダウンロードできれば、すべての WAS CE インスタンスに共通の鍵を手に入れることができるというわけである。この脆弱性は、WAS CE の各インスタンスでユニークな鍵を生成し、その鍵を使用するように変更することで修正された。
関連ガイドライン
CERT C Secure Coding Standard | MSC18-C. Be careful while handling sensitive data, such as passwords, in program code |
ISO/IEC TR 24772:2010 | Hard-coded Password [XYP] |
MITRE CWE | CWE-259. Use of hard-coded password |
CWE-798. Use of hard-coded credentials |
参考文献
[Chess 2007] | 11.2, Outbound Passwords: Keep Passwords out of Source Code |
[Fortify 2008] | Unsafe Mobile Code: Database Access |
[Gong 2003] | 9.4, Private Object State and Object Immutability |
翻訳元
これは以下のページを翻訳したものです。
MSC03-J. Never hard code sensitive information (revision 74)