ログ情報は、デバッグ、インシデント対応、フォレンジックにおける記録収集において重要である。しかし、センシティブなデータをログに残すことには、考慮すべき様々な危険がある。利害関係者(stakeholder)のプライバシ保護、個人情報収集に関する法的制限、内部関係者による情報漏えいの可能性など。ここで考慮すべきセンシティブな情報のなかには、IPアドレス、ユーザ名とパスワード、メールアドレス、クレジットカード番号、社会保障番号など、個人を特定できるすべての情報が含まれる。多くの国ではこのような個人情報の収集を禁止あるいは制限している。また、個人が特定されないような形であれば収集を認めている国もある。このようなことを考慮すると、ログ情報にはセンシティブなデータを含めるべきでないし、とくに法律で禁止されている場合には含めてはならない。
残念なことに、このルールへの違反はよく見受けられる。たとえば、LineControl という Java アプリケーションの 0.8.1 より前のバージョンでは、ローカルユーザのパスワードを含むセンシティブな情報を記録していた(CVE-2005-2990)。
JDK 1.4 およびそれ以降における java.util.logging クラスは、ログをとる基本的な仕組みを提供している。ログをとる仕組みはほかにもあるが、どのような仕組みを使うにせよ、基本的な考えかたは変わらない。
プログラムは、様々なレベルでデータを保護すべきである。アクセス時間のような情報は通常のログ情報に含めても安全だろう。ログ情報に含めてもよいが、ログファイルにアクセスできるのは管理者だけに制限すべき情報もある。クレジットカード番号のような情報は、暗号化した形で記録すべきである。パスワードのような情報はそもそも記録すべきでない。
以下にとりあげるコード例では、問題のログ情報が信頼境界の外に置かれる状況を想定する。また、通常のログ情報では、日時情報やイベント名なども含まれるだろうが、コード例を分かりやすくするため、ここではそのような情報は省略している。
違反コード
以下の違反コード例では、セキュリティ例外が発生したときにサーバは、接続してきたリモートクライアントのIPアドレスをログに出力している。このデータは、たとえば、ユーザの web ブラウジング特性に関するプロファイリングに利用されてしまう可能性がある。また、このようなログ出力は、多くの国では法規制に抵触するかもしれない。
ログ情報にIPアドレスを含めてはいけないのであれば、SecurityException に関するいかなる情報も含めるべきではない。IP アドレスが漏えいしてしまうかもしれないからである。例外にセンシティブな情報が含まれている場合には、アプリケーションが提供する MyExceptionReporter クラスは、catch ブロックの次の文に制御を渡す前に、その情報を削ぎ落としておくべきである(「ERR00-J. チェック例外を抑制あるいは無視しない」を参照)。
public void logRemoteIPAddress(String name) { Logger logger = Logger.getLogger("com.organization.Log"); InetAddress machine = null; try { machine = InetAddress.getByName(name); } catch (UnknownHostException e) { Exception e = MyExceptionReporter.handle(e); } catch (SecurityException e) { Exception e = MyExceptionReporter.handle(e); logger.severe(name + "," + machine.getHostAddress() + "," + e.toString()); } }
適合コード
以下の適合コードでは、MyExceptionReporter によるログ出力以外にセキュリティ例外に関するログ出力を行わない。
// ... catch (SecurityException e) { Exception e = MyExceptionReporter.handle(e); }
違反コード
セキュリティ上の理由により、センシティブな情報(たとえば年齢情報など)を含むログメッセージはコンソールに出力すべきではない。java.util.logging.Logger クラスでは複数のログレベルを扱えるようになっており、情報のレベル分けができる。ログレベルには FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE がある。デフォルトの設定では、INFO、WARNING、SEVERE レベルのログ出力の場合、メッセージをコンソールに出力する。コンソールに出力されたメッセージは、エンドユーザにもシステム管理者にも見えることになる。
年齢情報はログファイルにのみ出力し、コンソールには出力しない、という前提があった場合、以下は違反コードになる。
logger.info("Age: " + passengerAge);
適合コード
以下のコードでは年齢情報を FINEST レベルでログ出力しているため、コンソールには出力されない。前述のように、年齢情報はログファイルにのみ出力し、コンソールには出力しないというのが前提である。
// すべてのハンドラが INFO 以上のレベルのログのみを出力するように設定 Handler handlers[] = logger.getHandlers(); for (int i = 0; i < handlers.length; i++) { handlers[i].setLevel(Level.INFO); } // ... logger.finest("Age: " + passengerAge);
リスク評価
センシティブな情報をログ出力すると、システムのセキュリティポリシーに違反する可能性がある。また、ログレベルが不適切だったり、ログファイルを安全に管理していない場合、ユーザのプライバシ情報が漏えいする可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO13-J | 中 | 中 | 高 | P4 | L3 |
関連ガイドライン
MITRE CWE | CWE-532. Information exposure through log files |
CWE-533. Information exposure through server log files | |
CWE-359. Privacy Violation | |
CWE-542. Information Exposure Through Cleanup Log Files |
参考文献
[API 2006] | Class java.util.logging.Logger |
[Chess 2007] | 11.1, Privacy and Regulation: Handling Private Information |
[CVE 2011] | CVE-2005-2990 |
[Sun 2006] | Java Logging Overview |
翻訳元
これは以下のページを翻訳したものです。
FIO13-J. Do not log sensitive information outside a trust boundary (revision 69)