令和6年度 春期 情報処理安全確保支援士試験 午後 問4|リリース直前のレビューで次々と崩れた「安全なはず」のコード—情報処理安全確保支援士で学ぶセキュアプログラミングの事例
この記事で扱うセキュリティ事例
試験区分: 情報処理安全確保支援士
出典: 令和6年度 春期 情報処理安全確保支援士試験 午後 問4
主なテーマ: セキュアプログラミング(Java+RDBMS)、最小権限の原則、OSアカウントと所属グループの権限設計、ログへの重要情報の漏えい、パスワードのハッシュ保存とCRYPTREC暗号リスト、例外処理の不備、開発委託の責任分担
この記事は「情報処理安全確保支援士 午後問題 全70問」シリーズの1本です。→ 全70問の一覧・テーマ別索引はこちら
導入: なぜこの事例が重要なのか
「動くプログラムを書けること」と「安全なプログラムを書けること」は、まったく別の能力です。情報処理安全確保支援士試験の令和6年春期 午後 問4は、その差がどこに出るのかを、ひとつのWebシステム開発の物語を通して教えてくれます。
舞台になるのは、加工食品メーカーがインターネット通販に乗り出すために作った受注システムです。攻撃を受けて情報が流出した、という派手なインシデントではありません。むしろ逆で、リリース直前のセキュリティレビューで、外部の専門家が「このままでは危ない」という不備を次々に発見していく——いわば「事故が起きる前の物語」です。
しかし、見つかった不備の一つひとつは、現実の漏えい事故の典型的な原因そのものでした。権限の設計が甘くて関係のない担当者まで個人情報を見られてしまう。デバッグ用のログにパスワードが平文(暗号化されていない、そのまま読める状態)で書き出されてしまう。パスワードのハッシュ化(元に戻せない形に変換すること)に古い方式を使っている。例外(プログラム実行中に起きる想定外のエラー)の処理が甘く、データベースとの接続が閉じられないまま放置される——。
この記事を読むと、セキュアプログラミングというテーマで「どこを、なぜ疑うべきか」という視点が手に入ります。受験者にとっては頻出論点の宝庫であり、システムを発注・運用する立場の人にとっては「外部レビューで何を見てもらうべきか」を考える教材になるはずです。
インシデントの概要

主役はA社。加工食品の製造・販売を行う、従業員500名の会社です。これまでは問屋や直販店からの注文を、社内に設置したサーバ上の「業務システム」で受け付けて、在庫管理まで行ってきました。
このたびA社は、販売拡大を狙って、インターネットを使ったギフト販売に乗り出すことを決めます。個人のお客さんから直接注文を受ける「Web受注システム」を新しく作ることになりました。開発言語はJava、データの保管にはRDBMS(リレーショナルデータベース管理システム。表形式でデータを管理するソフトウェアの定番)を使います。A社はITベンダーであるB社と開発の委託契約を結び、両社が協働で開発を進めることになりました。
このシステムが扱う情報は、決して軽いものではありません。氏名、住所、電話番号、メールアドレス、パスワード、銀行口座情報、決済情報——A社が「重要情報」と分類するデータがずらりと並びます。最大で10万人の個人顧客の登録を見込んでおり、もし漏えいすれば、会社の信用に直結する規模です。
システムは、APサーバ(アプリケーションサーバ。プログラム本体が動くサーバ)、バッチサーバ(決まった時間にまとめて処理を回すサーバ)、ログサーバ(記録を集約するサーバ)などをクラウド上のIaaS(サーバなどの基盤をネット越しに借りる形態)に構築し、データベースはクラウドのマネージドDB(運用をクラウド事業者が肩代わりしてくれるデータベース)を利用します。サーバのOS(基本ソフト)はLinuxです。
そして開発が結合テストの段階に近づいたとき、A社は重要な判断をします。設計書とソースコードのセキュリティレビューを、セキュリティ専門会社のC社に委託したのです。レビューを担当したのは、C社の情報処理安全確保支援士(登録セキスペ)であるE氏でした。ここから、「安全なはず」だったシステムの綻びが、一枚ずつめくられていきます。
何が起きたのか

E氏が最初に手をつけたのは、業務システムとWeb受注システムの間でデータをやり取りする「データ連携機能」でした。
この機能は、1時間ごとに片方のシステムが注文や在庫のデータをCSVファイル(項目をカンマで区切った、表計算ソフトでも開ける形式のテキストファイル)に書き出し、HTTPS(暗号化された通信)でもう片方へ送り、受け取った側がそれを使って自分のデータベースを更新する、という仕組みでした。
E氏は、注文データをCSVに書き出すプログラム(表4のNo.3)の中身を確認します。そこには、注文ID、決済金額、銀行コード、銀行口座番号、お届け先住所、お届け先氏名、電話番号……といった、まさに「重要情報」の塊が含まれていました。しかもこのCSVファイルは「平文」、つまり暗号化されないまま本番バッチサーバの`/var/data`というフォルダに保存される設計です。
問題は、そのファイルに「誰がアクセスできるか」でした。Linuxでは、ファイルやフォルダごとに「所有者」「グループ」「その他」の三者に対して、読み書きの権限を細かく設定できます。E氏が権限の設定をたどると、CSVファイルの所有者は`batchappuser`というアカウントで、グループにも読み書きの権限が与えられていました。そして、この`batchappuser`が属するグループは`operation`。同じ`operation`グループには、システムの稼働を監視する「システム運用担当者」のアカウント(`operator`)も含まれていたのです。
ここでA社の要件を思い出す必要があります。A社のルールでは、重要情報を取り扱ってよいのは「重要情報取扱運用者」だけ、と明確に決められていました。システム運用担当者は、サーバが動いているかどうかを監視するのが役目で、中身の重要情報を見てはならない立場です。ところが権限設計の結果、システム運用担当者は、その気になれば顧客の銀行口座や住所が詰まったCSVファイルを開けてしまう。「見てはいけない人が、技術的には見られてしまう」という、最小権限の原則(各人に業務上必要な最小限の権限しか与えない考え方)に反する穴が、ぽっかり空いていたのです。
E氏は、これを是正する案と、さらに念のための「保険的対策」を併せて提案しました。是正案は、`batchappuser`の所属グループを`operation`から`personal`へ移し、CSVファイルに触れられるのを重要情報取扱運用者だけに絞ること。保険的対策は、CSVを書き出すプログラムに暗号化処理を加え、それを取り込むプログラムに復号(暗号を元に戻す)処理を加えることでした。たとえ本番バッチサーバにアクセスできる者がいても、暗号化されていれば中身は読めません。
次にE氏が目を向けたのは、新規ユーザーの登録機能を担う「UserData」というJavaのクラス(プログラムの部品)でした。ここからが、セキュアプログラミングの核心です。
ソースコードを読んだE氏は、まずパスワードの取り扱いに眉をひそめます。プログラムは、利用者が入力したパスワードを`SHA-1`というハッシュ関数(入力を固定長の値に変換し、元に戻せなくする関数)でハッシュ化していました。しかしA社の要件は「CRYPTREC暗号リストに記載されているハッシュ関数を使うこと」。SHA-1はすでに安全性に懸念があるとされ、この要件を満たしていなかったのです。
さらにE氏は、もっと不気味な落とし穴を見つけます。パスワードをハッシュ化する処理は`try`ブロック(エラーが起きるかもしれない処理を囲む構文)の中にあり、ハッシュ関数の準備に失敗すると例外が発生します。ところが、その例外を受け止める`catch`ブロックの中身は、エラーをログに記録するだけ。例外を「握りつぶして」、何事もなかったかのように処理を続けてしまう作りでした。
これが何を意味するか。もし将来、メンテナンスなどで実行環境が変わり、指定したハッシュ関数が使えなくなって例外が発生したら——パスワードはハッシュ化されないまま、入力されたそのままの平文で変数に残ります。そして処理はそのまま進み、後続の行で、平文のパスワードがユーザーマスターテーブル(利用者情報を保管する表)にそのまま保存されてしまうのです。エラーが「黙って」起きるからこそ、誰も気づかないまま重大な事故になる。例外の握りつぶしの恐ろしさが、ここに凝縮されていました。
そしてもう一つ。プログラムには、デバッグ(不具合の調査)のために、組み立てたSQL文と挿入するデータの中身をそっくりログに書き出す処理が、二系統入っていました。一つは標準出力(プログラムが画面に出すための出力先。このシステムではログ用テキストファイルにリダイレクト=転送される設定)への出力、もう一つはログサーバへ送られる「APログ」への出力です。挿入データには当然、パスワードや氏名、住所、電話番号、メールアドレスが含まれます。つまり、デバッグ用のログという、本来は誰でも見やすい場所に、暗号化もマスクもされていない重要情報がそのまま記録されていたのです。
ここで効いてくるのが、最初の権限設計の話でした。システム開発者は、障害発生時に原因を調べるため、本番ログサーバへのアクセス権を持っています。本来、システム開発者は重要情報にアクセスしてはならない立場です。ところがログサーバのAPログに重要情報が漏れ出していたために、システム開発者が「アクセスを禁止されているはずの情報」に、ログ越しに手が届いてしまう。権限設計の甘さと、ログへの重要情報出力という二つの不備が、ここで合流して一つの漏えい経路を作り上げていたのです。
E氏はさらに、データベースとの接続オブジェクト(`psObj`)が、処理の途中で例外が起きた場合に閉じられず、メモリリーク(使い終わったメモリ領域が解放されずに残り、少しずつ食いつぶされていく現象)を引き起こす可能性まで指摘しました。
これらの指摘を受けて、システム開発者はソースコードを修正します。古いSHA-1は要件に合うハッシュ関数に差し替え、例外を握りつぶす代わりに「回復不能な例外」として処理を中断するよう変更し、ログに出す前に重要情報を`*`で覆い隠す(マスクする)処理を追加し、標準出力への危険な出力は削除しました。データベース接続も、例外が起きても起きなくても必ず閉じられるよう、`finally`という仕組みで囲み直しました。
ところが——物語はもう一山あります。修正されたコードをE氏が再度レビューすると、まだ穴が残っていました。パスワードのハッシュ化が、ハッシュ関数を新しくしただけでは「レインボーテーブル攻撃」に対して無防備だったのです。これは、よく使われるパスワードのハッシュ値をあらかじめ大量に計算した「逆引き表」を使い、盗んだハッシュ値から元のパスワードを一気に割り出す攻撃です。E氏は、利用者ごとに異なる「ソルト」(ハッシュ化の前にパスワードへ混ぜる、利用者ごとに違うランダムな文字列)を加えるよう、最後の修正を促しました。A社はこの対応も完了させ、テストを経て、Web受注システムをようやくリリースしたのです。
ここから先は

情報処理安全確保支援士(登録セキスペ)の午後問題、「読んでも頭に入らない」と感じていませんか?本シリーズでは、2017年〜2025年の過去…
この記事が気に入ったらチップで応援してみませんか?
