【情報処理安全確保支援士試験 令和6年度 春期 午後 問4 設問2】徹底解説!Javaセキュアコーディング編

前回に引き続き、令和6年度 春期 情報処理安全確保支援士 午後 問4 の解説をお届けします。今回は、多くの受験者が苦手意識を持つかもしれない、ソースコードの読解が問われる 【設問2】 です。

この設問は、採点講評で「Java言語での例外処理仕様を理解していないと思われる解答が散見された」「セキュアコーディングの基本的内容であり、正確に理解してほしい」 とコメントされている通り、セキュリティのプロフェッショナルとして必須の知識が問われています。

一見難しそうに見えるJavaのコードも、ポイントを押さえれば大丈夫!一緒に脆弱性を見抜く目を養っていきましょう。


情報処理安全確保支援士試験 令和6年度 春期 午後 問4

【出典:情報処理安全確保支援士試験 令和6年度 春期 午後 問4(一部、加工あり)】

[ユーザー登録機能のセキュリティレビュー]
 ユーザー登録機能は、UserDataクラスによって実現している。UserDataクラスのプログラム仕様を図2に、UserDataクラスのソースコードを図3に示す。


 E氏は、図3のソースコードについて、次のように指摘した。

  • パスワードからハッシュ値を得るためのハッシュ関数が、表1の要件を満たしていない。
  • 今後、メンテナンスなどで実行環境を変更した場合に、(d)行目で(e)が発生すると、25、26行目では、パスワードが平文でユーザーマスターテーブルに保存されてしまう。
  • ①システム運用担当者とシステム開発者が、要件でアクセスが禁止されている情報にアクセスできてしまう
  • 利用するAPサーバの実装では、変数psObjの指すメモリ領域においてメモリリークが発生する可能性がある。

 E氏の指摘を受け、システム開発者は、UserDataクラスのソースコードを修正した。修正後のUserDataクラスのソースコードを図4に示す。


 図4のソースコードについて、E氏は、セキュリティレビューを再度実施した。
 E氏は、図4のソースコードでは、レインボーテーブル攻撃を受けたときに攻撃が成立してしまうので、図2の仕様及び②図4のソースコードの6、7行目を修正すべきであると指摘した。

 A社は、E氏の指摘の対応を完了した。その後、テストを実施し、Web受注システムをリリースした。

🎯 ユーザー登録機能のセキュリティレビュー

設問2の舞台は、Web受注システムの「ユーザー登録機能」です。セキュリティ専門家のE氏が、ユーザー登録処理を実装したJavaのソースコード(図3)をレビューし、いくつかの問題点を指摘しました。この指摘内容を一つずつ解き明かしていくのが、今回のテーマです。


設問2 (1), (2)

(1) 本文中の (d) に入れる適切な行番号を、図3中から選び、答えよ。
(2) 本文中の (e) に入れる適切な字句を答えよ。

【解説】

この設問は、E氏の以下の指摘に関するものです。 「今後、メンテナンスなどで実行環境を変更した場合に、(d) 行目で (e) が発生すると、25、26行目では、パスワードが平文でユーザーマスターテーブルに保存されてしまう。」

これは非常に深刻な脆弱性ですね。なぜこんなことが起きてしまうのか、図3のソースコードを追ってみましょう。

  1. パスワード処理の流れ
    • まず、3行目でユーザーが入力した平文のパスワードが、インスタンス変数 this.password にセットされます 。
    • 次に、4行目から始まる try ブロックの中で、パスワードのハッシュ化が行われます 。
    • 5行目で MessageDigest.getInstance(“SHA-1”) という処理があります 。これは「SHA-1」という方式でハッシュ化を行う準備です。
    • もし、この5行目で「指定されたハッシュアルゴリズム(SHA-1)が見つからない」という例外(NoSuchAlgorithmException)が発生すると、プログラムの処理は9行目の catch ブロックにジャンプします 。
    • 重要なのは、例外が発生すると、7行目のハッシュ値でパスワードを上書きする処理が実行されないという点です 。
    • catch ブロックでログを出力した後、プログラムはそのまま後続のDB登録処理に進みます。
    • その結果、23行目のDB登録処理では、変数 this.password にはハッシュ化される前の平文パスワードが入ったままとなり、それがデータベースに保存されてしまうのです。

この流れから、脆弱性の原因となる処理と、発生する事象が明らかになりました。

  • (d) パスワードが平文で保存される原因となる例外が発生する可能性があるのは、ハッシュ化の準備をしている5行目です。
  • (e) 5行目で発生する可能性があるのは、指定されたアルゴリズムが見つからないという例外です。

【解答】

  • (1) d: 5
  • (2) e: 例外

設問2 (3)

本文中の下線①について、システム運用担当者とシステム開発者が、アクセスが禁止されているのにアクセスできてしまう情報は何か。図2中のユーザーマスターテーブルの列名で、それぞれ全て答えよ。また、その情報が出力される場所を、解答群の中から選び、それぞれ記号で答えよ。

解答群
ア 開発ログサーバのAPログを保存したテキストファイル
イ 本番APサーバの/sbinディレクトリ配下のバイナリファイル
ウ 本番APサーバの/var/dataディレクトリ配下のCSVファイル
エ 本番APサーバの/var/log/serverlogディレクトリ配下のテキストファイル
オ 本番ログサーバのAPログを保存したテキストファイル

【解説】

下線①の指摘は「システム運用担当者とシステム開発者が、要件でアクセスが禁止されている情報にアクセスできてしまう」 というものです。これは、不適切なログ出力が原因で発生する典型的な情報漏洩の問題です。

1. 何が、どこに出力されているか? 図3のソースコードを見ると、2つのログ出力処理があります。

  • 25, 26行目: System.out.println(...)
    • これはJavaの標準出力にログを出力します。要件16によると、標準出力は「APサーバの /var/log/serverlog ディレクトリ配下のテキストファイルに出力する」と定められています 。
  • 99, 100行目: Log.debug(...)
    • これは注記によると「引数の文字列をログサーバに送信するメソッド」です 。要件15で、APログはログサーバに転送・保存されると定められています 。

そして、どちらのログも

this.toString() の内容を出力しています。これは UserData オブジェクトの中身、つまりパスワード、氏名、住所、電話番号、メールアドレスといった重要情報 をそのまま文字列にして出力していると考えられます。

2. 誰が、どこにアクセスできるか? 要件と権限設定を再確認します。

  • システム運用担当者: 本番APサーバへのアクセス権があります 。したがって、System.out.println によって出力されたAPサーバ上のログファイル(/var/log/serverlog 配下)を閲覧できる可能性があります。
  • システム開発者: 本番ログサーバへのアクセス権があります 。したがって、Log.debug によって転送されたAPログを閲覧できます。

3. 結論

  • システム開発者:
    • アクセスできてしまう情報: Log.debug に出力された this.toString() の内容、すなわちユーザーマスターテーブルの列名でいう「パスワード、氏名、住所、電話番号、メールアドレス」です。
    • 出力される場所: 解答群のうち、開発者がアクセスできるのは「オ 本番ログサーバのAPログを保存したテキストファイル」です。
  • システム運用担当者:
    • この設問については、IPAの公式解答で「不備により設問が成立しない」とされています。これは、APサーバ上のログファイルのパーミッション設定(774)と運用担当者の所属グループ(operation)の関係から、アクセス権の解釈が一意に定まらないなど、問題設定に何らかの曖昧さがあったためと考えられます。試験対策上は、このようなケースもあると認識しておきましょう。

【解答】

  • システム運用担当者
    • アクセスできてしまう情報: (不備により設問が成立しない。)
    • 出力される場所: (不備により設問が成立しない。)
  • システム開発者
    • アクセスできてしまう情報: パスワード、氏名、住所、電話番号、メールアドレス
    • 出力される場所: オ

設問2 (4)

図4中の (f) に入れる適切な字句を答えよ。

【解説】

この設問は、E氏の「パスワードからハッシュ値を得るためのハッシュ関数が、表1の要件を満たしていない」 という指摘への修正に関するものです。

  • 要件: パスワードは「CRYPTREC 暗号リスト (令和5年3月30日版)の電子政府推奨暗号リストに記載されているハッシュ関数」でハッシュ化する必要がある 。
  • 図3の問題点: getInstance("SHA-1") を使用していた 。SHA-1は現在、脆弱性の観点から推奨されていません。
  • 修正後(図4): getInstance(" (f) ") となっています 。

したがって、(f) には電子政府推奨暗号リストに記載されているハッシュ関数名を入れる必要があります。代表的なものとして、SHA-256SHA-384SHA-512が挙げられます。

【解答】

SHA-256/SHA-384/SHA-512


設問2 (5)

図4中の (g) に入れる適切な処理を、ソースコード又は具体的な処理内容のいずれかで答えよ。

【解説】

これは、設問(1),(2)で明らかになった「例外が発生すると平文パスワードがDB登録されてしまう」問題への対策です。図4のコードでは、

catch (NoSuchAlgorithmException e) ブロックで「回復不能な例外発生」として (g) の処理を求めています

図3の問題は、例外をcatchはするものの、その後の処理を止めずに続行してしまったことでした。 回復不能な例外が発生した場合、処理を安全に中断させるのが鉄則です。

Javaでは、このような場合に RuntimeException をスロー(throw)します。RuntimeException は、プログラムの実行をその場で停止させる効果があり、後続のDB登録処理が実行されるのを防ぐことができます。

【解答】

throw new RuntimeException(e) もしくは ランタイムエラーを例外としてthrowする


設問2 (6)

図4中の (h) に入れる適切なソースコードを答えよ。

【解説】

この設問は、E氏の「変数psObjの指すメモリ領域においてメモリリークが発生する可能性がある」 という指摘への対策です。これは、DB接続などで確保したリソースが、プログラム終了後も解放されない問題です。

図3では、DB操作を行うための PreparedStatement オブジェクトを生成していますが、try ブロック内で例外が発生した場合に、このオブジェクトを閉じる(closeする)処理が実行されない可能性がありました。

図4では、この問題を解決するために、DB処理を

try-catch ブロックで囲み、その後に (h) ブロックを設けてリソースのクローズ処理を記述しています

プログラムの正常終了時でも、例外発生時でも、どんな状況でも必ず実行したい処理を記述するための構文。それが finally 句です。finally ブロックにリソースのクローズ処理を記述するのが、Javaにおけるリソースリーク対策の定石です。

【解答】

finally


設問2 (7)

本文中の下線②について、図4の6、7行目をどのように修正すればよいか。修正後の適切なソースコードを解答群の中から選び、記号で答えよ。ここで、変数 saltには、addUserメソッドの呼出しごとに異なる32バイトの固定長文字列が入っているものとするし、ユーザーマスターテーブルの定義に変更はないものとする。

【解説】

最後の問題です!下線②の指摘は「レインボーテーブル攻撃を受けたときに攻撃が成立してしまう」 というものです。

  • レインボーテーブル攻撃: パスワードとハッシュ値の対応表(レインボーテーブル)を事前に用意しておき、漏洩したハッシュ値から元のパスワードを高速に割り出す攻撃。
  • 対策: ソルト(salt)を用いることです。ソルトとは、パスワードに付加するランダムな文字列のことです。パスワードにユーザーごとに異なるソルトを加えてからハッシュ化することで、同じパスワードでもユーザーが違えばハッシュ値は全く異なるものになります。これにより、レインボーテーブルは無力化されます。

ソルトを利用したパスワード保存のポイントは2つです。

  1. 保存時: 「ソルト + パスワード」をハッシュ化する。
  2. DBへの格納: 次回の認証時に同じソルトを使えるように、生成したソルトハッシュ値の両方をDBに保存する必要がある。

このポイントを踏まえて解答群を見ていきましょう。

  • : 「ソルト+パスワード」をハッシュ化し 、DBには「ソルト+ハッシュ値」の形式で保存しています 。これはポイント1, 2を両方満たしており、正しい実装です。
  • イ, オ: 「ソルト+パスワード」をハッシュ化していますが、DBにハッシュ値しか保存していません 。これでは認証時に使うべきソルトが分からなくなってしまいます。
  • ウ, エ: ハッシュ化の仕方や、ソルトとハッシュ値の組み合わせ方が不適切です。

したがって、ソルトを正しく利用してレインボーテーブル攻撃対策ができているのは、選択肢アです。

【解答】

まとめ

設問2、お疲れ様でした!Javaのコードが出てきて戸惑った方もいるかもしれませんが、問われているのはセキュアコーディングの基本的な考え方です。

  • 例外処理: 例外が発生したときに、システムが危険な状態(平文パスワードを保存するなど)に陥らないよう、処理を安全に中断させる。
  • ログ出力: ログにパスワードなどの重要情報を平文で出力しない。
  • パスワード保存: ハッシュ化はもちろん、ソルトを使ってレインボーテーブル攻撃対策を行う。
  • リソース管理: finally 句などを使って、確保したリソースは必ず解放する。

これらの原則は、言語が変わっても通用する普遍的なものです。今回の問題を通して、ぜひセキュアコーディングの「勘所」を身につけてくださいね!