doc/ja/security/programmers.sgml
Hiroyuki Hanai d8e498a13a Oops! Encoding must not be ISO-2022-JP!
Convert them to Japanese EUC.

Submitted by: Motoyuki Konno <motoyuki@snipe.rim.or.jp>
1998-07-27 11:27:40 +00:00

205 lines
8.2 KiB
Text

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN" [
<!ENTITY base CDATA "..">
<!ENTITY date "$Date: 1998-07-27 11:27:39 $">
<!ENTITY title "Security Do's and Don'ts for Programmers">
<!ENTITY % includes SYSTEM "../includes.sgml"> %includes;
]>
<!-- $Id: programmers.sgml,v 1.3 1998-07-27 11:27:39 hanai Exp $ -->
<!-- The FreeBSD Japanese Documentation Project -->
<!-- Original revision: 1.1 -->
<html>
&header;
<P></P><UL>
<LI><A NAME="#rule1"></A>どんな入力ソースも信用しないこと. つまり, コマンド
ライン引数, 環境変数, 設定ファイル, 到着した UDP パケット, ホスト名参照,
関数引数など, どれも信用してはいけません. そもそも, 受け取ったデータ長や
内容が各プログラムや関数のコントロール外のものなら, プログラムや関数はそ
のデータをコピーする時に注意をはらうべきです. この種のセキュリティ問題を
挙げると:
<P></P><UL>
<LI><A NAME="#rule1_1"></A>データ境界を越えるような strcpy() や sprintf()
関数の呼び出し. もしデータ長が分かっているのなら, strncpy() や snprintf()
関数を使う (もしくは, それが使えないのなら境界チェックを施した別の物を
組み込む) ようにして下さい. 実際, gets() や sprintf() は今後決して
使われることはありません.
<P></P></LI>
<LI><A NAME="#rule1_1"></A>strncpy() や strncat() 関数の呼び出し. それらの
関数がどのように動作するのかについて理解していることを確かめて下さい.
strncpy() 関数は終端文字 \\0 を付け足さないことがあるのに対し, strncat()
関数は常に \\0 を付け足します.
<P></P></LI>
<LI><A NAME="#rule1_2"></A>strvis(3) や getenv(3) 関数の乱用に気をつける
こと. strvis() は間違ったコピー先文字列を簡単に作ってしまいますし,
getenv() は想定される長さをはるかに越える文字列を返すこともあります.
これらはプログラムへの攻撃でしばしば使われる常套手段の一つで, 環境
変数を予想もしなかった値に設定してスタックや変数を上書きさせるのです.
あなたのプログラムが環境変数を読んでいるのなら, 偏執的にならないと
いけません!
<P></P></LI>
<LI>open(2) や stat(2) 関数を見つけるたびに, "アクセスしようとしている
ファイルがシンボリックリンクだったらどうなるだろう?" と自問して下さい.
<P></P></LI>
<LI><A NAME="#rule1_3"></A>mktemp(), tempnam(), mkstemp() 関数などを使用
しているところでは代わりに mkstemp() が使用されていることを確認して
下さい. 加えて, /tmp の中でアトミックになることはほとんどないという
ことに気づいて, /tmp 中の競合が発生していないか探してみて下さい.
<UL>
<LI>ディレクトリの作成. これは成功するか失敗するかのどちらかです.
<LI>O_CREAT | O_EXCL モードでのファイルのオープン
</UL>
mkstemp(3) はこういったことをあなたのために正しくやってのけてくれま
す. そう, 競合を起こさないで正しい許可権でテンポラリファイルが作成される
ことを保証するには mkstemp() を使わなければいけないのです.
<P></P></LI>
<LI><A NAME="#rule1_4"></A>攻撃者が適当な別のシステムからパケットを
投げたり, パケットを受け取ったりするように強いることができるのなら,
私達が受けるデータを完全にコントロールすることができますし, それらの
*いずれも*信用できないものとなります.
<P></P></LI>
<LI><A NAME="#rule1_5"></A>2.1 と 2.2 における UID, EUID, SVUID の
違いを理解して下さい. 私たちも理解していません. [XXX しかし Bruce と
話し合った後で理解してここを埋めなければいけません]
<P></P></LI>
<LI><A NAME="#rule1_6"></A>設定ファイルが正しいフォーマットになっている,
あるいは関連ユーティリティで作成されている, などと思ってはいけません.
変なことをするチャンスさえあれば, ひねくれたクラッカーがきっとその変な
ことをしでかしてしまうでしょう: 端末名や言語文字列などパス名の中に '/'
や '../../...' といったフリースタイルの文字が入る時はユーザの入力を
信用してはいけません. root 権限で setuid がセットされている状態のときは
ユーザから与えられる *一切の* パス名を信用してはいけません.
<P></P></LI>
<LI><A NAME="#rule1_7"></A>データの格納される方法に関してのセキュリティ
ホールや弱点に気をつけて下さい. テンポラリファイルの許可権はどれも
600 になっていないといけません.
<P></P></LI>
<LI><A NAME="#rule1_8"></A>高い権限で実行する可能性のあるプログラムから
おきまりの問題のコードを見つけるのに grep してはいけません. strcpy()
のような関数がオーバフローをおこすといったことよりも数多くのオーバー
フローのケースがあるので, 1 行 1 行コードを追っていくようにしなければ
いけません.
<P></P></LI>
<LI><A NAME="#rule1_9"></A>必要のない(訳注 root などの)特権を使わない
からといって, (侵入者に)悪用される可能性がなくなるわけではありません.
攻撃者は必要な実行コードをスタックに積んでから /bin/sh を実行しようと
するかもしれません.
</LI>
</UL>
<P></P></LI>
<LI><A NAME="#rule2"></A>UID を管理するようにして下さい. そう, できるだけ
はやく特権を完全に捨て去るのです. EUID と UID とを切替える必要は
ありません. setuid() をできる限り早期に行なえばいいのです.
<P></P></LI>
<LI><A NAME="#rule3"></A>エラーのあった設定ファイルの内容を絶対に画面に
表示しないようにして下さい. 行番号, それから桁数が分かれば十分です.
ライブラリと SUID/SGID が設定されているプログラムにこれらのことが
言えます.
<P></P></LI>
<LI><A NAME="#rule4"></A>セキュリティ問題に関しての, 現存するコードの
レビューのための Tips:
<P></P><UL>
<LI><A NAME="#rule4_1"></A>セキュリティフィックスについてあなたが確信を
持てないのなら, 目を通してもらうためにあなたが整えたコードをレビュー
する人に送って下さい. 安全の名において, かなり厄介な問題を引き起こさ
ないことを確信できないうちはコミットしてはいけません. :)
<P></P></LI>
<LI><A NAME="#rule4_2"></A>CVS コミットの権限のないものは, 変更の
レビューを最後に行った人にその権限があることを確認すべきです. その
人はレビューと最終バージョンのツリーへの取り込みの両方をすることに
なります.
<P></P></LI>
<LI><A NAME="#rule4_3"></A>>レビューする人に変更点を送る時, 簡単に
patch(1) を当てられるようにするために context か unidiff 形式の
diff を使うようにして下さい. ファイルまるごと送らないで下さい!
Diff は簡単に読むことができるし, (とくに複数の場所で同時に行われる
変更の時) ローカルのソースに専念できます. 特定のインスタンスに
伴うような特別な理由でもない限り, 共通の環境をベースにして作業を
簡単にするために, どんな変更も 3.0-current への変更とするように
してください.
<P></P></LI>
<LI><A NAME="#rule4_4"></A>コードを変更をするたびに, レビューする人達に
送る前に直接テストを行う (つまりビルドして該当するモジュールを実行
する) ようにしてください. 明らかに壊れているものをレビューしたいと
思う人はいません. ちゃんとテストするために 2.1, 2.2 や 3.0 上での
アカウントが必要なら言って下さい - プロジェクトはその目的でこれらの
環境を用意してあります.
<P></P></LI>
<LI><A NAME="#rule4_5"></A>コミットする方々へ:
-current パッチが 2.2 や 2.1 ブランチにも合うように必ず心がけて下さい.
<P></P></LI>
<LI><A NAME="#rule4_6"></A>不必要にあなた好みのスタイルにコードを
書き換えないで下さい - それはレビューする人にとって, 必要のない, より
難解な仕事を作るだけです. それをするのに明確な技術上の理由がある時に
だけ行うようにしてください.
</LI>
</UL>
<P></P></LI>
<LI><A NAME="#rule5"></A>単一のハンドラで複雑な処理を行うような
プログラムに気をつけて下さい. いろいろなライブラリ中の多くの関数は,
そのような処理を安全に行えるほど充分にリエントラントには作られて
いません.
<P></P></LI>
<LI><A NAME="#rule6"></A>realloc() の使い方には細心の注意を払って下さい
- 正しく使われていないことは, ないわけではなくむしろ頻繁に起こっている
ことです.
<P></P></LI>
<LI>固定長バッファを使う場合, バッファサイズが変更されたにもかかわらず
コードが sizeof() を使っていないがために発生する問題を防ぐために,
sizeof() を使用するようにして下さい. 例を挙げると:
<LISTING> char buf[1024];
struct foo { ... };
...
BAD:
xxx(buf, 1024)
xxx(yyy, sizeof(struct foo))
GOOD:
xxx(buf, sizeof(buf))
xxx(yyy, sizeof(yyy))</LISTING>
ポインタがポイントしている先のサイズを知りたいときに, ポインタの
サイズを計算しないように注意して下さい.
<P></P></LI>
<LI>``char foo[###]'' を見つけるたびに, foo の使い方をチェックしてオーバー
フローを起こさないことを確認して下さい. オーバーフローを回避できない
(か, オーバーフローが起こり得る) ときは, 最低でもスタックを食い潰さない
ようにするために malloc(3) でバッファ領域をとるようにして下さい.
<P></P></LI>
<LI>できるだけ早い段階でファイル記述子をクローズするようにして下さい.
これは標準入出力バッファの内容を捨て去ることよりも大切なことです.
ライブラリルーチンの中で, あなたが開いたファイル記述子を常に閉じる
ようにしてください。
<P></P></LI>
</UL>
&footer
</body>
</html>