公開日:2007年9月26日
独立行政法人情報処理推進機構
セキュリティセンター
本ページの情報は2007年9月時点のものです。
記載の資料は資料公開当時のもので、現在は公開されていないものも含みます。
サーバソフトウェアは、「サービス不能」(Denial of Servicve)に陥ることなく、サービスを提供し続ける必要がある。このサービス不能を引き起こす攻撃は「サービス妨害攻撃」(Denial of Service Attack)と呼ばれる。
ソフトウェア、特に、サーバソフトウェアが所定のサービスを提供し続けることができない状態に陥ることを「サービス不能」(Denial of Servicve)と言う。そして、サービス不能状態を引き起こす攻撃が「サービス妨害攻撃」(Denial of Service Attack)である。
サービス不能が生じる要因はさまざまである。表面的な現象から見ると、プログラムが停止してしまうケースと動き続けるケースの大きくふたつに分けられる
異常終了と無反応の違いは、プログラム内部で何らかの異常が生じたときにエラー処理機構が過敏に反応するか、検知する仕組みをもたないため問題の発生を見過ごしたままプログラムが動作し続けるかの差である。
この両者の要因となり得るもののひとつに「リソースの食い尽くし」が挙げられる。「リソースの食い尽くし」では、ソフトウェアがコンピュータ資源を使い尽くして、それ以上サービス提供が継続できない状況に追い込まれることになる。食い尽くされるリソースはおおよそ次のようなものである。
食い尽くしにも2種類のパターンがある
現実にはこのふたつのパターンが複合的に発生することもあるだろう。
サービス不能に至る要因にはさまざまなものが考えられる、ここでは次の3つに注目する。
サービスを提供するメインプロセスと、そのプロセスの状態を管理する監視プロセスに分ける方法がある。
監視プロセスは、メインプロセスに対して定期的にメッセージ等により問い合わせをする。
この問い合わせに対する応答が有れば、正常であり、タイムアウト等の何らかのエラーがあれば、メインプロセスに異常がおきていると判断できる。
Unix では、監視プロセスを親プロセスとして、子プロセスにあたるメインプロセスをfork, exec により起動すれば、親プロセスは、wait (2) により子プロセスの終了を知ることができる。
メインプロセスに異常があれば、メインプロセスを終了させた後、起動(再起動)するようにする。
まとまった処理にタイマを使用して、処理の異常を検出することができる。
例えば、クライアントからの要求を受け付けたら、タイマをセットし要求の処理が終わったら、タイマをクリアする。この間に、タイムアウトが発生したら無限ループ等の異常がおきていると判断できる。
異常を検出した時には、対象となるプロセスを終了させた後、起動(再起動)するようにする。
サーバ内やプログラム内のリソース消費状況を計測するようにし、あらかじめ定めた限界を超えたら新たなリクエストの受付を制限するような工夫が必要となる。また、ネットワークから到着するリクエストの単位時間あたりの件数やデータ量に一定の閾値を設け、リクエストを受け付けすぎないようにすることも大切である。
ただし、受付の拒絶自体がサービス不能状態であるので、通常の運用状態からいきなり受付拒否状態に移行することは避ける必要がある。
GNU/Linuxでは、リソースの制限を設定する関数に setrlimit(2) がある。
この関数は、主には次のようなリソースの制限を設定できる。
仮想メモリの最大サイズ(バイト)
CPU 時間の上限(秒)
データ、ヒープ の最大値
作成できるファイルの最大サイズ
オープンできるファイル数の最大値 +1
スタックの最大サイズ(バイト)
また、現在のリソースの使用量を知るには、getrusage() を使用し、下記のような構造体の情報を得ることができる。
struct rusage {
struct timeval ru_utime; /* 使用されたユーザー時間 */
struct timeval ru_stime; /* 使用されたシステム時間 */
long ru_maxrss; /* RAM 上に存在する仮想ページのサイズ (resident set size) の最大値 */
long ru_ixrss; /* 共有メモリの合計サイズ */
long ru_idrss; /* 非共有データの合計サイズ */
long ru_isrss; /* 非共有スタックの合計サイズ */
long ru_minflt; /* 利用されたページ */
long ru_majflt; /* ページフォールト */
long ru_nswap; /* スワップ */
long ru_inblock; /* ブロック入力操作 */
long ru_oublock; /* ブロック出力操作 */
long ru_msgsnd; /* 送信されたメッセージ */
long ru_msgrcv; /* 受信されたメッセージ */
long ru_nsignals; /* 受信されたシグナル */
long ru_nvcsw; /* 意図したコンテキスト切り替え */
long ru_nivcsw; /* 意図しないコンテキスト切り替え */
};
Windows では、SetInformationJobObject() によりリソースの制限を設定することができ、QueryInformationJobObject() によりリソースの使用量を知ることができる。
ディスクの使用量を制限するには、ファイルシステムの quota を使用する。
GNU/Linux の quota は、パーティション単位にユーザやグループに対して使用量とファイル数の上限を設定することができる。
Windows のクォータは、ドライブ単位にユーザに対して、使用量の上限を設定することができる。
サービス妨害攻撃等で引き起こされるサービス不能状態は、さまざまな要因により発生する。プログラムは、異常を検知し自動的にプロセスの終了および再起動を行うようにする必要がある。
また、サーバ内やプログラム内のリソース消費状況を計測するようにし、あらかじめ定めた限界を超えたら新たなリクエストの受付を制限するような工夫が必要となる。
ただし、受付の拒絶自体がサービス不能状態なので、受付の制限を行う際は十分に注意する必要がある。