セキュリティを考えたネットワークプログラミング

JPCERT/CC, NECの佐野さんが講師でした. gate 登録システムの開発に係わってきたがそのシステムがどこまで安全なのか 不安なのでこのセッションは楽しみにしていました.また専攻サーバでも CGI が 利用できるようにしたいと epnetfan で意見したことがあったが危険だからという 理由で理解されなかったことがあった.CGI はどこが危険なのか解り切っていな かったがこのセッションを聞いてどこがどこまで危険なのか把握できてよかった と思っている.セキュリティホールが存在する原因の内,最も困ったもの(無限 に危険なもの)は開発者の意図しない処理によるものであると思った.開発者が いくら気をつけてコードを書いても所詮人間の作るもの.全くミスがないことはない と 思う.できうる限り丁寧にコードを書くことが必要なのですね.それが唯一の対策 です.これはどうしてもブラックホールだ.しかし,その他のセキュリティホールに なる原因は潰せる.あらかじめセキュリティホールとなることが解っている処理だ. これを残してしまうことはプログラムを書く者のケアレスミス.ケアレスミスはなく そう.

ウィルスの歴史,現況

<セキュリティに関心が集まるきっかけ>
1988 年 11 月 2 日

隣接する計算機を侵入しながら増殖する Worm プログラム
<ウィルス制作の基本的アイディア>
隣接ホストを発見
ユーザを発見
相手ホストに侵入
相手ホストに自分の複製をつくる
このことを繰り返す
<セキュリティホール>
1.プログラム開発者の意図しないセキュリティ上の弱点
2.脆弱性
3.隠しコマンドの存在
4.仕様上の問題
プロトコル,認証機構の弱点
5.甘い設計,甘い仕様
6.ソフトウエアのバグ
条件分岐
バッファオーバフロー
競合条件
<ネットワークとセキュリティホール>
ネットワークを介して
誤動作させる入力を送る
誤動作させるタイミングで処理を要求
gate 登録システムで同じ uid が振られる事故があったがあれは
タイミングが悪かった
ローカルに実行するプログラムでも
侵入者はさらに権限を得るために利用される可能性がある
ネットワークプログラムは特権(root)で動くことが多い

主に C 言語での話

<バッファオーバフロー>
局所配列の領域を越えて書き込み
制御領域を壊し指定したコードを実行
侵入者たちの興味はプログラムカウンタのオフセットを見つけることにある
<C 言語によるセキュリティホールとなるプログラムの例>
<DNS を用いた不正アクセス>
嘘の返答をクライアントに返す
gethostsbyname の返り値がノーチェックだと危ない
<競合条件>
並列して動くプロセス間での干渉
シンボリックリンクを用いた攻撃
<lpr 問題>
<プロセスの権限>
実ユーザ ID
実行ユーザ ID
保存セットユーザ ID
<プロセス権限の設定>
親プロセスからの継承
システムコール
setuid, setgid, seteuid, setegid
安全なプログラムにするにはできるだけ特権(root)で動くプロセスをなくす
必要がなくなったら特権をなくす
<シェルの呼び出しの危険性>
コマンドにメタ文字が含まれると予期しないコマンドが実行される.
環境変数 PATH の設定を変更されていると予期しないプログラムが実行される.
環境変数 IFS の危険性
対策: PATH, IFS の再設定,絶対パスにする.コマンド列に意図しない文字

含まれたいないかチェックする. ARGV の上書き,秘密にした
い情報は
引数としてとらない.メモリ上に秘密にすべき情報を残さな
い.コアダンプ
の禁止,コアサイズの上限を 0 バイトにする.

perl

<セキュリティ問題>
スタックオーバフローなどの領域違反の可能性小
汚染(taint)チェック機能
汚れた値を実行時にトレース
重要な操作で引数が taint かチェック
インタプリタ
文字列評価と shell 呼び出しによる潜在的脅威
wapper プログラム
suidperl --- スクリプトの suid を許可
<CGI を利用した不正アクセス>
不正アドレスでコマンド実行
プログラムのバグ
認証の失敗
<perl による危ないプログラムの例>
外部から得た文字は信用しないようにする
<危険性の高い関数>
バッククォート, eval, exec, system
taintmodeを利用(-T オプション)し安全性を高める
<汚染の例>
man perlsec 参照
<汚染された文字の利用>
パターンマッチングで得た値はきれいとされる
パターンマッチングは慎重にすべき
<安全なプログラム>
$ENV{'PATH'} と $ENV{'IFS'} はプログラム中で再設定する.
$< = $>;
実行 uid と実 uid を一致させる.
= seteuid(getuid());

まとめ

与えれらた文字は信じない
特殊な文字が含まれていないか
正しい文字列か
エラーチェックは完全に
全てのオペレーションが正しく動作したことを確認
他とのインターフェイスを最低限に
共有リソースも最低限に
雑なコーディングはしない
責任をもってプログラムは書け
2000/01/03 小高正嗣(odakker@gfd-dennou.org)
2000/01/07 奥山尚範(okuyama@gfd-dennou.org)