【レポート】

セキュアなコードの書き方 - セキュアな設計が最も重要

3月29~31日の3日間に渡って早稲田大学大久保キャンパスで開かれた「Writing Secure Code」セミナーでは、同名の著書(邦題は「プログラマのためのセキュリティ対策テクニック」)の著者の一人であるDavid LeBranc氏が2日半・合計12時間に渡る講義を行った。ただ長時間な講義のため内容は非常に多岐に渡り、本稿で全部をご紹介するのは困難なため、講義の中から筆者が気になった点をいくつかピックアップしてご紹介したい。

何よりも「SecureなDesign」が最も重要

まず同氏が訴えたのは、「何よりも重要なのはSecureなDesignだ」ということ。同氏は「セキュリティバグの50%はシステムデザイン時のエラーだ」と語り、初日と2日目の午前中を費やしてシステムデザイン時の注意点、そして外部からシステムに与えられる脅威の評価法などについて語った。

同氏はまず脅威の要素を「Spoofing」「Tempering」「Repudiation」「Information Disclosure」「Denial of Service」「Escalation of Privilege」の6つに分類し、考えうる脅威がこの6類型のうちどれに属するか(複数に該当するものもある)を確認することが重要だと語った。また具体的にシステムに脆弱性が発見された場合でも、それによって侵害される可能性がある資産や影響を受けるユーザの範囲などによっては対策の優先順位が異なるとして、その評価法として「Damage」「Reproducibility」「Exploitability」「Affected Users」「Discoverability」の5要素の頭文字を取った「DREAD rating」を用いるのがよいという考えを披露した。

また、同氏がもう一つ力を入れて解説していたのがData Flow Diagram(DFD)の描き方。同氏は「DFDを書くことで、どこからどのようなデータが入力され、システム内でどのようにデータが流れるか、またプロセス間のデータのやり取りなどにおいてどこからどこまでの範囲が信頼できるものかという境界線(Trust Boundaries)を引くことが容易になる」として、DFDを描く際の基本原則(データの流れは片方向で描く、入出力のないプロセスはないなど)を詳細に解説していた。

コーディング時のバグは完全には取り除けない

2日目の午後からはいよいよ具体的なコーディング時の問題に入り、Buffer OverflowやHeap Overflow、printf()関数のFormat Stringを利用したAttackなど、具体的にコードのサンプルなどを示しながら、いかにしてそれらのバグを利用したAttackが可能になるかを実演を交えて示した。

で、問題なのはいかにしてそれらのバグの発生を抑えるかなのだが、同氏は「理想はsolidなコードを書くことなのだが、普通プログラマは1,000行コードを書いたら5~50行ぐらいはミスをする」「(.NETの)managed codeを使えばかなり問題は減るが、パフォーマンス上の理由などからそれらを使えない場面もある」と語った上、プログラマの教育などである程度はバグの発生を減らせるものの「完璧にバグの発生をなくすことは不可能だ」と語った。

またコードレビューやソース検査ツールについては、「コードレビューは確かに有効だが、レビュアーの能力に(検査の質が)左右されてしまう問題があるし、レビューするコードが多すぎると疲れる上に飽きてきてレビューの質が落ちてくる」「ソース検査ツールは人間と違って疲れたりということはないが、市販のものでだいたい20%ぐらいしか問題を検出できないため、Microsoftでは自社で開発した検査ツールを使用しているものの、それでも検出率はあまり高くない」と語り、有効性は認めるもののそれだけでは決して問題は解決できないとの認識を示した。

同氏は対策の一つとして、現在のVisual C++ .NETで利用可能になっている「/GS」オプションがいかにしてBuffer Overflowを利用したリターンアドレスの書き換えを防いでいるかなどについても言及したが、これも完全な防御策ではないとして、(外部の攻撃からの)可能な限りの回避策を身に着けておくことなどが必要だと訴えていた。

Microsoftのプログラマが誰も見抜けなかったバグとは?

コーディングの分野で同氏が「最も興味深い分野」と語るのが、Integer Overflowの問題だ。Integer Overflowはそれ自体は単なる桁溢れなどによる計算ミスだが、これが他の命令と組み合わさることにより、Buffer Overflowや不正なデータアクセスを招く原因となるため、同氏はこの問題をかなり重要視している。

その解説の中で、同氏が下記のような短いサンプルプログラムを取り上げた。このプログラムには1つバグがあるのだが、どこにバグがあるか、読者の方々はお分かりになるだろうか。

1:template <typename T>
2:
3:static T MaxInt() {
4: if( IsSigned() ) {
5:return (T)~( 1 << ( BitCount()-1 ) );
6:}
7://else
8:return (T)(~(T)0);
9:}

これは変数型として任意の整数型Tを与えると、その変数型Tが格納できる整数の最大値を返すというプログラム。一見したところ問題はなさそうに見えるし、実際16bitや32bitのint型を与えた場合には何の問題もなく動作するという。同氏によればこのソースコードを見たMicrosoftのプログラマ(コードレビュアー)は誰一人として、このプログラムのバグに気づかなかったというから、普通はバグを見つけられなくても無理はない。

ところが同氏によれば、整数型として64bit signed int型を与えると問題が発生したという。この場合、5行目において「1 << 63(1を63bit左にシフトする)」という処理を行うことになるのだが、このとき左辺の「1」の変数型が何になるかはコンパイラによる自動キャストで決まってしまうため、コンパイラによっては正しいビットシフトが行われないのだ。実際同氏がMicrosoft製のコンパイラで試した際には、この「1」が32bitのint型にキャストされたため「1 << 63」の結果として「0x80000000」が返ってきてしまい、正しい結果が得られなかったそうだ。

この問題を回避するためには、5行目を「return (T)~( (T)1 << ( BitCount() - 1 ) );」として、明示的に「1」を整数型Tにキャストしてやらなければならない。結局同氏はこの問題を、シングルステップ実行が可能なデバッガでトレースを行って初めて発見することができたという。

このようなコンパイラによる暗黙のキャストが原因となるケース以外にも、桁溢れ時の処理を怠っているなどの理由で計算に問題が発生している例は少なくないとして、同氏は自身が開発し、計算時に自動的に桁溢れなどのチェックを行ってくれる「SafeInt」クラスを利用すること(ちなみに利用に伴うパフォーマンスダウンは8%程にとどまるとのこと)、コンパイルはC++で行いWarning Levelはできるだけ最大にすること(Cでコンパイルすると、Warningを最大にしても「char c=300;」のような不適切な入力に対するWarningが出ない)などを問題回避策として推奨していた。

ちなみに同種のOverflow問題は浮動小数点演算においても発生する可能性があるが、同氏は「浮動小数点演算では常に丸め誤差などの問題があるため、(SafeIntのような)安全な浮動小数点演算クラスを作るにはさらにプログラムが複雑になってしまう」と語り、浮動小数点演算におけるOverflowについては将来的な課題として取り組む考えを示している。

Webサーバのセキュリティを守る上で重要な点とは?

さて、昨今セキュリティといって最も関心が高い分野といえば、やはりWebサーバのセキュリティということになるだろう。同氏はかつてeWeek(旧PCWeek)誌が主催した「OpenHack」コンテストに参加したときの経験などを元に、Webサーバのセキュリティを守る上で気をつけるべき点について解説した。

同氏がまず訴えたのは、Webアプリにおける入力データのチェックの難しさ。同氏は「基本的に全ての入力は悪意を持っていると疑え」とまず述べたものの、実際にユーザが入力してきたデータを検査するのは非常に難しいとして、その例としてURLの正当性の検査の場合を挙げた。特に同氏はUnicodeにおいて、自分の日常使っている言語では想像もつかないような問題が発生する可能性があるとして、その一例としてトルコ語における「I」の字の例を紹介。

トルコ語では通常のASCII文字の「I/i」の他に、ı(U+0131)・İ(U+0130)という2つの文字が存在するため、例えば「file://」で始まるURLを排除しようとする場合はこれらの文字による表記の可能性も検査しないと、トルコ語の入力環境がある場合には検査を突破されてしまう可能性がある。このため、.NET環境なら通常のToUpperメソッドを使う代わりに「ToUpper(CULTURE_INVARIANT)」を使うなどして、言語に依存しない形での検査を行わねばならない、とその難しさを語った。

それ以外に同氏はいわゆるクロスサイトスクリプティング(XSS)やSQL injectionなどの問題にも触れつつ、「OpenHack1並びにOpenHack4で得られた経験が、URLscanやIIS LockDownといったツール類に生かされているし、IIS 6.0ではインストール直後はほとんど全てのコンポーネントがoff状態になっているなど、以前に比べるとデフォルト状態でもかなりsecureになってきている」と語ったが、OpenHackにおいても本来なら十分な堅牢性を持っていたはずのLinuxベースのWebサーバが、CGIの脆弱性やXSSのバグを突かれて結局クラックを許してしまった点を同氏は指摘し「Webサーバにおいても、アクセス制御をきちんと行う、余計な権限は与えないなどの基本原則を徹底することが重要だ」と基本を徹底することの重要性を強調した。

同氏はWebサーバ以外のネットワークアプリケーションについても「ファイアウォールと親和性の高いアプリケーションにするために、サーバからクライアントに接続するようなプログラムは書くべきではない」「独自の暗号関数を実装するのは脆弱性の原因になりやすいし、コード内や設定ファイルに秘密鍵を持たせる方法では長期間セキュリティを確保するのは困難なので、Windows 2000以降で実装されたDPAPI(Data Protection API)を利用したほうがよい」などと指摘。セキュリティを確保するためには数多くのハードルがあることをうかがわせていた。



転職ノウハウ

あなたが本領発揮できる仕事を診断
あなたの仕事適性診断

シゴト性格・弱点が20の質問でサクッと分かる!

「仕事辞めたい……」その理由は?
「仕事辞めたい……」その理由は?

71%の人が仕事を辞めたいと思った経験あり。その理由と対処法は?

3年後の年収どうなる? 年収予報
3年後の年収どうなる? 年収予報

今の年収は適正? 3年後は? あなたの年収をデータに基づき予報します。

激務な職場を辞めたいが、美女が邪魔して辞められない
激務な職場を辞めたいが、美女が邪魔して辞められない

美人上司と可愛い過ぎる後輩に挟まれるエンジニアの悩み

人気記事

一覧

イチオシ記事

新着記事

求人情報