戦国IT - 情報処理技術者試験の過去問対策サイト
ブログお知らせお問い合わせ料金プラン

情報処理安全確保支援士 2011年 春期 午後1 問01


セキュアプログラミングに関する次の記述を読んで、設問1~4に答えよ。

   A社は、従業員数100名のソフトウェア開発会社である。A社では、PC向けソフトウェア製品として、“青少年が安全に安心してインターネットを利用できる環境の整備等に関する法律”に基づいた青少年有害情報フィルタリングソフトウェア(以下、Bフィルタという)を開発することとなった。  A社では、Bフィルタの開発に当たって、F主任をリーダとした開発チームを編成した。この開発チーム内の体制は、設計を行うDグループ、作成を行うPグループ及び試験を担当するQグループの三つのグループとした。また、プログラム開発に用いる言語は、JIS X 3014“プログラム言語C++”(以下、C++という)とした。  次は、この開発におけるセキュリティの脆弱性の発見から修正及び再発防止に至る経緯である。   〔URLマッチングの方式設計〕  Dグループでは、Bフィルタの概略機能を図1のようにまとめた。その後、要件定義を経て、URLマッチングによる有害の度合いを決定する方式設計を行い、図2の内容のとおり決定した。
情報処理安全確保支援士試験(平成23年度 春季 午後1 問01 図01)
情報処理安全確保支援士試験(平成23年度 春季 午後1 問01 図02)
〔詳細設計と作成〕  Dグループでは、図2の方式設計結果に基づいて設計作業を進め、URLをパーセントエンコードする機能を一つの関数として作成することを決定し、その関数の仕様を図3のとおりとした。
情報処理安全確保支援士試験(平成23年度 春季 午後1 問01 図03)
 その後、Pグループでは、パーセントエンコード関数の作成に取り掛かり、図4に示すソースコードを作成した。   情報処理安全確保支援士試験(平成23年度 春季 午後1 問01 図04) ↩設問2(1) ↩設問2(2) ↩設問3
〔脆弱性の発見〕  開発計画に基づき、URLマッチング機能だけがおおよそ完成した時点のものをプロトタイプ1として、Qグループによる試験を実施した。その試験の結果、ある特定の条件下でURLマッチング機能が正常に動作しない不具合が発見された。その結果を受けてプロトタイプ1の動作について詳細に確認したところ、パーセントエンコード関数が実行された直後に、ほかの関数でフラグとして使用している変数(以下、フラグ変数という)が想定外の値に書き換わり、URLマッチング機能が正常に動作しないことが判明した。  ソースコードの調査を行ったところ、パーセントエンコード関数にバッファオーバフロー脆弱性があり、隣接したメモリ領域に置かれたフラグ変数が想定外の値に書き換えられることが分かった。   〔関数の仕様変更〕  Bフィルタの開発チームは、Bフィルタで同様の脆弱性を作り込まないようにするために、標準C++ライブラリの文字列クラスを使用してパーセントエンコード関数を作り直すとともに、ほかの関数においても作り直しを行った。パーセントエンコード関数の作り直しに当たって、引数及び返却値を文字列型に変更するのに伴い、Dグループでは関数の仕様を図5に示すように変更した。その後、Pグループは図5の仕様に基づいた関数の作成に取り掛かり、図6のソースコードを作成した。  なお、図3の仕様に基づく関数urlPercentEncode()を呼び出していた部分は、すべて図5の仕様に基づく関数urlPercentEncodeString()を呼び出すように修正した。
情報処理安全確保支援士試験(平成23年度 春季 午後1 問01 図05)
 図4のソースコードでは文字列を配列として取り扱っていたので領域の境界をプログラムで管理する必要があったが、図6のソースコードではcので、バッファオーバフローが発生することはなくなった。   〔修正後の確認と再発防止〕  その後、Qグループでは、作り直したプロトタイプ1を試験して、バッファオーバフローが発生しないことを確認した。最後に、F主任は再発防止策として、従来のA社におけるC++開発標準ルールを図7に示すように改訂した。  なお、図7中の下線部は、この改訂によって追加した項目である。
 この改訂によって、A社におけるプログラム開発では本件と類似した問題点を作り込むことがなくなり、より安全なソフトウェアを提供することができるようになった。

設問1:

問題文を見る
図6中のa、bに入れる適切なメンバ関数名(メソッド名)を解答群の中から選び、記号で答えよ。
解答群  ア:begin  イ:clear  ウ:end  エ:get  オ:set  カ:size  キ:start  ク:tail

模範解答

a:ア b:ウ

解説

解答の論理構成

  1. 【問題文】図6では
    string::iterator readPoint = src.a();
    string::iterator atEOL = src.b();
    と記述されており、readPointとatEOLの2つの反復子(イテレータ)で文字列src全体を走査しています。
  2. ループ条件は
    while(readPoint != atEOL){ … }
    です。反復子が「先頭から末尾(終端位置)まで」を指し示すのが自然でなければ、この条件は成立しません。
  3. 標準C++ライブラリstringクラスの代表的なメンバ関数は
    • begin() : 先頭要素を指すイテレータを返す
    • end() : 末尾の次(終端)を指すイテレータを返す
    です。その他の候補(clear、sizeなど)はイテレータを返さない、あるいは意味が合致しません。
  4. したがって
    ・readPointは先頭を指す必要があるため a に入るのは “begin”
    ・atEOLは終端を指す必要があるため b に入るのは “end”
    となり、解答は
    a:ア
    b:ウ
    で確定します。

誤りやすいポイント

  • size() と混同する
    size() は要素数を返す関数でありイテレータ型ではないため、代入自体がコンパイルエラーになります。
  • 末尾位置のイメージ違い
    end() が「最後の文字」ではなく「最後の次」を指すイテレータである点を忘れると、ループ条件を誤って「<=」などに置き換えてしまいoff-by-oneエラーを招きます。
  • clear() の機能誤認
    イテレータを返しそうに見えても、clear() は内容を消去する副作用のみを持つため全く用途が異なります。

FAQ

Q: なぜconst_iteratorではなくiteratorを使っているのですか?
A: ループ内で読み出し専用ですが、後続の処理でイテレータを使った可変操作を想定しているケースなどではiteratorを使うことがあります。本問の主眼はバッファオーバフロー回避であり、イテレータ型の選択は必須要件ではありません。
Q: end() が「末尾の次」を返すメリットは?
A: 境界チェックが != end() で統一でき、範囲 [begin(), end()) が半開区間となることでSTLのアルゴリズム全体と整合が取れるからです。
Q: バッファ長の上限(128バイト)チェックはどこで行うべき?
A: 本問ではURL正規化の前提条件として提示されています。実装ではエンコード後の文字列長が増える場合もあるため、マッチング処理の直前など別途長さ検証を行うのが安全です。

関連キーワード: イテレータ、バッファオーバフロー、文字列クラス、ポインタ操作、範囲チェック

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

設問2:図4のソースコードで発見された脆弱性について、(1)、(2)に答えよ。

問題文を見る
(1)バッファオーバフローが発生するメモリ領域はどこか。図4中の変数名を用いて20字以内で述べよ。

模範解答

dstが指し示す領域

解説

解答の論理構成

  1. 脆弱性の種類を確認
    問題文には「パーセントエンコード関数にバッファオーバフロー脆弱性があり」と明示されており、対象は「図4」の関数です。
  2. 書き込み先バッファの特定
    「図4」1行目に
    void urlPercentEncode(char *dst, char *src, int n)
    とあり、dstが書き込み先バッファであることが分かります。
  3. 上限チェックの不備
    ループ条件は6行目
    while(src[srcPos] != '\0' && dstPos < n){
    で行っていますが、エンコード対象文字の場合は18〜22行目で 最大3バイト を一度にdstに書き込みます。
    dst[dstPos++] = '%'; // 1バイト ... dst[dstPos++] = x; // 2バイト目 ... dst[dstPos++] = x; // 3バイト目
    しかしdstPos < nの判定は 1回のループ開始時点のみ なので、ループ途中でnを超過してもチェックされず、dstの後続領域に上書きが発生します。
  4. 被害が出る領域
    問題文は「隣接したメモリ領域に置かれたフラグ変数が想定外の値に書き換えられる」と説明しており、これはdstの直後にあった変数への不正書き込みです。
    したがって、オーバフローが起きるメモリ領域は「dstが指し示す領域」と結論付けられます。

誤りやすいポイント

  • src側を疑ってしまう
    読み出しバッファであるsrcはサイズを超えて読み込まれてもメモリアクセス違反になりにくく、今回の脆弱性の直接原因ではありません。
  • nのチェックは十分と誤認
    1ループ3バイト書き込む場合があることに気付かないと、条件式dstPos < nで十分と勘違いしやすいです。
  • 「フラグ変数」そのものを回答に書く
    設問は「バッファオーバフローが発生するメモリ領域」を聞いており、書き換えられた側ではなく あふれ出した側 を答える必要があります。

FAQ

Q: dstPos + 2 < nと書けば脆弱性は解消しますか?
A: エンコードしない場合は1バイトしか書かないため条件が複雑になります。安全策としては今回のように標準ライブラリstringへ置き換える方が確実です。
Q: なぜsrc側に長さ制限(128バイト)があるのにオーバフローするのですか?
A: 128バイトは正規化後のURL長さです。関数単体ではその制約を知らないため、独立して呼び出されれば長さ無制限となり得ます。
Q: 配列ではなくstd::vector<char> を使えば安全になりますか?
A: 添字アクセスを使う限り境界チェックを自前で行う必要があり、push_backを使ったstring/vectorの方が安全です。

関連キーワード: バッファオーバフロー、境界チェック、可変長エンコード、ポインタ操作、安全な文字列操作

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

設問2:図4のソースコードで発見された脆弱性について、(1)、(2)に答えよ。

問題文を見る
(2)図4の6行目から始まるwhile文の副文(ループ本体)の実行において、バッファオーバフローが発生するための条件を、図4中の変数名を用いて60字以内で述べよ。

模範解答

dstが指し示す領域の残りが2バイト以下となった時点で、srcにエンコードすべき文字があった場合

解説

解答の論理構成

  1. 【問題文】の「パーセントエンコード関数にバッファオーバフロー脆弱性があり」とあるとおり、原因はurlPercentEncode() 内の領域管理にあります。
  2. 図4‐6行目のwhile条件は
    while(src[srcPos] != '\0' && dstPos < n){
    で、dstPos < nという“1バイト以上空いていれば継続”という判定しか行っていません。
  3. しかし図4‐18~22行目ではエンコード対象文字を見つけると
    dst[dstPos++] = '%'; // 1バイト x = (src[srcPos] & 0x00f0) >> 4; dst[dstPos++] = …; // 2バイト目 x = src[srcPos++] & 0x000f; dst[dstPos++] = …; // 3バイト目
    の計3バイトを書き込みます。
  4. したがって、ループ開始時点でn - dstPosが「1バイトまたは2バイト」しか残っていない状態でエンコード対象文字が現れると、3バイト目の書込みでdstの領域外に到達し、隣接メモリ(フラグ変数など)を上書きしてバッファオーバフローが発生します。
  5. よって模範解答は「dstが指し示す領域の残りが2バイト以下となった時点で、srcにエンコードすべき文字があった場合」となります。

誤りやすいポイント

  • 「ナル終端を付与できないだけ」と思い込み、3バイト連続書込みによる境界超過を見落とす。
  • dstPos < nなので安全だと早合点し、必要バイト数(1文字で最大3バイト)を考慮しない。
  • 逆に「残り1バイトのときのみ危険」と狭く捉え、2バイト残りの場合を失念する。
  • src側の読込位置(srcPos)ばかり注視し、dst側の書込み量を軽視する。

FAQ

Q: そもそも非エンコード文字のときはバッファオーバフローしないのですか?
A: はい。非エンコード文字は1バイトしか書き込まないため、dstPos < nの判定で領域をはみ出すことはありません。
Q: nは「書込める最大バイト数」と仕様にありますが、ナル終端の1バイトを含むのですか?
A: 仕様には「ナル文字で終了することは保証されない」とあるため、nに終端用バイトを含めるか否かは呼び出し側依存です。本脆弱性の本質は3バイト連続書込みで境界を超える点にあります。
Q: 早い段階でdstを十分なサイズにしておけば問題は起こらないのでは?
A: その通りですが、入力長を正確に予測できない場合は安全に確保しきれません。書込み前に「必要バイト数」を評価するか、図6のようにサイズを自動管理するstringなどを用いるのが推奨されます。

関連キーワード: バッファオーバフロー、パーセントエンコード、配列境界チェック、不正メモリアクセス

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

本文中のcでは、図4で存在したバッファオーバフロー脆弱性が、図6では存在しない技術的理由を述べている。cに入れる適切な字句を60字以内で述べよ。

模範解答

c:文字列をstringクラスとして取り扱っており、領域の境界は処理系が管理することとなる

解説

解答の論理構成

  • 【問題文】では、旧実装について「図4のソースコードでは文字列を配列として取り扱っていたので領域の境界をプログラムで管理する必要があった」と明示しています。
  • その後の改修方針として「標準C++ライブラリの文字列クラスを使用してパーセントエンコード関数を作り直す」と記述し、図5で関数シグニチャを「string urlPercentEncodeString(string src)」へ変更しています。
  • さらに、「図6のソースコードではcので、バッファオーバフローが発生することはなくなった。」と背景を説明しています。
  • 文字列クラスstringは格納領域の確保・拡張・終端管理を処理系(ライブラリ)が自動で行います。利用側はpush_backなどのメンバ関数を呼ぶだけで済み、配列添字演算で自力管理する必要がありません。
  • したがって、改修後は「領域の境界」を開発者が意識せずに済み、配列境界を越えて書込む不具合——すなわちバッファオーバフロー——が構造的に除去されるため、c には「文字列をstringクラスとして取り扱っており、領域の境界は処理系が管理することとなる」が入ります。

誤りやすいポイント

  • 「イテレータを使えば安全」と早合点し、根本理由を“イテレータ”に求めてしまう。安全性を担保しているのはstringが内部でサイズ管理している点です。
  • 「push_backも配列添字と同じ書込み」と誤解し、push_backでも境界チェックがないと思い込む。stringは必要に応じて自動で再確保します。
  • 「UTF-8化や128バイト制限があるから安全」と問題の主旨を取り違える。今回の質問はバッファオーバフロー防止の技術的根拠を問うています。

FAQ

Q: stringでも不正入力で例外が出ることはありますか?
A: メモリ不足などで再確保に失敗した場合はstd::bad_allocが送出される可能性はあります。ただし配列境界を越えて隣接メモリを破壊するタイプのバッファオーバフローは発生しません。
Q: vector<char> では同じ効果を得られますか?
A: はい。vectorも動的にサイズを管理するコンテナなので、添字アクセスよりpush_backやat() を用いれば同様に境界越えの書込みを防げます。
Q: 配列を使ったままでも安全に書く方法はありますか?
A: std::arrayと範囲チェック関数、あるいは安全なラッパー関数を導入すれば防げますが、運用コストとヒューマンエラーを考慮するとstringなどの高水準コンテナを用いるほうが確実です。

関連キーワード: バッファオーバフロー、文字列クラス、領域管理、ポインタ操作

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

図7について、文字列の取扱いで本件と類似した問題点の作り込みを未然に防ぐのに有効となるようにd〜fに入れる適切な字句を、それぞれ8字以内で答えよ。

模範解答

d:文字型の配列 e:上限チェック f:代入

解説

解答の導き方

設問は図7の空欄に入る語句を選ぶ問題です。図7の該当箇所は次の三箇所です。まずそれぞれの文と、問題文中の該当箇所を照らし合わせて論理的に決めます。
  • 図7(4. ポインタ・配列)にある「文字列処理を行う場合、文字列を格納するための d の使用を禁止する。」
    根拠として本文に「図4のソースコードでは文字列を配列として取り扱っていたので領域の境界をプログラムで管理する必要があった」とあり、さらに改修後に「標準C++ライブラリの文字列クラスを使用してパーセントエンコード関数を作り直す」とあります。これらから、禁止したいものは「配列として文字列を保持する方法(手動で境界管理が必要なもの)」であると読み取れます。日本語で最も直接的に表す語句は「文字型の配列」です。したがって空欄dには「文字型の配列」が適切です。
  • 図7(4. ポインタ・配列)にある「配列又はポインタに添字を指定して書込みを行う場合、e を毎回実施する。」
    根拠として図3の仕様は「nの値はdstが指す文字列に書き込める最大バイト数」と定め、図4の実装ではループ条件に「while(src[srcPos] != '\0' && dstPos < n)」のようなチェックがある一方で、エンコード時に複数バイトを連続して書き込んでおり(例:dst[dstPos++] = '%' の後さらに2バイト書く)、ループ条件の一回の比較だけでは各書込みが上限を超えないことを保証できず脆弱性を招きました。ここで求められている対策は「書き込みごとに上限を確かめること」ですから、空欄eには「上限チェック」が当てはまります。
  • 図7(5. 関数)にある「引数としてポインタを受け取った場合、添字指定での f は禁止する。」
    根拠として図7の同項目に「関数内で値を変更する場合を除き、関数の引数であるポインタはconstへのポインタとする。」や「文字列処理を行う関数では、処理が成功したときは、原則として処理結果の文字列を返却値として返す」とあること、および改修で「urlPercentEncode() を呼び出していた部分は、すべて図5の仕様に基づく関数urlPercentEncodeString()を呼び出すように修正した」ことから、関数が受け取ったポインタ先を添字で書き換える行為(添字指定での書き込み=代入)を禁止していることが明らかです。したがって空欄fには「代入」が適切です。
以上より、空欄に入る語句はそれぞれ次のとおりと導けます。
d:文字型の配列
e:上限チェック
f:代入

誤りやすいポイント

  • 「文字型の配列」を単に「配列」としてしまう誤り
    → 問の意図は文字列を保存するためのCスタイルの配列(手動管理が必要な配列)を明確に禁止する点にあるため、単に「配列」だと対象があいまいになります。
  • 「上限チェック」と「境界チェック/範囲チェック」を混同する誤り
    → 意味は近いですが、設問文は「書込み時の上限(最大書込みバイト数)を毎回確認する」という趣旨なので、より直接的な表現である「上限チェック」が求められます。実装上は「各書込み前に容量を確認する」ことを忘れないでください。
  • 添字による「読み取り」と「代入」を取り違える誤り
    → 問は「添字指定での(何を)禁止するか」を問うています。禁止されているのは書き込み(代入)であり、読み取りのみを指す語を入れると趣旨が合いません。
  • 読み取りは安全だと思い込む誤り
    → 読み取りの境界外参照も未定義動作であり危険です(下のFAQ参照)。

FAQ

Q: 読み取りの境界外参照は書込みほど危険ではないのではないですか?
A: いいえ、読み取りの境界外参照も未定義動作です。読み取りでもメモリ上の想定外の値を参照して誤動作や情報漏えいを招く可能性があり、安全とは言えません。したがって境界の外に出ないことを前提に実装し、必要ならば読み取り前にも境界の確認を行ってください。
Q: 「上限チェックを毎回実施する」とは実務上どうすればよいですか?
A: 各書込みの直前に、書き込み後のインデックスや必要バイト数がバッファの容量を超えないかを確認します。具体的には「次に書き込もうとするバイト数分だけ残り容量があるか」を比較すること(例:dstPos + bytesNeeded <= n)を毎回行うことです。複数バイトをまとめて書き込む場合はまとめてチェックしてください。
Q: 「添字指定での代入」が禁止される場合、関数はどう文字列を返せばよいですか?
A: 図7にもあるとおり、文字列処理を行う関数は原則として処理結果を返却値として返す(例:std::stringを返す)方針にするか、引数のポインタを受け取る場合は書込みを行う必要があるときだけ明示的にその旨を設計し、ポインタはconstでない場合でも事前条件と上限チェックを厳格にする、といった設計にします。可能ならばstd::stringを使い、呼び出し側で受け取る実装が安全です。

関連キーワード: バッファオーバフロー、境界チェック、std::string、ポインタ演算、パーセントエンコード

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

戦国ITクイズ機能

\ せっかくなら /

情報処理安全確保支援士を
クイズ形式で学習しませんか?

クイズ画面へ遷移する→

すぐに利用可能!

©︎2026 情報処理技術者試験対策アプリ

このサイトについてブログプライバシーポリシー利用規約特商法表記開発者について