安全なプログラムの作り方
DESCRIPTION
http://rubykaigi.org/2011/ja/schedule/details/17M01 での発表資料です。TRANSCRIPT
安全なプログラムの作り方Secure Programming
西山和広 (@znz)Good-Day Inc.
Powered by Rabbit 0.9.2
Agendaprologue
具体例
まとめ
1/41
prologue (1) はじまりまだ javascript もなかった頃の話
掲示板 (伝言板) CGI がありました(twitter をもっと簡易にしたようなもの)
2/41
prologue (2) 掲示板 CGIHTML のタグを解析して A とか B とかHTML の構造が崩れないものを許可
それ以外のタグ HTML とか HEAD とかBODY とかはエスケープ
エスケープするのは、ちゃんとした HTML を出力するため
3/41
prologue (3) 余談hidden で埋め込んだ文字の文字コードで他のフィールドの文字コード推定もうまくいかないブラウザがあるとか
出力した HTML と同じ文字コードでフォームの内容も送ってくると思ったら、そうじゃないブラウザがあるとか
そういう理由で文字コードは結局自動判別しかなかったというのはまた別のお話
4/41
prologue (4) 変化javascript が普及
onclick などが指定できるようになる
javascript: というリンクも使えるようになる
問題がなかったはずの掲示板が何も変えていないのに脆弱性のあるものになった
5/41
結論永遠に安全なアプリケーションは困難
6/41
対策一般に
入力はちゃんとチェックする
出力はちゃんとエスケープする
多層の対策をするなど
その他環境の変化に注意する
7/41
脆弱性じゃないものが脆弱性になったといえば
URL 入力欄ブラウザの高機能化で脆弱性になったものとして URL 入力
問題点「javascript:」で始まる URL で javascript が実行できる
対策外部へのリンクを意図した入力欄なら「 http: 」または「 https: 」で始まる URL のみ許可
9/41
逆に昔からダメだった例として
GET は冪等に (1)昔から言われていたこと
GET で状態を変化させてはいけない
GET は冪等 (同じリクエストには同じ応答) であるべき
11/41
GET は冪等に (2)HTTP のリクエストメソッドは GET, POST, HEAD など
GET や HEAD は何度リクエストを送っても同じ結果を返すべき (羃等)
書き込みや削除には POST (や REST 風ならPUT や DELETE など) を使うべき
GET で削除できるようにしていたら検索エンジンのクローラーに消されたという話も。
12/41
べきといえば
例えば、/tmp を避け
る
/tmp を避ける (1)/tmp 以下を直接使うのは避けるべき
一時ファイルを作るときなど
特に固定のファイル名で作るのは危険
問題の例symlink attack の危険
Windows で困る
15/41
/tmp を避ける (2)代わりに
Rails なら Rails.root+'tmp' 以下
一般には tmpdir や tempfile などの標準添付ライブラリ
16/41
るびまの記事参照Rubyist Magazine - 標準添付ライブラリ紹介【第 15 回】 tmpdir, tempfile http://jp.rubyist.net/magazine/?0029-BundledLibraries
17/41
tmpdir と tempfile歴史的理由により
tmpdir は e なしの tmp
tempfile は e ありの temp
覚え方tmpdir は dir が 3 文字なので tmp も 3 文字
tempfile は file が 4 文字なので temp も 4 文字
18/41
/tmp といえば
パーミッションは最小限に2006 年の JVN#27365476: the Minnu's filer2 において、使用中のユーザの権限で別のユーザに任意の Ruby スクリプトを実行される脆弱性 http://jvn.jp//jp/JVN27365476/index.html
/tmp 以下に作成される外部との連携用の Unix Socket が誰でも読み書きできるパーミッションになっていた
ファイルを作成するときは umask などに注意
20/41
パーミッションとい
えば
hiki 0.8.6 の脆弱性2007 年の JVN#05187780: Hiki において任意のファイルが削除可能な脆弱性 http://jvn.jp//jp/JVN05187780/index.html
設置する人が出来るセキュリティ向上手段 : ファイルの所有者と実行ユーザを分離
権限一緒 : hiki 本体も削除可能
権限分離 : データしか削除できない
22/41
hiki 0.8.6 の脆弱性の詳細hiki/session.rb の
if /[0-9a-f]{16}/ =~ session_id
が問題で
if /\A[0-9a-f]{16}\z/ =~ session_id
に修正
23/41
正規表現といえば
改行と正規表現 (1)^ $ と \A \z (\Z) を使い分ける
^ : 行頭
$ : 行末
\A : 文字列の先頭
\z : 文字列の末尾
\Z : 文字列の末尾か末尾の改行の直前
25/41
改行と正規表現 (2)^ $ と \A \z (\Z) を使い分ける
Perl では /m を付けない限り ^ $ は文字列の先頭と末尾
Ruby で同じ意味を持つものは \A と \Z
入力全体をチェックするに使うのは ^ $ ではなく \A \z
先ほどの hiki の例で ^ $ を使うと "任意\n#{session_id}\n任意" のように回避できてしまう
26/41
正規表現と文字予期しない文字を通してしまうと危険
何が何にマッチするのか知っておくのは重要
たとえば 英数字なら\w は 1.9 だと 'あ' などにはマッチしない
[A-Za-z0-9] などのように書く方が確実
用途に応じて [[:alnum:]] とか \p{Alnum} とか
27/41
任意の正規表現ユーザ入力から正規表現を作る場合
任意のユーザ入力から正規表現を生成するのは危険
パターンによっては DoS 可能だと思っておいた方が良い
28/41
任意の入力といえば
ログ出力 (1)WEBrickにエスケープシーケンス挿入の脆弱性 http://www.ruby-lang.org/ja/news/2010/01/10/webrick-escape-sequence-injection/
コンソールへの任意の出力を許すのは危険らしい
30/41
ログ出力 (2)RVM がプロジェクトごとの .rvmrc ファイルを確認のため表示する
2011 年の JVN#30414126: Ruby Version Manager におけるエスケープシーケンスインジェクションの脆弱性 http://jvn.jp//jp/JVN30414126/index.html
31/41
ログ出力 (対策)対策
外部入力をログ出力するときには String#dump などを使ってバイナリのまま出力しない
コンソールへの出力でも外部入力を含んだりバイナリを含む場合はエスケープすべき
32/41
エスケープといえば
エスケープは適切にエスケープは出力先に合わせた適切な場所で適切なものを
HTML の属性値なら '' ではなく "" でくくる
エスケープ結果にあった文脈を用意することも必要
<tag attr='#{CGI.escapeHTML(value)'/> では意味がない
javascript のエスケープをしてから HTML のエスケープをするなど多段のエスケープが必要なことも
34/41
多段のエスケープとい
えば
コマンドライン処理 (1)起動元プログラムの中での文字列としてのエスケープ
シェルを経由するならシェルが処理するエスケープ
最終的に実行しようとしているプログラムのコマンドライン処理に対するエスケープ
36/41
コマンドライン処理 (2)コマンドラインを起動するとき
出来るだけ複数引数の system を使う
シェルのエスケープによる面倒は避ける
例: system("svn", "ci", "-m", message, "--", *files)
37/41
コマンドライン処理 (3)チェックポイント
ファイル名に空白が入っていても大丈夫か?
ファイル名が - で始まっていても大丈夫か?
ファイル名に ['"*] などの記号が入っていても大丈夫か? (そもそもそういうファイル名を許可するのか?)
NUL 文字 (\0) が入っていても大丈夫か?
38/41
コマンドライン処理 (4)受け取る側
シェルやシェルスクリプトから起動するときにちゃんと引数を渡せているか?
「alias p='ruby -e "p ARGV" --'」のようなエイリアスを作る
「foo='foo bar'; p $foo; unset foo」などで確認
39/41
まとめ永遠に安全なアプリはほぼ不可能
Web アプリならブラウザなど外部環境の変化
某キャリアの SSL ゲートウェイのような外部要因
入出力は特に気を付ける入力はチェックする
出力はちゃんとエスケープする
ファイル名やパーミッションにも気を付ける
40/41
Questions?