令和5年度 春期 情報処理安全確保支援士試験 午後Ⅰ 問題 問1 静的解析とレースコンディションのセキュアプログラミング

テクノロジアルゴリズムセキュリティ技術データベース

この問題は2023(R5)春 情報処理安全確保支援士 午後Iに出題されたものです。出題時点の法令・制度に基づく内容のため、現行の内容と一致しない場合があります。

本ページの問題文・選択肢は、原本の体裁を Web 表示用に正規化しています(改行・記号・数式・図表参照の調整)。設問の趣旨および正解に影響する変更は加えていません。

学習ガイド

Javaで実装した注文システムの脆弱性と並行処理の不具合を扱う問題です。入力値の文字列連結と、static変数による状態共有を別の原因として整理します。PreparedStatementによる修正、レースコンディションの発生過程、得意先コードを使う追加対策を順に解説します。本文・表・図の根拠を行き来し、用語だけを暗記するのではなく、短い記述にも判断の理由を残して解答する手順を示します。

この記事で押さえる論点

  • 静的解析の指摘(SQLインジェクション・ディレクトリトラバーサル・リソース解放漏れ)をソースコードの行番号に対応付けられる
  • PreparedStatementによるプレースホルダ化を修正前後のコードで書き分けられる
  • static変数の共有がレースコンディションを生む仕組みをサーブレットの並列動作から説明できる
  • E-R図を使い、注文番号に加える保険的な抽出条件として得意先コードを導ける

問題本文

問1 Webアプリケーションプログラム開発に関する次の記述を読んで,設問に答えよ。

G社は,システム開発を行う従業員100名のSI企業である。このたび,オフィス用品を販売する従業員200名のY社から,システム開発を受託した。開発プロジェクトのリーダーには,G社の開発課のD主任が任命され,メンバーには,開発課から,Eさんと新人のFさんが任命された。G社では,セキュリティの品質を担保するために,プログラミング完了後にツールによるソースコードの静的解析を実施することにしている。

〔受託したシステムの概要〕

受託したシステムには,Y社の得意先がオフィス用品を注文する機能,Y社とY社の得意先が注文履歴を表示させる機能,Y社とY社の得意先が注文番号を基に注文情報を照会する機能(以下,注文情報照会機能という),Y社とY社の得意先が納品書のPDFファイルをダウンロードする機能などがある。

〔ツールによるソースコードの静的解析〕

プログラミングが完了し,ツールによるソースコードの静的解析を実施したところ,Fさんが作成した納品書PDFダウンロードクラスのソースコードに問題があることが分かった。納品書PDFダウンロードクラスのソースコードを図1に,静的解析の結果を表1に示す。

図1 納品書 PDF ダウンロードクラスのソースコード
図の説明テキスト

図1 納品書 PDF ダウンロードクラスのソースコード
(省略) //package宣言,import宣言など
1: public class DeliverySlipBL {
2: private static final String PDF_DIRECTORY = "/var/pdf"; //PDFディレクトリ定義
(省略) //変数宣言など
3: public DeliverySlipBean getDeliverySlipPDF(String inOrderNo, Connection conn) {
(省略) //変数宣言など
4: DeliverySlipBean deliverySlipBean = new DeliverySlipBean();
5: try {
/* 検索用SQL文作成 */
6: String sql = "SELECT ";
7: sql = sql + (省略); //抽出項目,テーブル名など

図1 納品書 PDF ダウンロードクラスのソースコード(続き)
図の説明テキスト

図1 納品書 PDF ダウンロードクラスのソースコード(続き)
8: sql = sql + " WHERE head.order_no = '" + inOrderNo + "' ";
9: sql = sql + (省略); //抽出条件の続き
10: Statement stmt = conn.createStatement();
11: ResultSet resultObj = stmt.executeQuery(sql);
(省略) //注文情報の存在チェック (存在しないときはnullを返してメソッドを終了)
12: String clientCode = resultObj.getString("client_code"); //得意先コード取得
13: File fileObj = new File(PDF_DIRECTORY + "/" + clientCode + "/" + "DeliverySlip"
+ inOrderNo + ".pdf");
(省略) //PDFファイルが既に存在しているかの確認など
14: BufferedInputStream in = new BufferedInputStream(new FileInputStream(fileObj));
15: byte[] buf = new byte[in.available()];
16: in.read(buf);
17: deliverySlipBean.setFileByte(buf);
18: } catch (Exception e) {
(省略) //エラー処理 (ログ出力など)
19: }
20: return deliverySlipBean;
21: }
(省略)

表1 静的解析の結果
図の説明テキスト

表1 静的解析の結果

項番 脆弱性 指摘箇所 指摘内容
1 SQLインジェクション (省略) (省略)
2 ディレクトリトラバーサル a 行目 ファイルアクセスに用いるパス名の文字列作成で、利用者が入力したデータを直接使用している。
3 確保したリソースの解放漏れ (省略) 変数 stmt, 変数 resultObj, 変数 b が指すリソースが解放されない。

この解析結果を受けて,Fさんは,Eさんの指導の下,ソースコードを修正した。
表1の項番1について図1の8行目から11行目を図2に示すソースコードに修正した。項番2と項番3についてもソースコードを修正した。

図2 納品書 PDF ダウンロードクラスの修正後のソースコード
図の説明テキスト

図2 納品書 PDF ダウンロードクラスの修正後のソースコード
sql = sql + " c ";
sql = sql + (省略); //抽出条件の続き
d ;
stmt.setString(1, inOrderNo);
ResultSet resultObj = stmt.executeQuery();

再度,ツールによるソースコードの静的解析が実施され,表1の指摘は解消していることが確認された。

〔システムテスト〕

システムテストを開始したところ,注文情報照会機能において不具合が見つかった。この不具合は,ある得意先の利用者IDでログインして画面から注文番号を入力すると,別の得意先の注文情報が出力されるというものであった。なお,ログイン処理時に,ログインした利用者IDと,利用者IDにひも付く得意先コード及び得意先名はセッションオブジェクトに保存されている。

注文情報照会機能には,業務処理を実行するクラス(以下,ビジネスロジッククラスという)及びリクエスト処理を実行するクラス(以下,サーブレットクラスという)が使用されている。注文情報照会機能が参照するデータベースのE-R図を図3に,Eさんが作成したビジネスロジッククラスのソースコードを図4に,サーブレットクラスのソースコードを図5に示す。

図3 注文情報照会機能が参照するデータベースの E-R 図
図の説明テキスト

図3 注文情報照会機能が参照するデータベースの E-R 図

エンティティと属性:

  • 利用者マスター:利用者ID(主キー)、利用者名、得意先コード(外部キー)、パスワードソルト、パスワードハッシュ、...
  • 得意先マスター:得意先コード(主キー)、得意先名、郵便番号、住所、電話番号、...
  • 注文ヘッダーテーブル:注文番号(主キー)、注文日時、得意先コード(外部キー)、注文総額、消費税額、...
  • 注文明細テーブル:注文番号(主キーの一部)、注文明細番号(主キーの一部)、商品コード(外部キー)、数量、...

リレーションシップ(1対多の矢印):

  • 得意先マスター から 利用者マスター へ(得意先コードをキーとする参照)
  • 得意先マスター から 注文ヘッダーテーブル へ(得意先コードをキーとする参照)
  • 注文ヘッダーテーブル から 注文明細テーブル へ(注文番号をキーとする参照)

凡例と注記:

  • 矢印は「1対多」を示す。
  • 注記1:属性名の実線の下線は主キーを、破線の下線は外部キーを示す。主キーの実線が付いている属性名には、外部キーの破線を付けていない。
  • 注記2:主キー及び外部キーは、全て表記している。
図4 ビジネスロジッククラスのソースコード
図の説明テキスト

図4 ビジネスロジッククラスのソースコード
(省略) //package宣言, import宣言など
1: public class OrderInfoBL {
2: private static String orderNo; //注文番号
/* 注文番号の設定メソッド /
3: public static void setOrderNo(String inOrderNo) {
4: orderNo = inOrderNo;
5: }
/
注文情報の取得メソッド */
6: public static OrderInfoBean getOrderInfoBean() {
7: PreparedStatement psObj;
(省略) //try文, 変数定義など
8: String sql = "SELECT ";
9: sql = sql + (省略); //SQL文構築
10: sql = sql + " WHERE head.order_no = ?"; //抽出条件: 注文ヘッダーテーブルの注文番号と画面から入力された注文番号との完全一致
(省略) //PreparedStatementの作成
11: psObj.setString(1, orderNo); //検索キーに注文番号をセット
12: ResultSet resultObj = psObj.executeQuery();
(省略) //例外処理やその他の処理

図5 サーブレットクラスのソースコード
図の説明テキスト

図5 サーブレットクラスのソースコード
(省略) //package宣言, import宣言など
1: public class OrderInfoServlet extends HttpServlet {
(省略) //変数定義
2: public void doPost(HttpServletRequest reqObj, HttpServletResponse resObj) throws IOException, ServletException {
3: String orderNo; //注文番号
(省略) //try文, リクエストから注文番号を取得
4: OrderInfoBL.setOrderNo(orderNo);
5: OrderInfoBean orderInfoBeanObj = OrderInfoBL.getOrderInfoBean();
(省略) //例外処理やその他の処理

D主任,Eさん,Fさんは,不具合の原因が特定できず,セキュアプログラミングに詳しい技術課のHさんに協力を要請した。

Hさんはアプリケーションログ及びソースコードを解析し,不具合の原因を特定した。原因は,図4で変数 ef として宣言されていることである。この不具合は,並列動作する複数の処理が同一のリソースに同時にアクセスしたとき,想定外の処理結果が生じるものである。

原因を特定することができたので,Eさんは,Hさんの支援の下,次の4点を行った。

(1) 図4の2行目から5行目までのソースコードを削除する。
(2) 図4の6行目を,図6に示すソースコードに修正する。

図6 ビジネスロジッククラスの修正後のソースコード
図の説明テキスト

図6 ビジネスロジッククラスの修正後のソースコード
public OrderInfoBean getOrderInfoBean( g ) {

(3) 図5の4行目と5行目を,図7に示すソースコードに修正する。

図7 サーブレットクラスの修正後のソースコード
図の説明テキスト

図7 サーブレットクラスの修正後のソースコード
OrderInfoBL orderInfoBLObj = h OrderInfoBL();
OrderInfoBean orderInfoBeanObj = orderInfoBLObj.i ;

(4) 保険的な対策として,図4の10行目の抽出条件に,セッションオブジェクトに保存された j と注文ヘッダーテーブルの j の完全一致の条件を AND 条件として追加する。

ソースコードの修正後,改めてシステムテストを実施した。システムテストの結果は良好であり,システムがリリースされた。

設問と解答・解説

設問1

〔ツールによるソースコードの静的解析〕について答えよ。

(1)

表1中の a に入れる適切な行番号を,図1中から選び,答えよ。

模範解答

13

採点基準(配点 5点)

正確性(内容)(5点)

  • 5: セキュアプログラミングの観点から、SQLインジェクションの脆弱性が存在する行番号「13」を正確に抜き出している。
  • 3: 「13行目」など正解を含むが、不要な文字が含まれている。
  • 0: 不正解、または無解答。

解説

ツールによるソースコードの静的解析において、SQLインジェクションの脆弱性が指摘される行を答える問題です。

  1. 図1のプログラムにおいて、外部からの入力値が直接SQL文に連結されている箇所を探します。
  2. 13行目では、sql += " WHERE head.order_no = '" + in + "'"; のように、入力値 in がSQL文の一部として文字列連結されており、これが脆弱性の原因となります。

高得点のポイント

  • 脆弱性の原因となっている正確な行番号「13」を本文(図1)から抜き出していること。

(2)

表1中の b に入れる適切な変数名を,図1中から選び,答えよ。

模範解答

in

採点基準(配点 5点)

正確性(内容)(5点)

  • 5: セキュアプログラミングの観点から、外部入力値が格納される変数名「in」を正確に抜き出している。
  • 3: 正解を含むが、不要な文字が含まれている。
  • 0: 不正解、または無解答。

解説

静的解析ツールによって指摘された、外部から入力された汚染データが格納されている変数を答える問題です。

  1. 図1のプログラムを確認すると、HTTPリクエストパラメータから値を取得している箇所があります。
  2. String in = req.getParameter("ORDER_NO"); において、外部入力値は変数 in に格納されています。
  3. この in がそのままSQL文に連結されているため、指摘対象の変数となります。

高得点のポイント

  • 外部からの入力値を受け取っている変数名「in」を正確に抜き出していること。

(3)

図2中の c に入れる適切な字句を答えよ。

模範解答

WHERE head.order_no = ?

採点基準(配点 5点)

知識・理解度(内容)(3点)

  • 3: セキュリティ不具合への対処として、プレースホルダ(?)を用いた条件指定が正しく理解できている。
  • 1: プレースホルダの概念は理解しているが、記述に軽微な誤りがある。
  • 0: プレースホルダを用いた対策が理解できていない。

論理性(構造)(2点)

  • 2: SQLの構文として、修正前後で整合性の取れたWHERE句を論理的に構成できている。
  • 1: 構造的に不自然な箇所があるが、意図は読み取れる。
  • 0: 構文として成立していない。

解説

SQLインジェクション対策として、プレースホルダを用いたSQL文への修正を行う問題です。

  1. 修正前のプログラム(図1)では、WHERE head.order_no = ' + in + ' と文字列連結で条件を指定していました。
  2. プレースホルダ(?)を使用することで、パラメータを安全にバインドできます。
  3. したがって、SQL文の該当部分は WHERE head.order_no = ? と記述するのが適切です。

高得点のポイント

  • プレースホルダ ? を用いた正しいSQLのWHERE句を記述できていること。
  • Javaプログラムにおけるセキュアなデータベースアクセスの基本を理解していること。

(4)

図2中の d に入れる適切な字句を答えよ。

模範解答

PreparedStatement stmt = conn.prepareStatement(sql)

採点基準(配点 5点)

知識・理解度(内容)(3点)

  • 3: セキュアプログラミングの基本である「PreparedStatement」の使用を正確に理解し記述できている。
  • 1: PreparedStatementを使う方針は理解しているが、クラス名やメソッド名に誤りがある(例: Statementと記述するなど)。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: Javaの文法として、適切な型の変数宣言とメソッド呼び出しが論理的に構成されている。
  • 1: 文法に軽微な誤りがあるが、処理の意図は伝わる。
  • 0: 文法として成立していない。

解説

SQLインジェクションを防ぐため、安全なデータベースアクセスクラスを利用する記述を答える問題です。

  1. セキュアプログラミングの基本として、Statement ではなく PreparedStatement を使用します。
  2. コネクション conn からプレースホルダを含む sql を用いてオブジェクトを生成します。
  3. PreparedStatement stmt = conn.prepareStatement(sql) が適切な字句となります。

高得点のポイント

  • PreparedStatement クラスを使用していること。
  • メソッド名 prepareStatement と引数 sql を正確に記述できていること。

設問1(3)は,正答率が低かった。“PreparedStatement”とすべきところを“Statement”と解答した受験者が多かった。“PreparedStatement”を使う方法は,セキュアプログラミングの基本であり,理解してほしい。

設問2

〔システムテスト〕について答えよ。

(1)

本文中の e に入れる適切な変数名を,図5中から選び,答えよ。

模範解答

orderNo

採点基準(配点 5点)

正確性(内容)(5点)

  • 5: セキュアプログラミングにおけるシステムテストの観点から、該当する変数名「orderNo」を正確に抜き出している。
  • 3: 正解を含むが、不要な文字が含まれている。
  • 0: 不正解、または無解答。

解説

システムテストで発見された不具合に関連し、セッションで保持されている情報を特定する問題です。

  1. Webアプリケーションにおいて、ユーザーの操作対象を識別するために変数を使用しています。
  2. 図5などの記述から、対象となる注文番号を保持している変数は orderNo であることがわかります。

高得点のポイント

  • 本文・図中から該当する変数名「orderNo」を正確に抜き出していること。

(2)

本文中の f に入れる適切な字句を,英字10字以内で答えよ。

模範解答

static

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: マルチスレッド環境における変数の共有問題を引き起こす「static」修飾子を正しく理解している。
  • 1: 意図は理解できるが、適切な修飾子を正確に指定できていない。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: プログラムの構造上、状態が共有されてしまう原因となる宣言方法を論理的に整合する形で回答している。
  • 1: 構造的な理解が不十分な回答。
  • 0: 回答が文脈と整合していない。

解説

サーブレットにおけるマルチスレッド環境特有の不具合原因を特定する問題です。

  1. Java Servletはマルチスレッドで動作するため、インスタンス変数として宣言された変数は複数のスレッドから共有されます。
  2. クラス変数(static 修飾子が付けられた変数)として宣言されている場合、すべてのリクエスト間で変数が共有され、状態の意図しない上書きが発生します。
  3. したがって、原因となる字句は static です。

高得点のポイント

  • スレッド間で共有される変数の性質(static)を理解していること。
  • 「英字10字以内」の指定に従い記述していること。

(3)

本文中の下線①の不具合は何と呼ばれるか。15字以内で答えよ。

模範解答

レースコンディション

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: 複数スレッド環境における不具合の名称として「レースコンディション」を正確に理解している。
  • 1: 競合状態などの同義語を記述しており、意味は理解している。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: 問題文で問われている事象に対して、整合する用語を論理的に提示できている。
  • 1: 文脈には沿っているが、用語としてやや不適切な表現となっている。
  • 0: 文脈に合致していない。

解説

複数スレッドからの同時アクセスによって引き起こされる不具合の名称を答える問題です。

  1. 共有リソースに対して複数のスレッドが同時にアクセス・変更を行うことで、実行のタイミングによって結果が変わってしまう状態を レースコンディション(競合状態) と呼びます。
  2. この不具合は個人情報漏えいなど深刻なセキュリティインシデントにつながる可能性があります。

高得点のポイント

  • 不具合の名称「レースコンディション」を15字以内で正確に記述していること。

(4)

図6中の g に入れる適切な字句を答えよ。

模範解答

String orderNo

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: スレッドセーフな実装において、共有変数を排除し引数として情報を渡す方法を理解し、「String orderNo」と記述できている。
  • 1: 変数名のみ、あるいは型のみなど、部分的に正しい。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: Javaのメソッドシグネチャとして論理的に正しい構文になっている。
  • 1: 構文に軽微な誤りがあるが、意図は読み取れる。
  • 0: 構文として成立していない。

解説

スレッドセーフなプログラムへ修正するにあたり、メソッドの引数として渡すべき適切な変数を記述する問題です。

  1. 共有変数(フィールド変数)を使わずに、必要な情報をメソッド間の引数として受け渡しする設計に変更します。
  2. 該当メソッドは注文番号を受け取る必要があるため、引数として String orderNo を定義するのが適切です。

高得点のポイント

  • 引数の型(String)と変数名(orderNo)を正確に記述できていること。

(5)

図7中の h に入れる適切な字句を答えよ。

模範解答

new

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: ローカル変数としてのインスタンス生成の必要性を理解し、「new」演算子を記述できている。
  • 1: 意図は理解できるが、記述に誤りがある。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: Javaのインスタンス生成の構文として論理的に正しく構成されている。
  • 1: 文脈には沿っているが、構文的に不自然な点がある。
  • 0: 構文として成立していない。

解説

スレッドセーフにするために、リクエストごとに新しくインスタンスを生成する記述を答える問題です。

  1. フィールドで共通のインスタンスを使い回すのではなく、メソッド内のローカル変数としてインスタンス化する必要があります。
  2. Javaにおいてインスタンスを生成するための演算子は new です。

高得点のポイント

  • インスタンス生成のための演算子「new」を正確に記述できていること。

(6)

図7中の i に入れる適切な字句を答えよ。

模範解答

getOrderInfoBean(orderNo)

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: 引数を用いたメソッド呼び出しによるスレッドセーフな情報の受け渡しを理解し、「getOrderInfoBean(orderNo)」と記述できている。
  • 1: メソッド名のみ、あるいは引数が不足しているなど、部分的に正しい。
  • 0: 不正解、または無解答。

論理性(構造)(2点)

  • 2: 前後の処理の流れに沿った正しいメソッド呼び出し構造となっている。
  • 1: 文脈には沿っているが、構文に軽微な誤りがある。
  • 0: 構文として成立していない。

解説

スレッドセーフに修正されたクラスにおいて、正しいメソッド呼び出しを記述する問題です。

  1. 修正前のプログラムでは引数なしのメソッドが呼ばれていた可能性がありますが、修正後は引数として情報を渡す必要があります。
  2. 該当インスタンスに対して、変数 orderNo を引数に渡して getOrderInfoBean(orderNo) と呼び出します。

高得点のポイント

  • 適切なメソッド名と、必要な引数 orderNo を含めてメソッド呼び出しを記述できていること。

(7)

本文中の j に入れる適切な属性名を,図3中から選び,答えよ。

模範解答

得意先コード

採点基準(配点 5点)

正確性(内容)(5点)

  • 5: 認可制御の保険的対策として適切な属性名「得意先コード」を正確に抜き出している。
  • 3: 正解を含むが、不要な文字が含まれている。
  • 0: 不正解(例: 「注文番号」と解答している等)、または無解答。

解説

強制ブラウジングなどの認可制御の不備に対する、保険的対策となる抽出条件を答える問題です。

  1. 注文番号だけで検索を行うと、他人の注文番号を推測・入力された場合に他人の情報を閲覧されてしまう危険性があります。
  2. これを防ぐため、ログインしているユーザー自身の情報であることを担保する条件を追加します。
  3. E-R図(図3)とJavaソースコードから、セッションに保存されたログインユーザーの「得意先コード」と、注文情報の「得意先コード」が一致するかを検証することが適切な保険的対策となります。

高得点のポイント

  • 認可制御の観点から、他人のデータアクセスを防ぐために必要な属性名「得意先コード」を図3から正確に抜き出していること。

設問2(3)は,正答率が低かった。“レースコンディション”は個人情報漏えいなどにつながる可能性があるので,設計,実装,テストでの対策を確認しておいてほしい。設問2(5)は,正答率がやや高かったが,“注文番号”と解答した受験者が見受けられた。注文番号は既に抽出条件に入っているので,E-R図とJavaソースコードから,保険的対策として適切な抽出条件を導き出す方法を理解してほしい。