情報処理安全確保支援士 2014年 春期 午後1 問01
Webアプリケーションに関する次の記述を読んで、設問1〜3に答えよ。
B社は、従業員数50名のインターネットサービス企業であり、インターネット上で各種の情報サービスを提供している。これらのサービスの実現に当たり、必要なアプリケーションを自社開発してきた。このたびB社では、画像ファイルを対象としたオンライン共有ストレージサービス(以下、Sサービスという)を立ち上げることにし、R部長を責任者としてアプリケーション開発に着手した。Sサービスの画面には広告主のサイトへのリンクを含んだバナー広告を掲載し、利用者からの利用料収入に加えて広告料収入の獲得も目指す。
〔Sサービスの要件定義〕
B社では、P主任を中心としてSサービスの要件を検討した。検討の結果、P主任はSサービスの要件案を図1に示すとおりまとめた。

この要件案は、レビューされた後、R部長によって承認された。
〔システム・ソフトウェア要件定義〕
その後、Q主任を中心としてシステム・ソフトウェア要件定義を実施した。その結果、SサービスはJavaサーブレットを利用したWebアプリケーションで構成することにした。画像処理プログラムについてはC++で記述し、プログラム内ではCベースの画像処理ライブラリであるV-libを利用することにした。JavaからC++プログラムを呼び出す際には、JNI(Java Native Interface)を利用することにした。
〔ソフトウェアの基本設計〕
システム・ソフトウェア要件定義が完了し、ソフトウェアの基本設計を開始した。その中で、V君はWebアプリケーションのセッション管理の方式について検討した。
次は、検討に際してのQ主任とV君との会話である。
Q主任:HTTPセッション管理には、どのような方式を採用するつもりかな。
V君 :セッション管理には、ログオン時にランダム文字列をセッションIDとして割り当てた上で、クエリパラメタの中にセッションIDを格納する方式を採用するつもりです。
Q主任:当社でも実績のある方式だね。ただ、今回はHTTPSだけでなくHTTPも使用できるようにするから、GETメソッドではなくPOSTメソッドを使用しておかないと、①HTTPヘッダ内のフィールドが原因で、バナー広告に設定されたリンク先のWebサーバへセッションIDが漏えいすることが考えられるね。
更に基本設計が進む中で、実行形式ファイルがアップロードされるとウイルスの温床になりかねないという指摘があった。議論した結果、この指摘への対策の一つとして、アップロードするファイルの拡張子を画像ファイルのものに制限することとした。制限する方式として、V君は、Webブラウザにおいてスクリプトによって判定することを考えた。この方式を実装したスクリプトを含むHTMLファイル例を図2に示す。この方式案について相談を受けたQ主任は、②契約者の操作によっては、拡張子が画像ファイルのものでないファイルがアップロードできてしまうという問題点を指摘し、制限する方式には③スクリプトによらない方式を検討するよう指示した。V君はその後、異なる方式を提案し、採用に至った。

〔画像処理プログラムでの不具合〕
基本設計及び詳細設計が無事完了し、U主任を中心としたグループでプログラムの作成を開始した。U主任は、サムネイル表示の際に使用するために、様々なファイル形式の画像ファイルを縦横とも128ピクセルに変換する画像処理プログラム(以下、ピクセル数変換プログラムという)の作成をT君に指示した。T君は、最初に、複数のファイル形式の中からファイル形式Zを選択して、ピクセル数変換プログラムの作成に取り掛かった。
このプログラムで取り扱う、ファイル形式Zを図3に示す。ピクセル数変換そのものには、V-lib内のvlibResize関数を使用することにした。V-lib内で定義され、vlibResize関数の引数として使用するvlibMat構造体の説明を図4に示す。また、vlibResize関数の外部仕様を図5に示す。



T君は、図6のピクセル数変換プログラムを作成し、U主任によるソースコードレビューを受けた。そのソースコードレビューで、U主任は、入力する画像ファイルの内容によっては38行目においてaが発生し、その結果として50行目においてbが発生することを指摘した。
なお、この処理系において、int型は4バイト、short int型は2バイト、char型は1バイトである。また、char型は特に記述がなければ符号なしである。

T君はこの指摘を受けて、図6の37行と38行の間に図7に示す行を追加し、再度U主任のソースコードレビューを受けた。ソースコードレビューの結果、指摘された問題点が修正されていること、他の部分に同種の問題点が存在しないことが確認された。

その後、全てのプログラムの作成とテストが完了して、B社はSサービスの運用を開始することができた。
設問1:〔ソフトウェアの基本設計〕について(1)〜(3)に答えよ。
(1)本文中の下線①のHTTPヘッダ内のフィールド名は何か。英字10字以内で答えよ。
模範解答
Referer
解説
解答の論理構成
- 問題文では、「GETメソッドではなくPOSTメソッドを使用しておかないと、①HTTPヘッダ内のフィールドが原因で、バナー広告に設定されたリンク先のWebサーバへセッションIDが漏えいする」 と記載されています。
- GET メソッドでセッション ID をクエリパラメタに埋め込むと、リンク遷移時に現在閲覧している URL(=セッション ID 付き)が外部サイトへ伝わる仕組みが存在します。
- ブラウザはリンクをクリックした際、HTTP リクエストに元ページの URL を示す Referer ヘッダを自動付与します。これにより外部サイトに「どのページから来たか」が通知されます。
- クエリパラメタにセッション ID が含まれていれば、そのまま Referer ヘッダに載ってしまい漏えいします。
- 以上から、下線部①の “HTTPヘッダ内のフィールド” は Referer であると導けます。
誤りやすいポイント
- Cookie と混同する
セッション ID を Cookie で管理する場合はブラウザが外部サイトに送信しないため本問の漏えいは起きません。 - フィールド名の綴り
正しくは “Referrer” ではなく HTTP 仕様どおり “Referer” と綴ります。 - Location ヘッダの誤認
Location はサーバ側が返す応答ヘッダであり、今回の「ブラウザ→外部サイト」送信ヘッダではありません。
FAQ
Q: なぜ POST メソッドなら漏えいしないのですか?
A: POST 方式でも Referer は送信されますが、セッション ID をクエリパラメタで渡さず HTTP ボディに含めるため Referer 内にセッション ID が現れません。
A: POST 方式でも Referer は送信されますが、セッション ID をクエリパラメタで渡さず HTTP ボディに含めるため Referer 内にセッション ID が現れません。
Q: Cookie でセッション管理すれば完全に安全ですか?
A: 参照先が同一サイトなら安全ですが、Cookie が盗まれる別のリスク(XSS など)が残るため、安全策としては HTTPS と Secure 属性付き Cookie の併用が望まれます。
A: 参照先が同一サイトなら安全ですが、Cookie が盗まれる別のリスク(XSS など)が残るため、安全策としては HTTPS と Secure 属性付き Cookie の併用が望まれます。
Q: Referer ヘッダを無効にする設定でも対策できますか?
A: ブラウザやMETAタグ、Content-Security-Policy で制御可能ですが、利用者全員に強制はできないためサーバ側設計での対策(POST+Cookie など)が基本となります。
A: ブラウザやMETAタグ、Content-Security-Policy で制御可能ですが、利用者全員に強制はできないためサーバ側設計での対策(POST+Cookie など)が基本となります。
関連キーワード: HTTPヘッダ、Referer, セッションID, クエリパラメタ、情報漏えい
設問1:〔ソフトウェアの基本設計〕について(1)〜(3)に答えよ。
(2)本文中の下線②の契約者の操作とは何か。30字以内で述べよ。
模範解答
ブラウザの設定でスクリプトを無効化する。
解説
解答の論理構成
- 問題文には、ファイル拡張子の判定を「③スクリプトによらない方式」に変更せよとあります。
- その理由として、Q主任が「②契約者の操作によっては、拡張子が画像ファイルのものでないファイルがアップロードできてしまう」と指摘しています。
- 図2の HTML では
- つまり JavaScript が動かない状態ではチェックが行われません。JavaScript を動かなくする典型的な「契約者の操作」はブラウザ側でスクリプトを無効化することです。
- 従って下線②の操作は「ブラウザの設定でスクリプトを無効化する」となります。
誤りやすいポイント
- 「ファイル名を変更する」と勘違いしやすいですが、ファイル名変更はスクリプト判定後にサーバ側が再検証すれば防げるため、設問の趣旨とずれます。
- 「HTTP を直接叩く」と解釈すると余分な想定になります。問題文の指摘は JavaScript 依存のチェックに潜む単純な盲点を問うています。
- 「ブラウザの拡張機能で改ざん」と考えると複雑化しますが、基本動作として JavaScript を無効化できることを見落としやすいです。
FAQ
Q: JavaScript を無効化する利用者は少ないのでは?
A: セキュリティポリシやアドオンで無効化する例は実際に存在し、Web アプリは想定すべきです。
A: セキュリティポリシやアドオンで無効化する例は実際に存在し、Web アプリは想定すべきです。
Q: サーバ側で MIME タイプを確認すれば良いのでは?
A: はい。そのような「③スクリプトによらない方式」として、サーバ側で拡張子・MIME・マジックナンバーを検証するのが一般的です。
A: はい。そのような「③スクリプトによらない方式」として、サーバ側で拡張子・MIME・マジックナンバーを検証するのが一般的です。
Q: POST 送信なら安全なのでは?
A: POST 送信は通信経路上の漏えい対策であり、クライアントサイドの入力検証漏れとは別問題です。
A: POST 送信は通信経路上の漏えい対策であり、クライアントサイドの入力検証漏れとは別問題です。
関連キーワード: クライアントサイドバリデーション、JavaScript無効化、ファイルアップロード、入力検証、セキュリティ対策
設問1:〔ソフトウェアの基本設計〕について(1)〜(3)に答えよ。
(3)本文中の下線③の方式とはどのようなものか。30字以内で述べよ。
模範解答
Webアプリケーションで拡張子判定を行う。
解説
解答の論理構成
- 基本設計の会話では、V君がブラウザ側スクリプトで拡張子を判定する案を提示しました。
引用:
「この指摘への対策の一つとして、アップロードするファイルの拡張子を画像ファイルのものに制限することとした。制限する方式として、V君は、Webブラウザにおいてスクリプトによって判定することを考えた。」 - しかしQ主任は、契約者の操作次第で制限を回避できる弱点を挙げ、
引用:
「②契約者の操作によっては、拡張子が画像ファイルのものでないファイルがアップロードできてしまうという問題点を指摘し、制限する方式には③スクリプトによらない方式を検討するよう指示した。」 - 「③スクリプトによらない方式」は、ブラウザ(クライアント)ではなくサーバ側で判定を行う方式を指します。ブラウザ依存を排除することで、利用者がスクリプトを無効化した場合や改ざんした場合でも安全に拡張子制限を適用できます。
- したがって解答は「Webアプリケーションで拡張子判定を行う。」となります。
誤りやすいポイント
- 「MIMEタイプ判定」とだけ答えると拡張子制限かどうかが不明確になり減点される恐れがあります。
- 「サーバ側でウイルスチェックを行う」など、拡張子以外の対策を混在させると設問の焦点がずれます。
- 「HTTPS 強制」や「Content-Disposition ヘッダ」など、別のセキュリティ手法と混同しないよう注意が必要です。
FAQ
Q: クライアント側スクリプトだと何が問題なのですか?
A: 利用者がブラウザの開発者ツールなどでスクリプトを無効化・改変すると、意図しないファイルをアップロードできてしまいます。サーバ側チェックなら回避されません。
A: 利用者がブラウザの開発者ツールなどでスクリプトを無効化・改変すると、意図しないファイルをアップロードできてしまいます。サーバ側チェックなら回避されません。
Q: 拡張子判定だけで十分なのでしょうか?
A: 本問では拡張子制限が要求事項ですが、実際の運用では拡張子だけでなく MIME タイプ確認やファイル内容検査も併用するのが望ましいです。
A: 本問では拡張子制限が要求事項ですが、実際の運用では拡張子だけでなく MIME タイプ確認やファイル内容検査も併用するのが望ましいです。
Q: サーバ側で判定するにはどこで実装するのですか?
A: 本システムでは「Javaサーブレットを利用したWebアプリケーション」で構築するため、サーブレット内でアップロードされたファイルの拡張子を確認し、不適切なものはエラー応答を返します。
A: 本システムでは「Javaサーブレットを利用したWebアプリケーション」で構築するため、サーブレット内でアップロードされたファイルの拡張子を確認し、不適切なものはエラー応答を返します。
関連キーワード: 拡張子チェック、サーバ側検証、クライアントスクリプト、ファイルアップロード、セキュリティ対策
設問2:〔画像処理プログラムでの不具合〕について(1)、(2)に答えよ。
(1)本文中のa、bに入れる適切な字句を、それぞれ15字以内で答えよ。
模範解答
a:整数オーバフロー
b:バッファオーバフロー
解説
解答の論理構成
-
38行目の計算
bytesOfBuff = bytesOfRow * fhBuf.rows; とあります。
直前の 37行目で bytesOfRow は列数に kColors を掛けた後に 256 バイト境界へ調整しているため、元画像が大きい場合には bytesOfRow がかなり大きくなります。ここで fhBuf.rows(行数)との乗算を行うと、32 ビット符号付き整数の最大値である 0x7fffffff を超えるケースが発生し得ます。
→ この現象は「整数オーバフロー」です。 -
オーバフローが起きた場合の副作用
bytesOfBuff に本来より小さい値が格納されてしまい、41行目
pixBuf = (char*)malloc(bytesOfBuff);
で確保される領域も不足したサイズになります。 -
不足領域への書込み
47~53行目の for ループでは、元画像全体を読み込みます。実データサイズは正しい値のままなので、確保サイズを超えて pixBuf を更新し続け、結果として
50行目 fread(pixBuf, kColors, fhBuf.cols, fp);
でメモリ境界を越えて書き込むことになります。
→ これは「バッファオーバフロー」です。 -
追加行による修正
図7の追加行
if ( c < d ) throw out_of_range("Image too large");
で、乗算前に「列数×行数×色数」が安全な範囲か確認し、オーバフローとそれに続くバッファオーバフローを事前に防止しています。
以上より
a に入る語句は「整数オーバフロー」、 b に入る語句は「バッファオーバフロー」と判断できます。
a に入る語句は「整数オーバフロー」、 b に入る語句は「バッファオーバフロー」と判断できます。
誤りやすいポイント
- 「配列境界を超える=バッファオーバフロー」に目が行き、原因である「整数オーバフロー」を見落とす。
- 37行目の 256 バイト境界調整を“端数切り上げ”と誤解し、計算式が安全だと思い込む。
- unsigned short int で定義されているヘッダ項目を「正なら問題なし」と考え、列数・行数チェックを甘くしてしまう。
FAQ
Q: 乗算前に long long 型へキャストすれば十分ですか?
A: 計算結果を保持できても、その後の malloc が 32 ビット OS で扱えるサイズを超える恐れがあります。キャストだけでなくサイズ上限のチェックが必要です。
A: 計算結果を保持できても、その後の malloc が 32 ビット OS で扱えるサイズを超える恐れがあります。キャストだけでなくサイズ上限のチェックが必要です。
Q: 追加行で比較している c と d は何を想定していますか?
A: 一般に (long long)fhBuf.cols * fhBuf.rows * kColors と kMaxInteger(0x7fffffff)を比較します。これで演算結果が int の上限を超えないことを保証できます。
A: 一般に (long long)fhBuf.cols * fhBuf.rows * kColors と kMaxInteger(0x7fffffff)を比較します。これで演算結果が int の上限を超えないことを保証できます。
Q: バッファオーバフローを検出するツールは必須ですか?
A: 推奨ですが、検出ツールに頼るだけでなく、設計段階から境界値分析・入力バリデーションを徹底することが根本的な対策になります。
A: 推奨ですが、検出ツールに頼るだけでなく、設計段階から境界値分析・入力バリデーションを徹底することが根本的な対策になります。
関連キーワード: 整数オーバフロー、バッファオーバフロー、境界チェック、入力バリデーション
設問2:〔画像処理プログラムでの不具合〕について(1)、(2)に答えよ。
(2)U主任が指摘したaが発生する入力ファイルに関する条件を、kMaxIntegerという字句を用いて60字以内で述べよ。
模範解答
ヘッダ部の列数と各ピクセルのバイト数の積にパディングを加えたものと、行数の積がkMaxIntegerを超える。
解説
解答の論理構成
-
ソースコード36〜38行目ではbytesOfRow = fhBuf.cols * fhBuf.colors; bytesOfRow += 255 - ((bytesOfRow + 255) % 256); /256バイト境界に調整/ bytesOfBuff = bytesOfRow * fhBuf.rows;と計算しています。
-
変数型はすべて int であり、上限は 11行目に定義された
const int kMaxInteger = 0x7fffffff; です。 -
行38行目の乗算で得られる真の値が kMaxInteger を超えると、
bytesOfBuff には符号付き整数のオーバフロー(a)が生じ、
― すなわち期待より小さい(場合によっては負の)値が入ります。 -
そのまま41行目で
pixBuf = (char*)malloc(bytesOfBuff);
を実行すると、確保するバッファが実際に必要なサイズより不足し、
50行目の fread(pixBuf, kColors, fhBuf.cols, fp); で
バッファオーバフロー(b)が発生します。 -
したがって a が起こる条件は
「パディングを含めた1行分のバイト数(bytesOfRow)とヘッダ部の行数(fhBuf.rows)の積が kMaxInteger を超える場合」
となります。
誤りやすいポイント
- 1行分のパディング調整 255 - ((bytesOfRow + 255) % 256) を忘れ、単純に fhBuf.cols * fhBuf.colors だけで判定してしまう。
- 「オーバフローが起きたら負になる」と思い込み、積が負値になるケースしか想定しない(実際には正の小さい値になることもある)。
- kMaxMatData(10行目)との比較で十分と勘違いし、kMaxInteger まで考慮していない。
FAQ
Q: どうして unsigned int ではなく int を使っているのですか?
A: 処理系依存を避けるために符号付きで統一し、例外で異常検出を行う方針だからです。ただし今回のようにオーバフロー検出を怠ると逆効果になります。
A: 処理系依存を避けるために符号付きで統一し、例外で異常検出を行う方針だからです。ただし今回のようにオーバフロー検出を怠ると逆効果になります。
Q: kMaxMatData との大小比較では不十分なのですか?
A: kMaxMatData はメモリ確保可能容量(100Mバイト)の上限ですが、オーバフローして小さな値になってしまうとこのチェックに引っ掛からず、異常が見逃されます。
A: kMaxMatData はメモリ確保可能容量(100Mバイト)の上限ですが、オーバフローして小さな値になってしまうとこのチェックに引っ掛からず、異常が見逃されます。
Q: パディング調整はなぜ256バイト単位なのですか?
A: 画像処理ライブラリの高速化のため、行頭を256バイト境界にそろえる設計ルールだからです。
A: 画像処理ライブラリの高速化のため、行頭を256バイト境界にそろえる設計ルールだからです。
関連キーワード: 整数オーバフロー、バッファオーバフロー、境界調整、入力検証
設問3:
図7中のc、dに入れる適切な式又は変数を答えよ。
なお、c、dのどちらか一方は、kMaxIntegerを含むこと。(同じ群中の組み合わせとする)
模範解答
ア群:
c:kMaxInteger / fhBuf.rows
d:bytesOfRow
イ群:
c:kMaxInteger / bytesOfRow
d:fhBuf.rows
解説
解答の論理構成
-
背景把握
-
【問題文】図6 37~38 行でbytesOfRow += 255 - ((bytesOfRow + 255) % 256); /256バイト境界に調整/ bytesOfBuff = bytesOfRow * fhBuf.rows;とあり、bytesOfRow * fhBuf.rows で int 型の乗算が行われています。
-
同図 39 行目でif (bytesOfBuff > kMaxMatData) throw out_of_range("Image too large");というサイズ上限チェックを行っていますが、実際には 38 行目の乗算時点で int の最大値(kMaxInteger)を超えると桁あふれ(整数オーバフロー) が発生し、正常な比較ができなくなります。
-
-
追加行の目的
-
【問題文】図7ではif ( c < d ) throw out_of_range("Image too large");を 37~38 行の間に挿入し、乗算を実行する前に 桁あふれを未然に検知 させるのが狙いです。
-
-
オーバフローの一般的な判定式
-
乗算 A * B が kMaxInteger を超えるかどうかはif (A > kMaxInteger / B) // 乗算するとオーバフローで判定できます。
-
これを「左右を入れ替えた形」にしても論理は同じで、if (B > kMaxInteger / A)でもかまいません。
-
-
当該変数への当てはめ
-
乗算の片方 A が bytesOfRow、もう片方 B が fhBuf.rows です。
-
よって、チェック式は次の2パターンのいずれかになります。ア群if (kMaxInteger / fhBuf.rows < bytesOfRow) …イ群if (kMaxInteger / bytesOfRow < fhBuf.rows) …
-
問題指示「c、d のどちらか一方は、kMaxIntegerを含むこと」にも合致しています。
-
-
よって模範解答は
- ア群
- c:kMaxInteger / fhBuf.rows
- d:bytesOfRow
- イ群
- c:kMaxInteger / bytesOfRow
- d:fhBuf.rows
- ア群
誤りやすいポイント
- kMaxMatData と kMaxInteger を取り違え、上限比較を誤る。
- 既に計算済みの bytesOfBuff を使ってチェックしてしまい、乗算後のオーバフローを防げない。
- /(整数除算)が切り捨てであることを忘れ、境界条件を間違える。
- “大きい方”と“小さい方”を逆に比較し、常に例外が発生しない・常に発生するというバグを入れる。
FAQ
Q: unsigned int にすればオーバフロー対策は不要ですか?
A: いいえ。符号なしでも桁あふれは発生し、値が 0 へ巻き戻るだけで例外は出ません。事前チェックが必要です。
A: いいえ。符号なしでも桁あふれは発生し、値が 0 へ巻き戻るだけで例外は出ません。事前チェックが必要です。
Q: double で計算し、最後にキャストする方法は?
A: 浮動小数点演算誤差により完全に安全ではありません。整数型のままオーバフロー判定を行う方が堅牢です。
A: 浮動小数点演算誤差により完全に安全ではありません。整数型のままオーバフロー判定を行う方が堅牢です。
Q: ガードチェックを複数回入れると性能に影響しますか?
A: 除算と比較のみなのでオーバーヘッドはわずかです。安全性を優先すべき場面です。
A: 除算と比較のみなのでオーバーヘッドはわずかです。安全性を優先すべき場面です。
関連キーワード: 整数オーバフロー、ガードチェック、メモリ安全性、画像リサイズ


