セキュリティ対策の基本はどの分野でもあまり変わりません。全体対策と個別対策、これらを総合的に駆使して安全性を維持します。全体対策、個別対策は両方とも”必要条件”です。全体対策だけ、個別対策だけ、では思ったような安全性を得ることは困難です。
ITセキュリティ以外の対策からITセキュリティについて考えてみます。
地震対策
地震対策の中でも建造物の耐震工事/耐震構造について考えます。地震が起きた際に建物が倒壊すると命に関わります。地震の揺れに対して脆弱な建物は多数あります。中に居る人の命を守るには建物が倒壊しないよう、安全な構造の建物、安全でない建物には耐震工事が必要です。
耐震工事を行う場合、無闇に構造を強化しません。局所的に強化しても他の部分を疎かにすると、逆に倒壊しやい脆弱な構造になってしまいます。個別の手法自体は正しくても、局所的に適用すると問題の原因になります。耐震手法・構造は全体的な耐震構造を考えて利用しないと逆に危険です。また構造を強化する手法が間違っている場合も、期待通りの耐震性が得られません。建物全体を見て、適切な手法を組み合わせ、耐震構造にしなければなりません。
建物の耐震対策からはアーキテクチャーの全体最適化が重要であること、個別の手法が正しく効果的でも”全体での役割”を理解した上で利用しないと逆に危険という教訓を得られます。
害虫対策
害虫対策ではまず保護したいエリアに害虫を入れないことが重要です。建物への害虫侵入を防ぐ場合、網戸も設置せずに害虫対策をすることは普通ありえません。まず害虫の侵入自体を防止し、それでも侵入してしまった場合に備えて対策します。網戸なしで窓を開け、次々に発生する害虫を室内で駆除するのではきりがありません。害虫対策は害虫駆除より、まず防虫です。
侵入対策だけでは満足できる害虫対策になりません。どうしても網戸なしの空間を開けてしまう場所、人が出入りする玄関や換気扇などから侵入を許してしまいます。網戸をしていても入ってきてしまう害虫には侵入後の対策を行います。◯キブリ対策なら◯キブリホイホイや殺虫剤などを使うでしょう。
外にいる害虫自体を駆除する方法もあります。これは個人や一企業ではなく社会的な対策が必要です。個人や一企業が採用するにはかなりハードルの高い対策ですが、一定の効果はあります。場合によっては大きな効果があります。例えば、蚊の発生を抑えるために鉢植えの皿、空き缶などに淀んだ水たまりができないようにする、などの対策があり一定の効果があるようです。
害虫対策からはまず全体的な対策となる網戸などの設置(境界防御)、すり抜けた害虫への対策(縦深防御)、害虫の発生を防ぐ社会的な対策(教育やルール定義)が効果的であることを学べます。
ITセキュリティ対策
話を単純化するためにアプリケーション開発に限ったITセキュリティ対策を考えます。ITセキュリティ対策はバグ対策と言えます。害虫対策に似ています。まずアプリケーション内のでバグが悪用されないよう、侵入対策(境界防御)を行うことが合理的です。
害虫対策からは境界防御について学べます。境界防御を行う場合、局所的に防御を行っても効果は期待できません。適切なアーキテクチャー(室内の戸に網戸を設置するのではなく、室外に面している窓に網戸を設置)を用いて全体的に対策することが必要です。適切なアーキテクチャーなしに境界防御を行っても、漏れや間違いが発生したり、効果がなくなったりします。
耐震対策からは正しく耐震対策手法を用いる教訓から学べます。入力バリデーションはとても効果的な全体対策でソフトウェアのセキュリティ対策としてとても効果的な手法です。しかし、効果的な入力バリデーションであっても全体における意味や効果を正しく理解せずに利用してしまうと、逆に危険です。効果的な対策であっても「全体における対策の意味や効果」を理解せずに過信すると危険になります。入力バリデーションをしているので出力時に安全対策を行わない、は入力バリデーションの「全体における対策の意味や効果」を理解していない例です。
害虫の発生を根本的に防ぐ事ができないように、バグの発生を根本的に防ぐ事はできません。ライブラリやフレームワークなどのプログラムは常に更新されます。アプリケーションのコードもユーザー・データの増大や仕様変更により常に変化しています。これらの新しいコードにバグが含まれないことを保証することは困難です。できるだけバグが含まれないようユニットテストなどを行ってバグ混入を防ぎます。しかし、テストは正常系のデータによるテストが主体で、攻撃者が送信してくるような異常系のデータによるテストは限られていることが多いです。
ユニットテストで全ての異常系データに対応するのは大変な手間がかかります。しかも異常系データの生成はブラックリスト型データにならざるを得ず、簡単に漏れが発生します。異常系データを網羅することは困難※です。しかし、開発者は「害虫対策の網戸」となるホワイトリスト型入力バリデーションを簡単に実装できます。開発者であれば、特定の入力がどのような入力であるか、知っているはずです。どこに入力(室外に面している窓)があるのかも基礎知識として知っているはずです。もし開発者がプログラムの入力を知らないならプロジェクトとしてどこかに問題があります。「開発者が知っている入力」を検証するだけで大幅にリスクを軽減できます。
※ 異常系データのテストは困難なのでファジングと呼ばれるテスト手法(攻撃手法)が存在します。
様々な対策を行っても、システマティックに完全に漏れを防ぐことは困難です。この問題に対応するために縦深防御(多層防御)を実装します。安全な入出力の責任は出力を行う側(呼び出し側)にあります。例えば、外部入力を利用し呼び出すオブジェクトのメソッドを指定するようなコードの場合、呼び出し側で確実に安全なメソッドのみ呼び出すようにしなければなりません。これが前提ですが、呼び出される側のオブジェクトで安全なメソッドのみ呼び出せるように制限(縦深防御)することも可能です。
プログラミングにおける社会的対策は基礎的なセキュリティ教育・啓蒙です。基礎的なセキュリティ教育で直接バグを無くすことはできませんが、適切に実施すると大きな効果を期待できます。なぜ脆弱性が攻撃されるのか?どのように脆弱性は生まれるのか?効果的な対策は何か?セキュリティ対策の評価方法とは?セキュアなアーキテクチャーとは?を教育すると効果が期待できます。
地震対策/害虫対策とITセキュリティ対策の類似点
セキュリティ対策の基本はどの分野でも似ています。
- 害虫対策:害虫対策からはまず全体的な対策となる網戸などの設置
- ITセキュリティ:開発者は「害虫対策の網戸」となるホワイトリスト型入力バリデーションを簡単に実装可能
- 地震対策:耐震手法・構造は全体的な耐震構造を考えて利用しないと逆に危険
- ITセキュリティ:効果的な入力バリデーションであっても全体における意味や効果を正しく理解せずに利用してしまうと逆に危険
- 地震対策:耐震対策はアーキテクチャーの全体最適化が重要
- ITセキュリティ:適切なアーキテクチャー(室内の戸に網戸を設置するのではなく、室外に面している窓に網戸を設置)を用いて全体的に対策することが必要
- 害虫対策:害虫の侵入自体を防止し、それでも侵入してしまった場合に備えて対策
- ITセキュリティ:システマティックに完全に漏れ(脆弱性)を防ぐことは困難。この問題に対応するために縦深防御(多層防御)を実装
- 害虫対策:害虫の発生を防ぐ社会的な対策(教育やルール定義)が効果的
- ITセキュリティ:基礎的なセキュリティ教育で直接バグを無くすことはできませんが、適切に実施すると大きな効果を期待できる
これら以外にも類似性を見つけられると思います。
防御的・セキュアプログラミング
ソフトウェア開発における基本的防御(インジェクション対策)は防御的・セキュアプログラミングの実施で行えます。単純に境界防御や個別の脆弱性対策を教えることでも効果はあります。しかし、なぜ境界防御を行うのか?脆弱性がどのように発生するのか?セキュアなアーキテクチャーとはどういう構造か?などの基本を理解した方がより効果的です。
開発者が利用するライブラリや外部システムは多岐に渡ります。それぞれ”共通する脆弱性”の原因を持っていますが、それぞれ”個別の脆弱性”の発生原因を持っています。”共通する脆弱性”はCWEでカタログされ現在719の共通脆弱性が登録されています。”個別の脆弱性”はこの何倍もあります。
例えば、改行インジェクションはメールヘッダーインジェクションやHTTPレスポンススプリッティングが有名ですが行ベースで意味があるプロトコルの場合は影響を受けます。memcachedとの通信を行うクライアントライブラリを作る場合、注意しないと改行インジェクションによる不正なデータ取得を許してしまいます。キーバリュー型のmemcachedでインジェクション?!と思うかも知れませんが、実際に改行インジェクションに脆弱なクライアントライブラリは作れてしまいます。開発者がこのような脆弱性に”自分で対応”するには、なぜ境界防御を行うのか?脆弱性がどのように攻撃されるのか?セキュアなアーキテクチャーとはどういう構造・コードか?などの基本を理解していると、”共通する脆弱性”から”個別の脆弱性”の発生原因を特定し対応できます。
個別の脆弱性対策をリストアップすると膨大な数になり、一人の開発者が覚えるには不可能な数になります。しかし、防御的・セキュアプログラミングの基本的な考え方はシンプルであり、シンプルでもその考え方を応用することにより広範囲な脆弱性に対応できるようになります。
防御的プログラミングはプログラミング原則の一つと考えられています。しかし、必ずしも広く一般にプログラミング原則の一つと認識されていないようです。プログラマでなくてもソフトウェア開発に関わる方すべては防御的・セキュアプログラミングの基本概念を理解し開発を行うようにすれば、かなり安全なソフトウェアを開発することが可能になります。
防御的・セキュアプログラミングの概念が考案されてから少なくとも四半世紀が経ちました。少なくともこれからの四半世紀も役立つ基礎知識であり続けるでしょう。長生きする知識とスキルを身につけない手はありません!もしご存知でない方は今から防御的・セキュアプログラミングを行い、その概念・アーキテクチャーを理解しましょう!基本は簡単で、応用が効きます!
最後に、防御的・セキュアプログラミングもソフトウェアセキュリティの”部分的”対策に過ぎません。どんな脆弱性にも対応できる銀の玉ではないことにも注意してださい。全体対策、個別対策は両方とも”必要条件”です。全体最適化とは何か?考えて対策しましょう!