情報処理安全確保支援士過去問題 令和5年春期 午後Ⅰ 問1
⇄問題文と設問を画面2分割で開く⇱問題PDF出題趣旨
Javaで実装されたWebアプリケーションプログラムに対して,ツールによるソースコードの静的解析やセキュリティ観点からのシステムテストの実施はセキュリティの不備を発見するのに有効である。本問では,Webアプリケーションプログラム開発を題材として,静的解析やシステムテストで発見されたセキュリティ上の不具合への対処を踏まえたセキュアプログラミングに関する能力を問う。
設問1
- a: 13
- b: in
- c: WHERE head.order_no = ?
- d: PreparedStatement stmt = conn.prepareStatement(sql)
- 〔aについて〕
ディレクトリトラバーサルは、ユーザーが入力したファイル名をパラメータとして受け取り、それをもとに処理を行うアプリケーションに対して行われる攻撃手法です。IPAの「安全なウェブサイトの作り方 改訂第7版」では、外部からのパラメータでファイル名を直接指定する実装を避けることが対策と紹介されています。
表1項番2の指摘内容には「ファイルアクセスに用いるパス名の文字列作成で利用者が入力したデータを直接使用している」とあります。図1の13行目にて納品書PDFを参照するパスを文字列結合にて生成しています。これが指摘内容に該当します。〔受託したシステムの概要〕には「Y社とY社の得意先が注文番号を基に注文情報を照会する機能(中略)Y社とY社の得意先が納品書のPDFファイルをダウンロードする機能などがある」と記載されています。これにより、利用者が注文番号を入力して納品書PDFをダウンロードする操作を行うことが読み取れます。変数 inOrderNo にユーザーが入力した注文番号が格納されると考えられるので、指摘内容とも一致します。したがって、空欄aには「13」が入ります。
∴a=13 - 〔bについて〕
Javaではデータベース接続やファイルなどのメモリ以外のリソースはガーベジコレクションによって解放されません。リソースが解放されない状態が続くとメモリが枯渇するおそれがあります。リソースを解放するには、finally句にてcloseメソッドを用いて明示的に解放する方法があります。図1の14行目で納品書PDFに書き込むためのリソースを変数 in に格納していますが、他の箇所にcloseメソッドなどでリソースを解放するコードが見当たりません。したがって、空欄bには「in」が入ります。
∴b=in - 〔cについて〕
SQLインジェクション攻撃は、利用者から入力情報を基にSQL文を組み立てる処理に問題がある場合、攻撃者が入力したSQLがデータベース上でそのまま実行されてしまい、データベースに蓄積された情報の改ざんや非公開情報の閲覧ができてしまう攻撃です。解決策として、IPAの「安全なウェブサイトの作り方 改訂第7版」では、SQL文の組み立てはすべてプレースホルダで実装する方法と、特別な意味を持つ記号文字(「`」や「¥」)をエスケープ処理する方法が紹介されています。プレースホルダとは、利用者入力部分に特殊文字(?など)を割り当てたSQLのひな形を用意し、特殊文字部分には実行時にエスケープ処理された値を割り当てる仕組みです。
図1の8行目では、変数 inOrderNo を文字列結合してSQL文を生成しています。変数 inOrderNo にはエスケープされていない入力値が格納されているので、SQLインジェクションの脆弱性があります。よって、プレースホルダでSQL文を組み立てるコードに修正します。「WHERE head.order_no = 」までは書き写せば十分です。しかし、「inOrderNo」の値は実行時に決まるのでプレースホルダで置き換えます。したがって、空欄cは「WHERE head.order_no = ?」となります。
∴c=WHERE head.order_no = ?
〔dについて〕
Javaでプリペアドステートメントを利用するには、java.sql.ConnectionのpreparedStatement メソッドを用いて PreparedStatement インタフェースのオブジェクトを生成します。引数にはプレースホルダを含むSQL文を指定します。したがって、空欄dは「PreparedStatement stmt = conn.preparedStatement(sql)」となります。
∴d=PreparedStatement stmt = conn.prepareStatement(sql)
設問2
- e: orderNo
- f: static
- レースコンディション
- g: String orderNo
- h: new
- i: getOrderInfoBean(orderNo)
- j: 得意先コード
- 〔eについて〕
空欄eの前に書かれている不具合の詳細を確認すると、「ある得意先の利用者IDでログインしてから注文番号を入力すると,別の得意先の注文情報が出力される」とあります。図4の注文番号から注文情報を選択するソースコードを変数に格納される値を意識しながら読んでいきます。- 変数 orderNo をクラス変数(後述)として宣言(2行目)
- サーブレットクラスから受け取った注文番号を変数 orderNo に格納(4行目)
- 注文情報を取得するSQLをプリペアドステートメントで組み立てる(8~10行目)
- 10行目のプレースホルダに注文番号を当てはめて、注文ヘッダーテーブルの注文番号との完全一致で注文情報を取得(11~12行目)
∴e=orderNo
- 〔fについて〕
変数 orderNo がどのような変数か答える問題です。Javaの変数は❶クラス変数、❷インスタンス変数、❸ローカル変数の3種類があります。- クラス変数
- 一つのクラスごとに値を共有する変数。staticキーワードをつけて宣言する
- インスタンス変数
- 一つのインスタンスごとに値を保持する変数
- ローカル変数
- メソッド(関数)やブロック({ … })の内側でのみ利用できる変数
∴f=static
- (1)の不具合のように、複数のスレッド(マルチスレッド)で動作するアプリケーションにて複数のスレッドが同じデータをほぼ同じに更新すると、(本来は予期しない)後続の処理が先行する処理の結果を上書きしてしまう現象が発生します。これを「レースコンディション」といいます。スレッド間でのリソースのアクセス順序が重要であり、実行のタイミングによって異なる結果が生じる場合にレースコンディションが発生します。
∴レースコンディション - 〔gについて〕
図6のソースコードでは注文情報を取得する getOrderInfoBean メソッドを修正しています。(2)の空欄fおよび(3)より、変数 orderNo をローカル変数に修正すればレースコンディションの脆弱性を回避できます。ローカル変数に修正するには、(1)の通りに2行目から5行目のソースコードを削除したのち、getOrderInfoBean メソッドを注文番号を引数とするメソッドに修正します。Javaでは引数は「引数の型 引数名」の形式で宣言します。引数の型は図5の3行目より String、引数名は図4の11行目より orderNo です。したがって、空欄gは「String orderNo」となります。
∴g=String orderNo
〔hについて〕
空欄hを含むコードは OrderInfoBL クラスのインスタンスを生成するものです。Javaではインスタンスを生成する際には「new クラス名」の形式を使用します。したがって、空欄hには「new」が入ります。
∴h=new
〔iについて〕
修正前の図5の5行目のコードでは、OrderInfoBL クラスのクラスメソッド getOrderInfoBean を利用して注文情報を取得しています。空欄gの解説で述べたように、修正後の getOrderInfoBean メソッドでは、注文番号を格納した変数を引数に指定します。getOrderInfoBean メソッドを呼び出すコードが書かれている図5を見ると、3行目と直後のコメントには、注文番号は変数 orderNo に格納されることが書かれていますので、この変数を引数に指定すればよいことがわかります。したがって、空欄iには「getOrderInfoBean(orderNo)」が入ります。
∴i=getOrderInfoBean(orderNo) - 〔jについて〕
〔システムテスト〕によるとセッションオブジェクトには、利用者ID、得意先コード、得意先名が格納されています。また、注文ヘッダーテーブルのE-R図には「得意先コード」があります。よって、以下の流れで実装すれば(4)の保険的対策が可能です。- 10行目の抽出条件に、注文ヘッダーテーブルの得意先コードとの完全一致条件をAND条件として追加する。得意先コードの値が割り当てられる部分には10行目と同じくプレースホルダを指定する
- 得意先コードをセッションオブジェクトから取り出して変数に格納する
- psObj.setString(2, 得意先コードを格納した変数)のようにプレースホルダに得意先コードの値を割り当てる
∴j=得意先コード