Java言語の書式指定文字列は、たとえばC言語のそれよりも厳密に解釈される [Seacord 2005]。標準ライブラリ実装は、引数が対応する書式指定子に一致しない場合、適切な例外をスローする。これは悪意ある攻撃の機会を低減しはする。しかしなお、悪意のあるユーザ入力により書式指定文字列を悪用し、情報漏えいやサービス運用妨害を引き起こすことは可能である。それゆえ、信頼できない入力源から取得した文字列を使って書式指定文字列を組み立てるべきではない。
違反コード
以下の違反コードは情報漏えいが発生する例を示している。クレジットカードの有効期限を入力として受け取り、それを書式指定文字列のなかで使っている。
class Format { static Calendar c = new GregorianCalendar(1995, GregorianCalendar.MAY, 23); public static void main(String[] args) { // args[0] はクレジットカードの有効期限を指す // args[0] には %1$tm, %1$te, %1$tY といった悪意ある引数が含まれるかもしれない // 第1引数は 05 (May) を、第2引数は 23 (day) を、第3引数は 1995 (year) を出力する // cと比較し、一致しない場合に以下の行を出力する System.out.printf(args[0] + " did not match! HINT: It was issued on %1$terd of some month", c); } }
適切な入力値検査を行っていないため、攻撃者は%1$tmや%1$te、%1$tYのような書式指定子を含む入力をプログラムに与えることで、入力の確認対象となる年月日を取得することができる。
適合コード
以下の適合コードでは、ユーザ入力が書式指定文字列から除外されるように保証している。
class Format { static Calendar c = new GregorianCalendar(1995, GregorianCalendar.MAY, 23); public static void main(String[] args) { // args[0] はクレジットカードの有効期限を指す // cと比較し、一致しない場合に以下の行を出力する System.out.printf("The input did not match! " + "HINT: It was issued on %1$terd of some month", args[0], c); } }
リスク評価
書式指定文字列がユーザ入力によって汚染(taint)されると、情報漏えいやサービス運用妨害につながる。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
IDS06-J | 中 | 低 | 中 | P4 | L3 |
自動検出
静的解析ツールの汚染解析は、このルールへの違反のいくつかを検出できるだろう。
関連ガイドライン
CERT C Secure Coding Standard | FIO30-C. Exclude user input from format strings |
CERT C++ Secure Coding Standard | FIO30-CPP. Exclude user input from format strings |
ISO/IEC TR 24772:2010 | "Injection [RST]" |
MITRE CWE | CWE-134. "Uncontrolled Format String" |
参考文献
[API 2006] | Class Formatter |
[Seacord 2005] | Chapter 6, Formatted Output |
翻訳元
これは以下のページを翻訳したものです。
IDS06-J. Exclude user input from format strings (revision 73)