2003年06月18日(水)

ニフティのWebフォーラムのXSS脆弱性

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - ニフティのWebフォーラムのXSS脆弱性

えび日記2003年6月18日(水曜日) XSS大王でニフティのWebフォーラムのXSS脆弱性について述べられている。何も考えずに作ってるなーという感じを受けていたが、本当に何も考えずに作っていたとは。さすがはニフティ。個人的にはなぜ今ごろばけらさんがニフティのWebフォーラムの脆弱性を発見したかという当りに興味があったりしますが。

ちなみに私による一部の情報というのは、掲示板のタグの中に属性を書きまくれるのでJavaScriptでやり放題という脆弱性である。そもそもこれはイルカさんがstyle属性だけでなくonclickとかも書けるので便利に使えるとか発言していたのを私が見ただけなので、発見したのは私ではない。報告しようかなあと思ったのだが、とりあえず発言者のIDから攻撃者の身元は分かる(はず)だから、きっと「やるならやってみろ」でIt's by designなのだろうと勝手に納得してやめたのだった。面倒だし。

2003年07月15日(火)

404エラーページの脆弱性

カテゴリ: Web, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 404エラーページの脆弱性

ばけらさんに404エラーページのXSSを発見されてしまった。恐るべき執念(謎)。HTML::Templateのescape="1"を覚えた私には3秒で直せるホールだが、そっちよりもいやんな問題を発見してしまった。うちの404ページは移動したページやリンク切れなどを判定して適宜エラーメッセージを出している。リンク切れの判定はRefererとリクエストURLが自サイトの時という条件で行っているのだが、掲示板の書き込みで自サイトへの存在しないリンクを記載されると、それもリンク切れと判定されてしまうのだ。私のせいではないのに。

404ログにきっとばけらさんがアタックした痕跡が残っているだろうと思って見てみると、なんか別のアタックの痕跡が。himituディレクトリの下をひたすら総当りで調べている感じ。1秒1リクエストなのが意外に良心的。いやなにが。.txt から始まって英数字をすべて試しつつ n2k.txt まで行ったところで飽きたのか、それとも恐ろしく時間がかかることに気づいたのか、そこで終了していた。それでも6時間くらいかかっているのだが。

2003年10月09日(木)

パスワードはCGIスクリプトに直接書かない

カテゴリ: セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - パスワードはCGIスクリプトに直接書かない

IPA ISEC セキュア・プログラミング講座

基本的なことばかりだが、「2-2. スクリプトに埋め込まれたDBパスワード」はちょっと目からうろこだった。曰く、スクリプトにDBパスワードを書いてはいけないと。ならどこに書くのん? というと、ライブラリやモジュールなど、Webから見えないところにあるファイルに書けと。こうすればうっかりスクリプトのコードがWebに晒されてしまったとしても、パスワードは見ることができない。なるほど。「人に見られてはいけないものは、そもそもWebから見えるところに置いてはいけない」という原則は、コードの一片にでも適用すべきものということなんだねえ。

2003年10月28日(火)

htpasswdコマンドは脆弱?

カテゴリ: Web, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - htpasswdコマンドは脆弱?

Webのベーシック認証のパスワードを設定するためのhtpasswdというコマンドがある。このコマンドを普通に起動すると、標準入力からパスワードの入力を求められる。その他にバッチモードというものがあって,プログラムで処理しやすいように「htpasswd -b ユーザー名 パスワード」という形式でパスワードが設定できるようになっている。この時、パスワードの部分には生のパスワードが入る。これってセキュリティ的にまずくないだろうか。CGIの環境変数にAuthorizationフィールドが入らなくなったのは、他のプロセスから環境変数が参照できるのでパスワードがダダ漏れという理由からで、確かコマンドラインも他のプロセスからも見れたはず。

2003年11月29日(土)

互換性の高いウイルス

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 互換性の高いウイルス

スラッシュドット ジャパン | WindowsベースのATMがNachiに感染

そんなものの上で動くWindowsでもちゃんと感染できるほど高い互換性を持っていることを褒めるべきなのだろうか(謎)。

2003年12月08日(月)

整数演算オーバーフローの脆弱性

カテゴリ: セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - 整数演算オーバーフローの脆弱性

RTCでrsyncの脆弱性の話でちょびっと盛り上がる。malloc()で確保するメモリサイズはchar単位で指定するので、int配列を確保する場合は配列の長さにsizeof(int)を乗じることになる。配列の長さ自体はsize_tに収まるとしても、その整数倍が収まるとは限らない。オーバーフローするとまず間違いなく元の数よりも小さくなるので、ここに脆弱性を生むポイントがある。たとえ配列の添え字で範囲チェックをしたとしても、実際に確保された領域はそれよりも狭いので、バッファオーバーフローが発生する。

で、Javaなら大丈夫という話になったのだが、実際のところどうなのだろう。確かにJavaなら不意なアクセスは行いようが無いが、そのかわりに例外が投げられる。キャッチされない例外の末路はプロセス終了であり、もしそれが何かのサーバプロセスであればDoS攻撃が可能ということになる。たとえJavaプログラマであれど、配列の範囲を超えてアクセスしたから何々するというコードを全ての配列アクセスに対して書くことはないと思うので、JavaであってもDoS攻撃は可能だと思われる。

2004年03月05日(金)

新聞に不正侵入のお知らせ

カテゴリ: Web, その他, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 新聞に不正侵入のお知らせ

新聞にはたまに製品の回収などの広告が載っている事がある。私はわりとこれが好きで常にチェックしてしまうのだが、今日の朝刊(読売新聞)を見ていたらJALビジネスのWebサーバに不正侵入されて云々という告知があった。わ、わざわざ新聞でお知らせするなんて、いったい何があったのだろう。

2004年03月07日(日)

自称セキュアフォーム

カテゴリ: Web, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 自称セキュアフォーム

YahooBBモバイルは現在試験サービス中なので申し込めば無料で利用することができる。せっかくAirMacカードを付けたのだからと、「Yahoo! BB - ADSLサービス申し込み」から申し込みを行おうとした。が、ログインボタンを押すとSafariが「これはセキュリティ保護されていないフォームです」という警告を表示する。httpsなのになんでー? と思ったらななななんと、フォームのPOST先が普通のhttpなのだった。……えーと、その。 いくらなんでもそれはないんじゃないでしょうか。というかボタンの横にある意味あり気な鍵マークはダミーですか。

2004年03月08日(月)

XSSっぽい何か

カテゴリ: Web, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - XSSっぽい何か

インフォシーク ヘルプ → メールについて
おそらくWebメール機能のFAQだと思われるが、「15. 文字化けしてメールがよめません!」に気になる記述がある。

半角のカタカナ、句読点(、。)や、カギカッコ(「」)、不等記号(<>)

カタカナ、ひらがな、漢字は、2バイト文字(いわゆる全角文字)を使用する方が安全です。
→ご利用の辞書(IME)によっては最初の変換に出てくる場合もありますのでご注意ください。
特に半角の不等記号(<>)を使用した場合、かなり高い確率で文字化けが発生いたします。
「絵文字」や「顔文字」のご使用は、できるかぎりお控えください。

半角カナと半角カナ系の記号類に付いてはまあ良いだろう。が、< > で化けるというのは納得がいかないというか、単に未知のタグとしてブラウザに無視されたりした結果を「化けた」としているような感じがひしひしと。もしそうならアレなわけで、そうではなく理解不能な謎の仕様で化けるのか、もしくはFAQの内容がもう古くなっていると思いたい(謎)。

2004年04月21日(水)

TCPのRSTを投げかける攻撃

カテゴリ: セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - TCPのRSTを投げかける攻撃

スラッシュドット ジャパン | TCPに容易にDoS撃を可能とする脆弱性

もはやこんなところにも気を遣わなければならない時代になったんだなあ。というか、ただひたすらパケットを投げつけると、うん十万分の一の確率で成功するかもしれないというつまらない攻撃をやるような人がいそうな時代になったというか。攻撃成功の確率が上がるのは何か新しい手法が編み出されたとかではなくて、現状を鑑みたら考えているものとは違ったということのようだ。

TCPでは輻輳制御の為にシーケンス番号とウインドウサイズという情報をやりとりしている。シーケンス番号は簡単に言うとストリーム上のバイト位置で、「この位置のデータです」とか「この位置まで受け取りました」という様に使用する。シーケンス番号の初期値は個々の接続ことに決められ、接続開始時に「シーケンス番号の初期値はxxです」というようなやり取りが行われる。様々な都合上、この初期シーケンス番号は接続ごとにバラバラの値が使われる。

ウインドウサイズは受信バッファのサイズで、受信完了のシーケンス番号とウインドウサイズによって「今受け取れるのはストリーム上のここからここまでです」という情報を刻々と相手とやり取りしている。この範囲外のパケットが来た場合、「期待しているのはこのシーケンス番号からのデータです」と答えてパケットを突っ返すようになっている。

RSTはTCPのパケットに付くフラグのひとつで、接続のリセットを示す。プロセスがTCPで接続中に異常終了してしまった場合、OSは接続の相手にこの接続がもはや有効ではないことを通知しなければならない。このような時に使用するのがRSTフラグで、切断というより断線に近い形態の切り方である。

やり取りされるシーケンス番号はストリームを隙間なく埋めなければならないので、受取り可能なシーケンス番号は接続の両端のホストしか知りえないはずである。たとえ知らなくても総当たりで行けば、いつかは有効なシーケンス番号にヒットするが、シーケンス番号は32ビット符号無し整数なので、攻撃成功の確率は1/232となる。

が、IPはパケットが到達する順序も、到達するかどうかも保証していないので、RSTが来る以前のパケットが失われているかもしれない。続き番号のシーケンス番号を期待しているとうまくRSTによって切れない可能性があるので、ウインドウサイズ内なら有効なRSTとしているのだと思われる。現在よく使われるウインドウサイズは割と大きめで、たとえばWindows XPでは初期ウインドウサイズは64KBである(スケーリングオプションを使用しない場合の上限)。つまり無作為に選んだシーケンス番号のRSTパケットがヒットする確率がシーケンス番号ちょっきりより65536倍上高いということになるわけだ。

2004年07月15日(木)

スワップファイルからパスワードが漏れる

カテゴリ: Cocoa, Mac, セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - スワップファイルからパスワードが漏れる

スラッシュドット ジャパン | Mac OS X: スワップファイルからパスワードが漏れる?」より。

パスワードを保持していたメモリ領域がスワップアウトされてしまうと、暗号化されていないパスワードがHDDに書き込まれてしまうという話。スワップファイルをgrepすると、というのはさほど重要なことではない。スワップファイルはrootでなければ読めないし、rootであればprocfsなどからプロセスのメモリ空間をいくらでも覗くことができるので、スワップファイルをあさるという間接的な方法を取る必要は無い。問題は生パスワードがHDDに意図せず書き込まれてしまうことだ。

ファイルは、たとえその存在が消去されたとしても、その存在を復活させたり、または内容の一部を取り出すことが可能である。また、磁気記憶装置の記録内容はかなりしつこく消えないので、なにかのデータで上書きされたとしても、パスワードを取り出されてしまうかもしれない。そんなところに生パスワードが書き込まれてしまうのはいただけない。

このような問題をなるべく避ける為の、プログラムでパスワードを扱う際の定石というものがある。

  • パスワードを書き込むメモリ領域を物理メモリに固定する
  • 使い終わったら速やかにゼロクリアする

言われてみればごもっともで、実施するのは難しくはない感じがするが、ではCocoaでこれをどうやるのかと言われるとかなり困る。まずメモリ領域を物理メモリに固定する方法がFoundation KitにもApp Kitにも無い。CarbonにはHoldMemory()というAPIがあるが、これをCocoaとまぜこぜで使う方法が思い浮かばない。使い終わったらゼロクリアの方はもっと致命的で、文字列オブジェクトを破棄する前にゼロクリアしたらオブジェクトが壊れ、破棄した後にクリアしようとしたら無効なメモリアクセスが発生するかもしれず、二進も三進も行かない。自前でSecureStringクラスなどというものを作れば、自分で生成して自分で破棄する分には何とかなるが、ライブラリが返してくる文字列に対しては無力である。

この辺りの問題はCocoaだけでなく、メモリ確保と破棄というプリミティブな操作をプログラマが明示的に行わない処理系全てに当てはまるのではないだろうか。Ruby、Perl、Java、C#はともかく、C++も例外ではないと思う。そういえば一応セキュア度アップに邁進しているMicrosoftの、.NET Frameworkではその辺りはどうなっているのだろう。

2004年07月20日(火)

NSZone

カテゴリ: Cocoa, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - NSZone

パスワードを記録していたメモリ領域を使用後に0クリアするというのをCocoaでどうやるかという問題について、NSZoneを使用するのはどうだろうかと考えてみた。専用のゾーンをひとつ作り、オブジェクトをそのゾーンで確保する。オブジェクトを破棄したら、すかさずゾーン全体を0クリアする。オブジェクトが破棄されてもゾーン自体は生きているので、アクセスしても問題無いはず。

と思ったら、ゾーンの先頭アドレスとサイズを得る方法が無いのだった。終了〜

2004年11月11日(木)

MacOS XのWarning Banner

カテゴリ: Mac, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - MacOS XのWarning Banner

なんと、AppleのJavaランタイムでは、この警告表示が出ないようだ。脆弱性発見?

2005年05月05日(木)

Safariの証明書表示

カテゴリ: Mac, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - Safariの証明書表示

MacOS X 10.4 のSafariでは、ようやくSSLのサーバ証明書を表示できるようになった。いままでは単なる絵だった鍵マークをクリックすると、下記のようなシートが表示される。

[Safariの証明書シート]

必要な情報が一目で確認できてなかなか良い感じである。組織名とかも表示した方が良いような気もするが、「詳細な情報」の横の三角形をクリックすれば見られるので、それはそれでいいのかもしれない。

オレオレ証明書など、検証できない証明書については、従来のSafariでも警告が出るようになっていたが、肝心の証明書を見ることができないので割と意味が無かった。10.4のSafariではこれも改善され、証明書が見られるようになったばかりか、信頼するかどうかの指定もできるようになった。信頼する為には、証明書のフィンガープリントを確認して、それが本物かどうかを確認する必要があるのだが、肝心のフィンガープリントは詳細情報の一番下にある為(「指紋」という見出しになっている)、ちょっと確認しづらいのが難点。まあ、そんなことをせずに、キーチェーンに証明書を追加して信頼する設定にするというのが真っ当な使い方なのかもしれない。

[検証できない証明書についての警告シート]

2005年05月06日(金)

証明書アシスタント

カテゴリ: Mac, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 証明書アシスタント

キーチェーンのユーザーインタフェースである「キーチェーンアクセス」は、MacOS Xのバージョンアップごとに着実に進化していっている。10.4では本体がiアプリ風になった他、証明書アシスタントというものが付くようになった。証明書アシスタントでは、証明書、認証局、証明書要求を簡単に作ることができる。

大抵の環境では、ルート認証局からの階層的な信頼設定しかできないため、自己証明書を作っても、それを利用することは難しい。かといって独自の認証局を作るというのはリスクが大きい。したがって自己証明書や認証局が簡単に作れたからといって、ものすごく便利というわけでもない。が、MacOS Xでは証明書ごとに信頼設定を行うことができるので、自己証明書を作れれば、PKIがぐっと身近になる可能性がある。ただし会えない人同士では利用できない。証明書のやりとりには信頼できる経路が必要だが、証明書の交換前の段階では信頼できる通信経路が無いため、実際に会って交換する以外に方法が無いためだ。

Mac系雑誌で取り上げられれば普及しそうな気がするが、普通の人がメールに暗号化やデジタル署名するかといわれると微妙。

2005年05月29日(日)

addslashesとSQLの特殊文字

カテゴリ: PHP, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - addslashesとSQLの特殊文字

PHPには、SQLの文字列リテラル内に埋め込めるよう特殊文字をエスケープするaddslashes関数というものがある。SQLを組み立てる際はこれでエスケープするというのが定説だが、なぜかpg_escape_stringmysql_escape_stringというのもある。これはどういうことなのだろう。addslashesでは不足ということなのだろうか。

IPAセキュアプログラミング講座:[2-1.] SQL組み立て時の引数チェックの「入力文字列はエスケープしよう」の部分によると、DBMSによって特殊文字に違いがあるらしい。JetエンジンのVBAステートメントが書けるというのもスゴイが、それより一番驚いたのが ' をエスケープするには '' とするという点だ。addslashesでは特殊文字の前にバックスラッシュを入れることで無効かを行う訳だが、それではシングルクオートはエスケープできないということになる。えーと、その、大丈夫なんでしょうか。

MySQLの場合はバックスラッシュでエスケープなので、MySQLを使っている場合はならaddslashesでもうまく行くということらしい。つまりMySQL専用? PostgreSQLの場合は両方の形式が使えるので大丈夫らしいが、SQLite用のsqlite_escape_stringにはaddslashesを使うなという警告が書かれている。とはいえaddslashesの方にそういう説明を書かないとはまる人続出なような気がするのだが。というかすでにはまっているシステムがありそうな予感。

2005年06月11日(土)

xp_cmdshell

カテゴリ: Windows, セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - xp_cmdshell

データベースシステムにはストアドプロシージャというものがある。SQLでは行えない複雑な処理やDBMSに依存するような処理を行う為に、別途定める言語で記述した処理をデータベースに登録し、クライアントから呼び出すことができるという機能だ。多くのプログラミング言語では、言語環境の外にある機能を使えるようにするために拡張ライブラリという仕組みが用意されている。ストアードプロシージャでもそのような仕組みが用意されている場合があり、それを拡張ストアードプロシージャという。

Microsoft SQL Serverでは、恐ろしいことに、任意のコマンドを実行することができるxp_cmdshellという拡張ストアードプロシージャが標準で用意されている。これが何を意味するかというと、SQLインジェクションの脆弱性があると、もれなくOSコマンドインジェクションの脆弱性もあるということだ。ちなみにxpはWindows XPではなくextended procedureの略らしい。

これで色々納得がいった。カカクコムの不正アクセスの話で、攻撃方法はSQLインジェクションらしいという噂が出ていたが、それでどうしてサイトが改竄できるのかがどうにも理解できなかった。任意のコマンドが実行できるならそれも可能だろう。

2005年06月20日(月)

Safariのオレオレ証明書を常に信頼する設定

カテゴリ: Mac, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - Safariのオレオレ証明書を常に信頼する設定

Safariで信頼できない証明書を使用したhttpsなページにアクセスすると、構わずアクセスするかやめるかどうかを確認するためのシートが表示される。そこに「これらの証明書を常に信頼する」というチェックボックスがある。おそらくここにチェックを入れると次回以降は例の確認シートが表示されなくなるのだと思うのだが、チェックを入れても相変わらず表示されるのはなぜだろう。信頼設定は「常に信頼する」に変化しているのだが。うちの10.4が変なだけなのだろうか。なんだかシステム環境設定のSpotlightもうまく動かないし。

2005年07月01日(金)

ruby-1.8.2標準ライブラリのXMLRPCに任意のコマンド実行の脆弱性

カテゴリ: Ruby, セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - ruby-1.8.2標準ライブラリのXMLRPCに任意のコマンド実行の脆弱性

オブジェクト指向言語Ruby - XMLRPC.iPIMethodsの脆弱性について

指定したオブジェクトが持つメソッドを自動的に公開するサービスがあって、それがうっかり祖先のメソッドまで公開してしまうようになっていたため、Objectクラスが持つsystem()なども公開され、その結果、任意のコマンドをリモートから実行できてしまうということらしい。

詳細は公開されていないが、原因はパッチを見れば一目瞭然である。オブジェクトが持つメソッドの一覧を取得するのにModule#public_instance_methodsを使用している。このメソッドは祖先が持つメソッドも含めるかどうかのフラグを引数として与えるようになっているが、この引数はデフォルト値を持っているので省略可能である。XMLRPCでは省略して使っていたが、1.8より前のデフォルト引数は偽であり、祖先が持つメソッドは含まれないようになっていたため、問題は無かった。が、1.8以降からデフォルトが真に変わるという恐ろしいことが起こり、脆弱になってしまったというわけだ。

この件はデフォルト値に頼ると痛い目に会うという教訓を見事に体現しているだろう。デフォルト値を暗黙のうちに想定して使っているような場合は、想定している値を明示的に指定するべきである。デフォルト値に頼っていいのは、どれに転んでも別にこだわらないときだけだろう。

こういう問題があるのでデフォルト値というのはそう簡単に変えられるものではないと思うのだが、これはなんで変更されたのだろう。いちおう理由があると思うのだが。

2005年07月13日(水)

HTTP Request Smuggling

カテゴリ: Web, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - HTTP Request Smuggling

セキュリティホールメモ: HTTP Request Smuggling

smugglingとは密輸という意味で、プロキシサーバなどの中間サーバに感知させないでオリジンサーバにHTTPリクエストを送りつけられるという脆弱性である。中間サーバにはIDSなどリクエストの内容を見て危険そうなものを叩き落とすといった機能を持つものがあるので、これを回避されるのは大変問題である。また、中間サーバのキャッシュ汚染によるXSS脆弱性も発生する可能性がある。

この脆弱性の原因はHTTPリクエストのバイト長の解釈の揺れである。HTTPの持続性接続では、ひとつのTCP接続で複数のリクエスト/レスポンスの組がやり取りされる。各リクエストの境界は直前のリクエストの長さに依存しているが、その長さを示す方法は複数あり、しかも冗長性をもつ方法もある。たとえばContent-Lengthヘッダフィールドが複数あるリクエストを許容してしまうサーバがあった場合、どのContent-Lengthヘッダフィールドを採用するかは実装しだいだろう。この解釈の違う中間サーバとオリジンサーバを組み合わせて使用した場合に、一方がリクエストと認識しない(直前のリクエストのボディの一部と解釈してしまう)ものを送信できるため、こっそりとリクエストを送り付けることが可能になるというわけだ。

この脆弱性を回避するには、解釈の方法を変えたり、エラーレスポンスを返すようにするだけでは駄目である。解釈の方法を変えるのが駄目なのはすぐに分かる。複数の解釈が存在し得る以上、自分とは異なる解釈をするものと組み合わせれば脆弱性が発生してしまうからだ。そもそもの問題は、とあるリクエストの解釈の影響が、後続のリクエストの解釈に影響してしまうことにある。エラーレスポンスを返すようにしても、そのまま後続のリクエストが送られてしまうことには変わりがない。つまり、この脆弱性を回避するには持続性接続を切断するしかないのだ。幸い、いつでも予告無しに切断できるので、曖昧なリクエストが来た場合は切断してしまえばよい。

リンク先のページにApache は、Apache 自身が中間機器でない限りは安全だとされているという分かったような分からないような文があるが、これはおそらくApacheにはリクエスト解釈のバグはないということなのだと思われる。事例のいくつかには、オリジンサーバ側のバグを利用して中間サーバが解釈しないリクエストを潜ませるというものがある。この場合はオリジンサーバ側が脆弱性の原因となるわけだが、Apacheではそういうことは起こらないということなのだろう。ただしApacheとリクエストの解釈の仕方が違うサーバが存在している可能性は否定できないので、中間サーバとした場合には分からないという訳だ。

2005年08月31日(水)

(?{})

カテゴリ: Perl, セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - (?{})

Perlの正規表現では、(?{ コード })という記述を用いることで、パターンマッチ中に任意のコードを実行することができる。

$ perl -e '"aaa" =~ /(?{print "OK"})/'
OK

検索CGIなどでは、検索条件として正規表現が使えるものがある。Perlで実装されている場合、まず間違いなく入力された正規表現をそのままm//に渡しているだろう。正規表現中に任意のコードを含ませることができるということは、つまりそれって脆弱性? と思ったらPerl自身がちゃんと考慮していた。さすがはPerl。PHPとは違いますな。

$ perl -e '$re = "(?{print ¥"OK¥"})"; "aaa" =~ $re;'
Eval-group not allowed at runtime, use re 'eval' in regex m/(?{print "OK"})/ at
-e line 1.

エラーメッセージにある通り、パターンマッチ内に直接書かれていないものは許可されないのである。どうしても使用したい場合はプラグマuse re 'eval'を指定する必要がある。実際にはその上でtaintモードを有効にし、さらに汚染除去した文字列を使用する必要がある。

Perlではqr//という記法でもってあらかじめ正規表現オブジェクトを生成する方法もある。ここに例のあれを記述したらどうなるのか。

$ perl -e '$re = qr/(?{print ¥"OK¥"})/; "aaa" =~ $re;'
panic: top_env

panicって一体……

2007年12月02日(日)

SSLの特殊性(1)

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - SSLの特殊性(1)

共通鍵暗号を用いた暗号化通信と、公開鍵暗号を用いた暗号化通信では、ひとつだけ重要な違いがある。それは公開鍵暗号を用いた通信では、全くの見ず知らずの人とも暗号化通信を行えるという点である。共通鍵暗号を用いた通信では、自分の持っている鍵と同じものを、何らかの方法で通信相手にも持たせる必要がある。そういった経緯がある以上、鍵を渡しようも無い全くの見ず知らずの人とは暗号化通信を行うことは出来ない。また、その過程から、暗号化通信を行うことが出来れば、それがすならち自分の意図した相手だという証明にもなる。

だが、公開鍵暗号を用いた通信では、事前に鍵を相手に渡す必要がないため、全くの見ず知らずの人とも暗号化通信を行えるのである。共通化暗号を用いた通信では、暗号化通信ができることが身元証明になったが、公開鍵暗号を用いた通信では、誰に対しても暗号化通信ができるため、それは証明にならない。せっかく通信経路を暗号化して盗聴を防いだとしても、肝心の相手が偽物だったら全く意味がない。したがって、何らかの手段を用いて、自分の意図した通信相手であることを確認する必要がある。

続く

2007年12月03日(月)

SSLの特殊性(2)

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - SSLの特殊性(2)

共通鍵暗号を用いた通信では、通信相手が意図した相手かどうかが重要になる訳だが、それはどうやって確認する事ができるのだろうか。結局のところそれは公開鍵暗号でも事情は変わらす、相手が持っている鍵が自分の意図した通信相手のものであるかどうかということになる。ただ、共通鍵暗号と異なるのは、識別に使う鍵は公開鍵であるため、第三者に知られてしまっても問題無いという所にある。したがって公開鍵は相手を識別するためのIDとして使用できる。

最も簡単で確実な確認方法は、あらかじめ入手しておいた相手の公開鍵と、通信相手の公開鍵を照合する方法である。SSHはこの方法を使用しており、未知の公開鍵を持ったサーバに接続した場合、その公開鍵をユーザーに示し、本当に意図したサーバなのかを確認させるようになっている。この方法では事前に接続先サーバの公開鍵を入手しておく必要があるが、そもそも事前にアカウント情報を入手しておく必要があるため、その点はまったくデメリットにならない。アカウント情報と共にサーバの公開鍵を貰えばいいだけのことだ。

《続く》

2007年12月04日(火)

SSLの特殊性(3)

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - SSLの特殊性(3)

結局のところ、共通鍵暗号を用いたとしても、全くの見ず知らず同士では安全な通信を行うことはできない。双方とも公開鍵という偽り様のない情報を提示する事はできるが、その公開鍵が目的の相手の所有しているものかを、事前の情報無しに検証することはできないのである。相手の真贋を確認することができない以上、たとえ通信経路が暗号化されていたとしても、それは安全な通信とはいえない。

とはいえ、ネット通販の分野など、一見さんのお客でも安全な通信を行いたいという要求もあるわけで、それを実現しているのがSSLである。したがってSSLには相手の真贋を確認する方法が盛り込まれている。 では、SSLでは初見の人の真贋を事前の情報無しにどうやって判断しているのだろうか。

一見難しそうだが、その方法は意外と単純である。当事者同士での証明が無理ならば、第三者に証明してもらうのだ。互いに信頼している第三者の言うことならば信頼しようという訳である。結局のところ互いに信頼している第三者という繋がりが必要になるので、本当に何も取っ掛かりの無い人とは安全な通信ができないのだが、直接の知り合いでなくても可能という点は大きい。

この「第三者」のことを「認証局」という。認証局は公開鍵の持ち主の情報を証明書という形で提供する。 証明されたい側は認証局に証明書を発行してもらい、確認したい側はその証明書の発行者が自分の信頼している認証局のものかを確認する。ここで注意が必要なのは、信頼できるのはあくまでも相手の出した証明書が本物という点だけであって、相手が信頼に足るものかどうかは証明書の中身等を見て判断する必要がある。

SSLはこのように公開鍵暗号を用いつつ直接の知り合いでなくても安全な通信を可能としているため、色々とややこしいことになっている。

2008年04月28日(月)

脆弱性攻撃の良い描写

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 脆弱性攻撃の良い描写

θ(シータ) 11番ホームの妖精」という本を読んでいたら、なにげに良い描写があったので引用してみる。

よく(「よく」というほどさせませんけれど)アリスにコンピュータの不正規侵入をしてもらうと事もなげにこなすのでたまに誤解しそうになりますが、ハッキングというものはたとえば「泥棒さんが民家の鍵をピッキングする」ほど簡単なことではありません。多くの場合はアリスのデータベース、またはオンラインの様々な情報から総合して得られたセキュリティ・ホールを用いて、認証システムを回避します......と言っても分かりづらいと思いますが、要は「玄関の鍵が開かないので窓がベランダの鍵が開いていないか一つ一つ調べていく」ようなものです。

ライトノベルとしては全くもって夢の持てない説明である。ちなみに「アリス」というのはその世界で言うところの第七世代人工知能。うっかりしていると問題領域を全数探索していて、その結果をすべて報告しようとしたりする気の利かないコンピュータでである。

セキュリティホールを突いた攻撃というと高い技術が必要になるようなイメージがあるが、実際には空き巣と変わりがないレベルである。とはいえ攻撃には僅かな隙を突いて攻撃するという特殊な技術を必要とするが、防御の方はそういうものが必要ないため簡単である。閉まっていない所を探してとにかく閉めれば良い。よくハッカーに対抗するにはハッカーをという話が出たりするが、攻撃技術の大半は防御には必要ないのである。防御には地味なイメージが付きがちだが、攻撃も割と地味な努力の積み重ねなのだ。

2008年05月12日(月)

SQL ServerのExecute文

カテゴリ: セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - SQL ServerのExecute文

SQL Serverにはxp_cmdshellというよく悪用される拡張ストアドプロシージャがあるのはその筋では有名な話だが、実はもうひとつExecute文というものがある。これはスクリプト言語でおなじみのevalと同等の機能を持っている。つまり任意の文字列をTransact-SQLとして実行できるのである。

何の目的で用意されたものなのかわからないが、通常のクエリーやストアドプロシージャではExecute文の活躍の場は無いように思える。AIのように自己進化するプログラムならば話は別だが、一般的なアプリケーションでは仕様として盛り込まれていない処理を行う必要は無いので、造り付けの処理をを条件分岐などで切り替えるだけで済む。

そんな使い道のなさそうなEexecute文が最近話題になっているSQLインジェクションによるウェブサイト改竄で有効に使われているのが皮肉なところである。

全テーブルの全カラムの値を書き換えるには、スキーマの情報を取得し、それを使用してUPDATE文を組み立て、実行するという3つのステップが必要になる。通常この攻撃を行うためにはスキーマの情報を攻撃対象から抜き出して、手元でUPDATE文を組み立て、さらにUPDATE文をインジェクションしなければならない。これはかなり手間のかかる作業になるので、よほどの理由が無い限り行使されないものと言えるだろう。だがExecute文が使えれば、すべて攻撃対象のサーバ内で完結させることができる。固定のSQLをインジェクションして、あとは待つだけで良いのだ。まったく簡単である。

Execute文は文であるので、それ自体の使用を禁止することはできないようだ。Transactg-SQLはそれ自体がストアドプロシージャを記述するための手続き型言語も兼ねているので、SQL ServerでのSQLインジェクションは、単なるSQLインジェクションとは別次元のものになっているような気がする。

2008年09月25日(木)

MySQLのカラム切り捨て脆弱性

カテゴリ: セキュリティ, プログラミング このエントリーを含むはてなブックマーク はてなブックマーク - MySQLのカラム切り捨て脆弱性

WordPress 2.6.2で修正された「mt_srand and not so random numbers」と「MySQL and SQL Column Truncation Vulnerabilities」のうち、MySQLの方は他のアプリケーションでも影響しているものがありそうな感じがする。セキュリティ上の問題まで行かなくても、意図しない挙動になっていたりしないだろうか。

この問題はMySQLの以下の2つの挙動によって起る。

  • INSERT、UPDATE文でカラムの長さ以上の文字列を挿入しても、エラーにせず文字列末尾を切り捨てたものを挿入する
  • WHERE句での文字列の比較は、文字列末尾のスペースを切り捨てたもので行われる

論理削除を行えるようにした場合、カラムに一意制約を付けられないため、アプリケーション側で一意性チェックを行うことで、一意性が保証されるようにすることがある。が、この2つの挙動を利用すると、データ登録時の一意性チェックをすり抜けることが出来てしまう。 まず、重複させようとする値の末尾にカラムの最大長までスペースを付け、その後ろにスペースでない文字を付けたものを用意する。一意性チェックでは、テーブルを検索して同じ値がないことを確認する訳だが、スペースではないものは切り捨てられないので、この文字列は既存の値とはマッチしない。一意でないことが確認できたので、この文字列はテーブルに挿入される。すると末尾の文字が切り捨てられ、末尾はスペースのみになる。MySQLは末尾のスペースを無視して検索するので、データを取り出す時には、スペース有り無しの両方がマッチしてしまう。1件しかマッチしないという前提で作られた処理がどうなるかは実装次第だ。

入力時に文字列の長さチェックを行っている場合、末尾の切り捨てが起るような文字列が挿入されることがないため、この問題はかろうじて回避されている。根本的な解決方法は、MySQLのSQLモードにSTRICT_ALL_TABLESかSTRICT_TRANS_TABLESを指定して、カラムに不正値を挿入した時にエラーになるようにすることである。その他のMySQL独特の挙動を抑制するためにTRADITIONALを指定する方が良い感じではあるが、アプリケーションがその挙動に依存している可能性もあるので、変更するのは難しいかもしれない。

ちなみにカラム切り捨ての方は、文字コードを指定せずにテーブルを作った場合に問題になる場合がある。たとえばMobavle Typeのエントリータイトルに255文字以上入力して保存すると、末尾の文字が化けてしまう場合がある。これはMovable Type側はUTF-8の文字列を送っているが、MySQL側はISO-8859-1として扱うので、UTF-8の途中のバイトで切り捨てられてしまうためである。

2008年09月28日(日)

マニュアルでそれ以外の何かであると偽装することが勧められているPHP

カテゴリ: PHP, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - マニュアルでそれ以外の何かであると偽装することが勧められているPHP

PHPのマニュアルのセキュリティの部分を見ていたら、「PHPの隠蔽」というページを見つけた。内容がすごく気になったので読んでみたら、なんのことはない、単にURLの拡張子をphp以外にするというものだった。別にどうということはないものだが、挙げられている例がアレだ。件のページでは1つ目の例として以下のものが挙げられている。

例1 PHPを他の言語として隠す

# PHPコードを他のコード型のようにする
AddType application/x-httpd-php .asp .py .pl

いきなり偽装ですか!

なんというか、順序的には拡張子をhtmlにする方を先に出すべきではないだろうか。静的なHTMLが置き辛くなるというパフォーマンス上の課題があるとしても。

それはそれとして、この拡張子の偽装は、PHP自体に脆弱性がもりもりあった時代には効果があったかもしれないが、今の世では役に立たないだろう。今の攻撃の主流はXSS、SQLインジェクション、CSRFなどで、これらの脆弱性は言語やフレームワークに関わらず基本的な攻撃方法は同じである。したがって動的コンテンツであると判断された段階でそれらの攻撃を仕掛けられる可能性があり、他の言語に偽装しても攻撃されることには変わりない(拡張子がphpというだけで脆弱だと感じる人を除く)。静的なhtmlを装えば攻撃者やgoogle検索除けの御利益があるかもしれないが、そんな天命を待つよりも人事を尽すべきだろう。

2008年10月07日(火)

出力処理のホワイトリスト

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 出力処理のホワイトリスト

話の経緯はともかくとして、誰にも理解されなかった「出力時におけるホワイトリストの利用」というのは、おそらく以下のようなやり方のことを言っているのだと思われる。

<?php
/* 入力を取得する*/
$name = $_POST['name'];
$email = $_POST['email'];
$url = $_POST['url'];

/* 何らかの処理を行う */

/* エスケープ済みの変数を用意する*/
$html_name = htmlspecialchars($name);
$html_email = htmlspecialchars($email);
$html_url = htmlspecialchars($url);
?>
<p>
名前: <?= $html_name ?><br>
eメール: <?= $html_email ?><br>
URL: <?= $html_url ?><br>
</p>

入力されたままの"生"のデータを格納した変数とは別に、エスケープ済みの値を格納する変数を用意して、出力処理ではその変数だけを使用するようにするのである。このエスケープ済みの変数群が、HTMLに出力しても安全(ホワイト)な変数のリストと言えなくもない。大垣氏はこのホワイトリストに属する変数の管理方法については何も言及していないが、管理表を作ってがんばるというのは現実的ではないので、変数名で判別可能な形にするのがベターな方法だろう。この例ではエスケープ済みの変数には接頭辞として html を付けるようにしている。

以前に上記の方法と同じようなものを検討したことがある。エスケープ漏れが発生するのは、同じ変数の中味が処理の段階によって未エスケープからエスケープ済みに変わったり、未エスケープとエスケープ済みの変数が何の区別もなく混在しているからだという話をどこかで読んだためだ。区別できるようにすれば間違える確率はぐっと減るし、間違えていることの検出もやりやすくなるだろう。

一見良さそうなこの方法にも欠点はある。必要なエスケープは出力先のコンテキストによって変わるため、出力コンテキストの種類が増えれば、その分だけエスケープ済み変数の種類を増やし、使い分けなければならない。問い合わせフォームなどでありがちな確認画面表示、DBやCSVファイルなどのストレージへの保存、メール送信という処理を行うだけでも3種類になる。たとえ出力先がHTMLだけだったとしても、要素野中味、属性値、CDATA区間の中味、JavaScriptの一部など、エスケープルールの異なるコンテキストが複数ある。こうなると話は単純ではない。エスケープ済み変数の種類を間違えてしまう可能性も出てくるし、そもそもエスケープ済み変数に格納する際にエスケープ方法を間違えてしまうかもしれない。エスケープ方法を間違ってしまった場合、間違ったエスケープの方を前提に使用している部分があるかもしれないため、変数の利用状況を全て調べる必要があり、修正は気軽には行えない。

この欠点の原因は、値を使う部分とエスケープ処理が離れているというか、それぞれが無関係の部分にあるからなのだろう。コンテキストごとにエスケープ方法が異なるということを考慮した設計を考えると、コンテキスト自体がエスケープ方法を知っているべきであり、コンテキスト自体が適切なエスケープを行うという形に落ち着くと思われる。結局テンプレートシステムやバインド機構を使うのがベターということになるわけだが、そういった追加のライブラリを導入せずに済ませたい小規模なアプリケーションというものもある。言語自体がテンプレートっぽいPHPでは特にそうだろう。そんな場合でも、ドキュメント/ビューアーキテクチャのように出力処理とそれ以外の部分に分けて、エスケープ処理は出力処理の中で行う形にはできる。つまりこんな感じだ。

<p>
名前: <?= htmlspecialchars($name) ?><br>
eメール: <?= htmlspecialchars($email) ?><br>
URL: <?= htmlspecialchars($url) ?><br>
</p>

エスケープ処理をひとつひとつ書くのは漏れが出やすそうな感じがするが、どんな方法を取ったとしても漏れが出る可能性は否定できないのだから、それは心配しても仕方の無いところである。ポイントはミスの見つけやすさと修正のしやすさだ。htmlspecialchars()の入っていない「<?= ?>」はエスケープ漏れの可能性が高いし、エスケープ方法が正しいかどうかは、それが記述されているコンテキストを見ればすぐに分かる。修正も、その部分の表示にしか影響しないことは明らかなので、エスケープ処理を追加したりすれば良い。結局オーソドックスな方法の方がましと言うのがあれだが、それにしてもPHPのhtmlspecialchars()は名前が長くて面倒くさい......。

2008年10月10日(金)

Ajaxセキュリティ

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - Ajaxセキュリティ

JavaScriptによるXSS脆弱性という話も出てきているので、その辺りの知識を仕入れるべく「Ajaxセキュリティ」という本を読んでみた。内容的には脆弱性がある前提での攻撃方法の解説が大きな割合を占めているので、防御方法の方を期待している人にとってはちょっとまどろっこしい。結局のところAJAXアプリケーションであっても脆弱性の原因はXSSやSQLインジェクションなどのメタ文字の不適切な取り扱いが大部分を占めるので、防御方法の説明はちゃんとエスケープしろで終わってしまうのだから仕方がないのかもしれない。とはいえ、FLASHのクロスドメインスクリプティング機能の迂闊な使用、JSONデータの保護、サードパーティ製のウィジェットが使えるポータルサイトでの防御などの部分は興味深い。

おおむね良い本ではあるのだが、P.269「第9章 オフラインAjaxアプリケーション」のパラメータ付きSQLクエリを使うべしという説明の中の以下の部分が気になった。

WHERE句における条件文の数が不定の場合も、パラメータ付きのクエリは使用できません。この問題が最も良く発生するのは、Webサイトの検索機能においてユーザーが可変個の検索条件を指定できる場合です。

〜略〜

開発者としては、WHERE句に入る条件の数が事前には分からないので、正しい数の?プレースホルダをあらかじめ設定して、パラメータ付きクエリ文字列を作成することはできません。この問題は、複雑なストアドプロシージャによって解決するのが普通です。しかし、SQLiteはストアドプロシージャをサポートしません。そのため開発者は、ユーザーが検索する条件に基づき、アドホックSQLクエリを動的に組み立てるしかありません。

そんなことはない。パラメータ付きクエリ文字列を動的に組み立てれば、アドホックSQLクエリを動的に組み立てるということは避けられる。たとえば同書でパラメータ付きクエリ文字列ではできないクエリの例として挙げられているSELECT * FROM Articles WHERE content LIKE '%Ajax%' AND content LIKE '%offline%' AND content LIKE '%security%'といったAND検索は以下のように処理できる。

var keywordList = ["Ajax", "offline", "security"];
var sql = SELECT *FROM Articles;
var conditions = [];
var params = [];

for each (keyword in keywordList) {
    conditions.push("content LIKE ?");
    params.push("%" + keyword.replace(/%/g, "%%") + "%");
}
if (conditions.length > 0)
    sql += " WHERE " + conditions.join(" AND ");
}

do.execute(sql, params);

この程度の処理だと % を %% に変換するついでに ' を '' に変換することで済ませたくなるが、自前でエスケープしていないところに意義がある。検索条件に数値や真偽値などが混ざってくれば、パラメータ付きクエリ文字列を使う利点が見えてくるだろう。餅は餅屋にまかせるべきなのだ。

同書の説明からすると、ストアドプロシージャを使えば少なくとも動的にSQLを生成することは避けられそうな感じを受けるが、実はそうでもない。ストアドプロシージャの利点はSQLが地の文として普通に書けるというところにあるが、この例のように発行するSQLが固定ではないない場合は、結局文字列として組み立ててから改めてクエリーを発行するしかない。やっていることはパラメータ付きクエリ文字列や、アドホックSQLクエリを動的に組み立てることと同じで、結局はどこでそれをやるかの違いしかない。ストアドプロシージャを使えばSQLインジェクション攻撃への対策になるような説明を見ることもあるが、脆弱になる度合いは変わらないのである。

2008年10月17日(金)

なかなか直らないMovable TypeのXSS脆弱性の訳

カテゴリ: MovableType, セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - なかなか直らないMovable TypeのXSS脆弱性の訳

Movable TypeではXSS脆弱性の修正が度々行われているが、直りきらないのはエスケープが必要かどうかの判断が難しい仕様になっているところにあるのではないだろうか。MTでは基本的にテンプレート側でescape="html"の指定を付けることで行う様になっているが、以下のような処理が為されているため付けてはいけないものも混在しているため、一様に付ければ良いと言う訳ではない。

  • 独自の文法からHTMLに変換されている
  • サニタイズされている
  • エスケープ済みの値がMTSetVerされている
  • エスケープ済みの値をコントローラ側でセットされている

escape="html"を付ける必要があるのか、それとも付けてはいけないのかは、タグ名からは分からないし、リファレンスマニュアルにも書かれていない。おそらく初期のMTでは、サイト側のテンプレートにはescape="html"を書かなくても良いようになっていたのではないだろうか。たとえばMTEntryBodyなどはHTMLに変換されたものが出力されるタイプのタグなのでエスケープは不要である。カテゴリ名やコメントの投稿者名はHTMLのメタ文字がサニタイズされる為、やはり不要である。機能の追加にしたがってそれがだんだん崩れてきたのだろう。その中途半端な状態のせいでエスケープが必要という意識が根付かないのか、検索フォームのIncludeBlogsパラメータのエスケープ漏れ(MT-3.33)、MTCommentPreviewIsStaticのエスケープ漏れ(MT-3.34)、MTCommentPreviewXXX系タグのエスケープれの修正(MT-3.35)など、エスケープ漏れの修正が度々行われている。

エスケープ済みの値をMTSetVerしたりするのは、テンプレートモジュール間の値の受け渡しをMTSetVer/MTGetVerで行うようになっているからのようだ。今のところ渡す側と受け取る側、どちらがエスケープするかの明確なルールは無いようで、少なくともpage_title、html_titleは渡す側がエスケープしているものもある。すべての場合でエスケープしているわけではないのが謎だが、おそらく仕様的にHTMLのメタ文字が入らないのを前提にエスケープを省略しているものと思われる。

コントローラ側でエスケープしているのは、メッセージをローカライズするための__transタグのためのようだ。__transタグは<__trans phrase="..." params="...">以下のようにして使うもので、paramsに指定する値のダブルクォートのエスケープはHTMLの文字参照に変換して行うようになっている。したがって1回エスケープしただけでは__transタグにデコードされてしまうので、HTMLとしてもエスケープする必要がある場合は2回エスケープする必要がある。MTテンプレートの仕様では同じグローバルフィルタを2回かけることはできないので、どこかで事前にエスケープしなければならない。あの複雑なテンプレートの中に混ぜるのは避けたかったのか、コントローラ側に処理を追加するという選択をしたようだ。過去のバージョンのテンプレートを見ても、この__transタグの仕様を考慮していそうな部分が少ないのだが、パラメータとして指定している値が数字や日付、アーカイブタイプ名など、HTMLのメタ文字が含まれないものばかりだったため、うまくいっていたように見えたのだろう。機能拡張によって、その危ういバランスが崩れてしまったわけだ。

結局、何をどこでエスケープするかのポリシーが決まっておらず、場当たり的に処理しているところに根本的な原因があると思われる。こうなってしまうと作り直しに近いことを行わないと根本的な是正は難しいだろう。こうならないためにも、設計段階で何をどこでエスケープするかのポリシーを定めることを心掛けたいものである。

2009年01月13日(火)

開発者視点の脆弱性の分類

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 開発者視点の脆弱性の分類

Webアプリの脆弱性は5+1の分類で把握せよ-NTTデータCCS長谷川氏より

そこで同氏が提唱するのが、侵害パターンによる「5+1の類型」だ。Webアプリケーションの侵害パターンは、その脆弱性の性質によって異なる。同氏はそのパターンから脆弱性を「暴露問題」「エコーバック問題」「入力問題」「セッション問題」「アクセス制御問題」の5種類と、それらどれにも含めることのできない「各種の問題」に分類し、「こうすることで脆弱性を体系的に把握することが可能になり、対策の検討もしやすくなる」としているのだ。

この分類は既存のソフトウェアに対する脆弱性検査を行う際には有用だと言えるが、実際の開発の際には不十分だと思う。記事中にあるようにソフトウェア開発は、要件定義、設計、実装と段階を追って進んで行く訳だが、その各段階で具体的に何に対して注意しなければならないかは、この分類だけでは分からない。結局、全工程において危なそうなものを気合いで見分けて対処しるという状況は変わらないわけで、これで何かが劇的に変わる訳ではない。実際、この分類を使えば即セキュアなウェブアプリケーションを作れると思った開発者はどれくらい居るだろうか。つまり、この分類はセキュリティ検査屋の為の分類であって、開発者のための分類ではないのだ。

では開発者のための脆弱性とはどういったものだろうか。ソフトウェアにまつわる問題というのは設計・実装・運用のいずれかが原因になっている。どんなに完璧に実装したとしても、そもそもの設計や後の運用が悪ければ駄目だし、設計や運用が完璧でも、バグがあったらどうしようもない。脆弱性もソフトウェアにまつわる問題には違いないので、この3つに分類できるはずだ。ということで開発者視点の脆弱性としては、まず以下の3つに分類したい。

  1. 設計上の不備
  2. バグの副作用による脆弱性
  3. 運用上の不備

たとえばXSS。これはHTMLのメタ文字の不適切な取り扱いが原因のバグが原因で、CSVファイルでカンマを特別扱いし忘れたのと同じレベルのバグである。バグの主な症状は表示が崩れるというものだが、それを利用してscipt要素やスクリプトが実行可能な属性と認識されるような表示の崩れを起こさせることが可能であれば、他人のサイトで任意のスクリプトを実行させることができるという脆弱性になる。XSSはバグが原因であるため、設計段階で対処するのは難しい。もちろん、設計段階で何がしかの配慮をすることは可能だが、それに対する検証をテスト工程に盛り込まなければ結局発生は抑えられずに終わる。バグの発生に対する有効な対策はテストしかないので、一通り動作する事だけではなく、誤動作しないというテストを行うことが肝心である。それは難しいことではなく、HTMLのメタ文字である '"<>& といった文字を入力して問題無く扱えるか確認するだけといったレベルのものである。

対してCSRFは設計レベルの脆弱性である。ウェブアプリケーションとしては問題無く動作しているものだが、その機能の設計自体に脆弱な隙があったというものだ。どんなに完璧に実装して完璧にテストしたとしても、そもそもの設計が脆弱なのでは意味がない。設計に脆弱性があると後の工程から大きな手戻りが発生したり、リリース後の修正が難しいものになるため、設計段階で考慮し修正しておくことが肝心である。ある意味、このレベルからが真の脆弱性と言えるのではないだろうか。開発者的には前者のXSS等はただのバグなわけで、単に直せばいいものである。セキュリティ対策が----などといった大層なものではない。

運用上の不備としては、クリティカルなファイルを公開ディレクトリに置いてしまった、認証をかけ忘れた、パスワードが脆弱などの問題が挙げられる。この辺はもう、どんなにアプリケーションの設計やテストを頑張ったとしても防げない。それらとは別の、危険な運用をさせない運用設計とテストが必要になる。

開発期間が短くなりがちなウェブアプリケーションではテスト工程が簡略化され、正しく動作する事だけがテストされ、誤動作しないというテストは行われない事が多い。設計上の不備に関してはそれを補ってくれるフレームワーク等を利用することで改善が期待できるが、バグに関しては自分たちでテストするしかない。XSS、SQLインジェクション、OSコマンドインジェクションなど、脆弱性の大半を占めるものはメタ文字の不適切な取り扱いというバグの副作用による脆弱である。したがって、メタ文字を入力して正しく扱えるか確認するというテストを追加するだけで、セキュアなアプリケーションになることは間違いないだろう。

2009年01月18日(日)

最も危険なプログラミングエラーTop 25

カテゴリ: セキュリティ このエントリーを含むはてなブックマーク はてなブックマーク - 最も危険なプログラミングエラーTop 25

2009 CWE/SANS Top 25 Most Dangerous Programming Errors」というものが公表された。日本の同種のものだと「パラメータ改竄(に対する脆弱性)」みたいに脆弱性と攻撃手法を厳密に分けずにごっちゃになっていることが多いが、このリストは厳密に脆弱性というか、原因となったものについて書いているのが興味深い。せっかくなので訳してみた。表現が端的なので、詳細を読まないとなんのことなのか分からないものもある。

  • コンポーネント間の安全でない相互作用
    • CWE-20: 不適切な入力検証
    • CWE-116: 出力の不適当なエンコーディングまたはエスケープ
    • CWE-89: SQLクエリの構造を保つことに関する怠り(別名SQLインジェクション)
    • CWE-79: ウェブページの構造を保つことに関する怠り(別名クロスサイトスクリプティング)
    • CWE-78: OSコマンドの構造を保つことに関する怠り(別名OSコマンドインジェクション)
    • CWE-319: 機密情報の平文送出
    • CWE-352: クロスサイトリクエストフォージェリー(CSRF)
    • CWE-362: 競合状態
    • CWE-209: エラーメッセージによる情報漏洩
  • 危険なリソース管理
    • CWE-119: バッファメモリの境界内に操作を制限することに関する怠り
    • CWE-642: クリティカルな状態データの外部制御
    • CWE-73: ファイル名やパスの外部制御
    • CWE-426: 信頼できない検索パス
    • CWE-94: コードの動的生成の制御に関する怠り(別名コードインジェクション)
    • CWE-494: 改竄チェックの無いコードダウンロード
    • CWE-404: リソースの不適切なシャットダウンや解放
    • CWE-665: 不適切な初期化
    • CWE-682: 誤った計算
  • 穴だらけの防御
    • CWE-285: 不適切なアクセス制御(認証)
    • CWE-327: 破られている、または危険な暗号化アルゴリズムの使用
    • CWE-259: パスワードのハードコード
    • CWE-732: クリティカルなリソースに対する安全でない権限割り当て
    • CWE-330: 能力不足の乱数の使用
    • CWE-250: 不必要な特権での実行
    • CWE-602: サーバ側セキュリティのクライアント側施行

インジェクション系は「構造を保つことに関する怠り(Failure to Preserve ... Structure)」という表現になっている。確かに、プログラミングエラーとして厳密に表現するとそういうことになるのだろう。実装に問題があるということが分かるのでなかなかいいと思う。

「クリティカルな状態データの外部制御(External Control of Critical State Data)」は何のことだが分かりづらいが、セッションデータなど、改竄されてはいけない状態情報をhiddenやクッキーなどに保存することで外部から受け取る状態になってしまっていることを示している。「ファイル名やパスの外部制御」も同様で、要はディレクトリトラバーサルに弱いという問題である。

「サーバ側セキュリティのクライアント側施行Client-Side Enforcement of Server-Side Security」というのは、本来サーバ側で行わなければならない検証や認証をクライアント側だけで行っているので、いくらでもスルーできるというものだ。これはAJAXやFLASHなどで良く起る。

CSRFがそのままなのが残念といえば残念。「Failure to ...」の形にするとしたらどういう文になるだろうか。