バッファオーバーフローとは?発生の原因とセキュリティをふまえた3つの対策
今回は、バッファオーバーフローがなぜ起こるのかを整理したうえで、どうすれば防げるのかについて説明します。セキュリティに配慮したプログラミングの一環として、ぜひ役立ててみてください。
今回は、バッファオーバーフローがなぜ起こるのかを整理したうえで、どうすれば防げるのかについて説明します。セキュリティに配慮したプログラミングの一環として、ぜひ役立ててみてください。
知識・情報
2022/04/27 UP
- 開発
- 技術
- プログラミング
ソフトウェアに「バッファオーバーフロー(バッファオーバーラン)」の問題が含まれていると、セキュリティ上の重大なリスクになる場合があります。しかし、プログラミングとの関連性については「あまりイメージできない」という人もいるのではないでしょうか。
そこで今回は、バッファオーバーフローがなぜ起こるのかを整理したうえで、どうすれば防げるのかについて説明します。セキュリティに配慮したプログラミングの一環として、ぜひ役立ててみてください。
バッファオーバーフローとは
バッファオーバーフローはセキュリティの観点からリスクが高いため、「脆弱性」に位置付けられる問題です。脆弱性はなくしたほうが望ましいですが、すべてを取り除くのは簡単ではありません。
バッファオーバーフローはOSをはじめ、さまざまなソフトウェアに内在しているからです。多くの機器がインターネットに接続されている現状をふまえて考えると、リスクは常にあるものという前提で対策するのが望ましいといえます。
利用者にとっては、OSや各種ソフトウェアをこまめに更新することが対策の基本になるでしょう。これらの更新には、新たに発見された脆弱性を修正するプログラムが含まれているためです。
開発者としては、バッファオーバーフローに関する心構えとして知っておきたい2つのポイントがあります。
ポイント1:バッファオーバーフローはバグである
バッファオーバーフローは、メモリとデータの操作に関するバグ(プログラムの欠陥)の一種です。C言語やC++など、メモリを直接操作する場面の多いプログラミング言語で発生しやすいといえます。
バグは通常、意図的に作り込むものではありません。しかし、たとえ開発者に悪意がなくても、第三者に悪用される恐れがあります。対策のためには、バッファオーバーフローがなぜ起こるのかを知ることが大切です。
ポイント2:完璧なバッファオーバーフロー対策はない
バッファオーバーフローがバグである以上、完全になくすことはできません。ミスや見落としは誰にでもあることだからです。しかし、適切な対策を施せば、大部分のバッファオーバーフローは防げるでしょう。
バッファオーバーフローのようなバグを防ぐコツは、一つひとつの作業を几帳面に行なう姿勢を保つことです。基本的な対策方法について知り、セキュリティに配慮した開発を心がけましょう。
【原因】バッファオーバーフローはなぜ起こる?
問題の原因について知ることが、バッファオーバーフロー対策の第一歩です。ここでは、バッファオーバーフローが発生し悪用されるにいたるまでの流れについて説明します。
原因1:バッファはいたるところで使われる
バッファオーバーフローは、名前から想像できるとおりバッファの扱い方に関する問題です。「バッファ(buffer)」という言葉には「緩衝材」などの意味があり、プログラムにおいてはデータを一時的に置いておくメモリなどを指します。
もし、プログラム中でバッファをまったく用いなければ、バッファオーバーフローの問題も発生することはないでしょう。しかし、現実的にはそうもいきません。バッファは通信データの処理やファイルの入出力、画面表示などさまざまな目的で使われるためです。バッファオーバーフローは、開発者にとって避けて通ることが難しい問題だといえます。
原因2:バッファの境界を踏み越えると問題が起こる
バッファを扱うとき、その境界を踏み越えてしまうような操作がバッファオーバーフローです。この動作を理解するために、バッファについてもう少し具体的にイメージしてみましょう。
バッファは通常、次のいずれかにあたります。
●関数呼び出しごとにスタック上に確保されるメモリ領域
●動的に確保されるメモリ領域
●静的に確保されているメモリ領域
これは、バッファのサイズは確保された時点で決まっているということです。
バッファを使ってデータを処理する際には、データをバッファにコピーしておく必要があります。プログラム中でこの動作を行なうとき、データのサイズがバッファのサイズを上回るケースが問題です。サイズの計算などにミスがあると、バッファの境界を踏み越えてデータをコピーしてしまうことになるでしょう。
一方、バッファに隣接するメモリ領域には、ほかのデータが格納されているかもしれません。そのため、バッファオーバーフローでは予期せぬデータ破壊が発生します。「予期せぬ」とは、どのデータが破壊されるのかわからないという意味です。
そうなると、プログラムはもはや設計どおりには動作しないため、どのような現象が起こるのかは予測できません。動作が不安定になったり、フリーズやクラッシュを引き起こしたりといったケースが考えられます。
原因3:攻撃者はバッファの問題を引き起こそうとする
バッファの操作に問題があるとしても、実際にバッファオーバーフローを引き起こすことは少ないと考えられる場合もあるでしょう。例えば、想定よりも大きなファイルを読み込むと問題が発生することがわかっているものの、通常の運用ではバッファに収まる小さなファイルしか扱わないといったケースです。
しかし、セキュリティ上のリスクは、攻撃者の存在を加味して考えなければなりません。攻撃者の多くは、プログラムの実装ミスにつけこんでバッファオーバーフローを引き起こそうとするからです。
具体的には、通常では考えられないような大量のデータを送り込むなどの攻撃方法が考えられます。そのデータのなかにマルウェア(悪意のあるプログラム)が含められている可能性を考えれば、リスクの高さをイメージできるのではないでしょうか。
このような攻撃では、バッファの境界を越えてデータが破壊される際の動作に乗じてプログラムの制御が奪われ、マルウェアを実行される恐れがあります。最悪の場合はシステム全体を乗っ取られてしまうことも考えられるため、バッファオーバーフローへの対策は重要です。
【対策】バッファオーバーフローを防ぐには
ここからは、バッファオーバーフローを防ぐための対策について説明していきます。「これだけやっておけば大丈夫」というような完璧な方法はないため、複数の対策を組み合わせるのがおすすめです。
対策1:外部から入ってくるデータを信用しない
マルウェアは外部からやってきます。まずは、プログラムにどのようなデータが入ってくる可能性があるのかを把握することが肝心です。通信データや入力ファイル、データベースのほか、URLパラメータやコマンドライン引数などが考えられます。
データを把握できたら、それらを以下の2つの観点からチェックするよう、プログラムに対策を施しましょう。
●バリデーション(入力の検証):データのサイズや書式などが想定どおりになっていることを確認する
●サニタイジング(無害化):データ内に危険なコードなどが含まれていたら実行不能な状態にする
これらの対策は、バッファオーバーフローに限らずさまざまな攻撃に対して効果的です。
対策2:バッファとデータのサイズをチェックする
バッファを扱うプログラムを書くときは、サイズチェックを徹底しましょう。データがバッファからはみ出さないようにすれば、バッファオーバーフローを引き起こす直接の原因を取り除くことができます。
ただし、データとバッファの大きさを比べさえすればチェックしたことになるとは限りません。例えば、バッファを配列として操作するなら、要素にアクセスする際のインデックスが要素数以上になっていないことを確認する必要があります。ポインタで操作するなら、そのアドレスがバッファの内側に収まっていることを確認する必要があるでしょう。
C言語によるプログラミングでは、サイズ指定のない関数を使用禁止にするのも有効な方法です。strcpy()やsprintf()の代わりにstrncpy()やsnprintf()を使うルールにすれば、データをコピーする際のサイズチェック漏れを防ぎやすくなります。
対策3:バッファオーバーフローをツールで検出する
バッファオーバーフローは、ツールによってある程度検出することも可能です。その場合は、「静的解析」と「動的検出」の2つを組み合わせるとよいでしょう。
静的解析とは、ソースコードを解析して危険箇所を検出する手法のことです。ソースコード内のどの部分に潜在的な問題があるのかが、ピンポイントでわかります。C言語で禁止された関数が使われていないかどうか確認するなどの単純なチェックも、静的解析の一種といえるでしょう。
動的検出は、プログラムが動作している状態で問題が発生しないか確認する手法です。バッファの境界ごとに目印となるデータを格納しておき、それらが書き換わっていないことをチェックする方法などがあります。擬似的な攻撃をしかけて堅牢性を確かめるのも有効な方法でしょう。
CPUの機能が必要になりますが、プログラムが配置される「テキスト領域」以外での実行を防止する動的検出もあります。この手法では、バッファ内のデータを実行しようとするとプログラムが停止するため、万が一マルウェアが呼び出されてしまった場合の被害を抑えることが可能です。
バッファオーバーフロー対策でセキュリティに配慮した開発を
バッファオーバーフローは、セキュリティ上の問題につながる恐れのあるバグです。完全になくすのは簡単ではありませんが、原因について知り、有効な対策をすれば大部分は防ぐことができます。また、対策は1つに絞るよりも、複数の手法を組み合わせて取り入れるほうが効果的です。
バッファオーバーフローに起因するリスクを減らし、セキュリティに配慮した開発を心がけましょう。