現在のWebアプリケーションのほとんどは「入り口対策」がない「入り口ノーガード設計」です。
※ アプリケーションの入力処理、つまりMVCアーキテクチャーならコントローラーレベルで「入り口対策」がない設計が「入り口ノーガード設計」です。
このような設計になっているので、本来は自然数だけのハズのHTTPヘッダーのContent-Length(やContent-Type/Content-Disposition)にプログラムが書けてしまったStruts2 Webアプリにより国内ではクレジットカード情報が何十万件も盗まれる、米国では1億4千万件以上の信用情報が漏洩する、といった事件が発生しています。
幸い、「入り口対策」がない「入り口ノーガード設計」でもこういった大規模インシデントになるような脆弱性の攻撃は多くありません。しかし、話題にならないだけで多数のインシデントが世界中で発生していると考えられます。
先の事例はStruts2/フレームワークのセキュリティ問題、と捉えられていることが多いと思います。しかし、これは本質的にセキュリティ原則を無視した「入り口ノーガード設計」の問題です。
コード検査していると「入り口対策」をしていて、本当に良かったですね!というケースに出会うことが少なくありません。
2018年5月からEUでGDPRが施行されます。GDPR違反となると2000万ユーロまたは全世界売上の4%のどちらか高い方が罰金(組織によっては1000万ユーロまたは全世界売上の2%)となります。GDPRには様々な要件が要求されていますが、国際情報セキュリティ標準であるISO 27000で”普及している”とされた”セキュアプログラミング技術”の原則さえ採用しないシステムで個人情報漏洩が起きた場合の被害は、簡単に会社を潰すレベルの損害になる可能性があります。
もし「入り口ノーガード設計」のオフィスセキュリティだとしたら?
ネットワークシステムとほぼ同じです。
- 入り口対策がない入退室管理でオフィスの安全性を守る
誰でも勝手に入れるオフィスで盗まれては困るモノを守るのは至難の技であることは簡単に想像できると思います。
誰でも入れるオフィスでもそこそこの安全性を確保する事も可能ですが、その為には「トイレに行くだけ」でも保護対象の資料などを鍵を掛けた引き出しやロッカーに仕舞うコストが発生します。荷物の配達などでは、社員に成り済ました部外者が勝手に荷物を受け取ることを防止するため、配達員の監視をしなければならない、といった馬鹿げたコストも発生するかも知れません。1
ITセキュリティに於ても、オフィスの物理的セキュリティ確保は重要事項なので、オフィスの入り口対策がない「入り口ノーガード設計」のオフィスセキュリティ設計はあり得ない、と理解されている方が大半だと思います。
もし「入り口ノーガード設計」のネットワークシステムだとしたら?
ネットワークシステムで最外周の信頼境界線での入力対策を行わない「入り口ノーガード設計」を採用することとは
- 入り口対策がないファイアーウォールで会社/組織のネットワークを守る
と同じです。
インターネットから内部ネットワークへ通信でき、セキュリティ問題のあるデバイスを自由に探して、自由にデバイスの脆弱性を攻撃できる状態になります。
入力対策がないファイアーウォールでネットワークの安全性を保つには、ネットワーク上のデバイス全ての既知/未知の脆弱性を修正/対応しなければなりません。
ネットワークシステムの管理者でなくても、これにはトンデモないリソースが必要であるとともに、”ネットワーク上のデバイス全ての既知/未知の脆弱性を修正/対応”することに現実性はないと理解ると思います。
ネットワークに於ける入り口対策の重要性はITシステムの専門家でなくても理解し、程度の差こそあれ「入り口ノーガード設計」を採用するのではなく、入り口対策を自分で実施している方が多いです。
現在のほぼ全てのWebアプリは「入り口ノーガード設計」
ネットワークのセキュリティでも、物理的なセキュリティでも「入り口ノーガード設計」は非合理的で余計なコストが必要となる設計であることに異議は無いと思います。ソフトウェアも同じです。
ですが、現存するほぼ全てのWebアプリは「入り口ノーガード設計」です。OWASP TOP 10の策定の議論でもほとんどのアプリは「入り口ノーガード設計」で、入り口以外のコードもノーガード設計だという意見がありました。
ソフトウェアの最も外の信頼境界線で入り口対策を行わない「入り口ノーガード設計」の場合、自分が作っているソフトウェアの脆弱性のみでなく、フレームワーク/ライブラリ/インフラまで含めた全ての既知/未知の脆弱性を修正/対応しなければなりません。
「入り口ノーガード設計」の場合、冒頭で挙げた事例のようにセキュアコーディングの第1原則で対応可能な単純な問題でも、取り返し難い重大なインシデントに発展してしまいます。
ネットワークシステムの「入り口ノーガード設計」と同じく、アプリケーションが「入り口ノーガード設計」で関連する全てのソフトウェアの全ての既知/未知の脆弱性に対応しなければならない場合、ドンデモないリソースが必要となり、現実的ではありません。
フレームワーク/ライブラリなどが不正な入力でどのような誤作動をするのか?誰にも完全に把握できません。しかも、ライブラリ/APIの多くが「不正な入力」を正しく検出することを保証せず、開発者が正しい入力を送る”仕様”になっています。
アプリレベル信頼境界での「入り口対策」(=ソフトウェアの最も外となる信頼境界線での入力対策)を行わないで得をするのは、サーバー犯罪を行う犯罪者、アプリケーションファイアーウォールを売るセキュリティ業者、外部からセキュリティ検査をするセキュリティ業者だけです。
「入り口ノーガード設計」ソフトウェア開発者もソフトウェアの利用者にも得になることはありません。強いて挙げるなら、セキュアな構造に必要な入力対策を省略して開発コストが少し低くなるように見えることくらいです。(しかし、適切な入力バリデーション無しで同じレベルの安全性を保障したい場合、コストは跳ね上がります。ネットワーク内のデバイスの安全性を完璧に保つことに膨大なコストが必要であること、と同じです)
入り口対策(入力バリデーション)のコスト
セキュアコーディングが要求する厳格な入り口対策(入力バリデーション)にはコストが必要ですが、その他のコストやリスクに対する効果を考えると格安です。
ソフトウェアもネットワーク/オフィスと同じく、適切な入り口対策(入力バリデーション)を行うと、何とか管理可能なリスクレベルにまでリスクを低減できます。
とは言っても、アプリには入力は数も多いし、変化するので入力バリデーションは現実的でない!と主張される方も居るかも知れません。
しかし、オブジェクト指向言語にインターフェース機能があるようにインターフェースは比較的安定していて少数です。多数のデータの入り口があっても、データの種類は安定していて少数です。アプリケーションレベルの入り口対策(入力バリデーション)はデータ型/オブジェクトのクラスを指定する作業と同程度の作業量で定義できます。データ型/オブジェクトのクラス指定は開発者がいつも行っている作業で難しいことではありません。
参考:https://github.com/yohgaki/validate-php – 一旦”データ形式”を定義すれば、同じ”データ形式”は同じ定義を使いまして、”データ型”指定と同じ程度の作業でアプリレベルの入り口対策が実装可能。
入り口対策(入力バリデーション)は現在開発者が安定した品質のソフトウェア生産の為に作っているユニットテストに比べれば、遥かに少ないコストで維持&管理2できます。
ネットワークの入り口対策が内部ネットワーク内の未知の脆弱性に対応できる事と同様に、入り口対策(入力バリデーション)は未知の脆弱性にも対応できます。ソフトウェアに潜む未知の脆弱性を全て洗い出すコストは膨大で、実施は不可能です。仮に実現したとしても、アプリが利用するフレームワーク/ライブラリ/インフラは常に変化し続けるので継続的に維持するコストは膨大です。一方、入り口対策(入力バリデーション)は確実に実現でき、確実にリスクを削減します。
参考:ほぼ全てのインジェクション攻撃を無効化/防止する入力バリデーション 〜 ただし出力対策も必須です 〜
入り口対策(入力バリデーション)とサイバー攻撃の本質/原理と対策
結局の所、サイバー攻撃のほとんどは「不正な値」をアプリケーションに与え、アプリケーションの何処かで「不正な処理」を実行されたり、「不正な状態」にする攻撃です。そもそも「不正な値」を入り口対策(入力バリデーション)で完全に廃除してしまえば、サイバー攻撃のリスクは激減します。
(注意:バリデーションは妥当な入力だけを受け入れる、ホワイトリスト型、で実装し不正な値で処理を停止しなければなりません。処理を停止する理由はコンピュータープログラムは”妥当な入力”(正しい+入力ミスの値)でしか、正しく動作しないからです。2017年版OWASP TOP 10が要求する入り口対策にはDoS対策も含まれます。)
入り口対策(入力バリデーション)がなぜセキュアコーディング原則の第一番目で、出口対策(出力対策)が第七番目なのか?
※ IPAの資料ではセキュアコーディング原則の順番が不必要に変わっています。このため、このように順番を記載して説明する際の混乱の元になっています。この順番はCERTの原本と同じ順番です。
「入力をバリデーションする」原則はコンピューターの動作原理とソフトウェアに対するサイバー攻撃の仕組みから導き出された原則です。
不変の原理:コンピュータープログラムは妥当な入力値でのみ、正しく動作できる。
不変の基本構造:コンピュータープログラムは
- 入力値を受け付ける(入力処理)
- 何らかの有用な処理を行う(ロジック処理)
- 処理結果を渡す(出力処理)
の構造を持っています。
「正しい入力値」はロジック処理が正しく行れ、出力が正しく行われるために必須です。
例えば、整数演算で
result = 1234 + ‘<script>alert(XSS)</script>’
を正しく計算することは不可能です。仮にパラメーターが整数値であっても、プログラムが想定していないオーバーフロー/アンダーフローを起こす数値だと正しく動作しません。
オーバーフロー/アンダーフローはC言語でよくセキュリティ問題の原因になっています。C言語のライブラリ等は多くのプラットフォームの基盤になっているので、C言語以外の言語ユーザーにも無関係ではありません。
そもそもコンピュータープログラムは”原理的”に正しい入力値でしか、正しく動作できないことに加え、多くのソフトウェアに対するサイバー攻撃は”原理的”に不正な入力値を送って目的を達成します。3
つまり、コンピュータプログラムとサイバー攻撃の原理から入り口対策(入力バリデーション)が真っ先に実施すべき対策となります。
「あれ、出力対策こそが真っ先にすべき対策では?」と思った方はプログラムの構造を思い出してください。
- 入力値を受け付ける(入力処理)
- 何らかの有用な処理を行う(ロジック処理)
- 処理結果を渡す(出力処理)
出力処理で不正な値対策を行っても、遅過ぎ、です。Fail Fast原則にも、セキュアコーディング原則のアーキテクチャーにも則っていません。「出力対策こそがセキュリティ対策」とよく勘違いされているので注意しましょう。
※ 出力対策が不要としているのではありません。出力対策は出力先に対して無害な出力を行う責任を持っています。ここでは、入力対策は妥当な入力値であることを保障する責任がある、を理解り易く強調して記載しているだけです。
まとめ
「入り口ノーガード設計」はあり得ない設計、コストが余計にかかる設計、とネットワークセキュリティや物理的セキュリティの対策ではよく理解されている開発者でも、何故か
- ソフトウェアだけは「入り口ノーガード設計」こそが目指すべきセキュリティ設計
と考えているケースが当たり前です。
開発者だけの間でこう啓蒙されているのではなく、セキュリティ専門家でも同じく「入り口ノーガード設計」=「サイバー攻撃支援設計」と言える構造が良い、としているケースも少なくないので仕方ないかも知れません。4
理想と現実からは程遠い、不十分なセキュリティ対策が強く&幅広く啓蒙されていた例は「入り口ノーガード設計」だけではありません。「SQLインジェクション対策はプリペアードクエリ/プレイスホルダだけで完璧!」も原理的/論理的に不十分/不完全な対策であることが理解っていた対策です。
不完全なSQLインジェクション対策が蔓延した結果、新しくコード検査をさせて頂くクライアント様のコードに「初歩的な識別子エスケープ漏れ」によるSQLインジェクション脆弱性が含まれていることが珍しくありません。
参考: 完全なSQLインジェクション対策
「SQLインジェクション対策教育には、エスケープが欠かせない」と論理的に正しい主張をしても「こいつは◯◯か?!」という反応であったことは記憶に新しい方も多いと思います。
最近の入力バリデーションの議論では、昔はセキュリティ対策ではないし必要ない、と主張されていた方も方針転換し「セキュリティ対策としては信頼性がなく重要でない」という程度になりました。
「入力バリデーション」の話をしても、お陰で「こいつは◯◯か?!」という反応はないですが、世界一流のコンピューターサイエンティストのセキュリティ専門家5が第一の原則にしている「入力バリデーション」はWebアプリにはほぼ全くと言ってよいほど取り入れられていないのが現状です。
つまり、開発者の皆さんにとっては早い者勝ち、遅い者負け、のスタートラインに今は立っている状態です!まだまだ遅くは無いです!
参考:
- プログラムから「想定外」を無くす方法
- セキュリティを論理的に構築する方法
- 「脆弱性を局所的に潰す」はアンチプラクティス
- エンジニアなら分かる文字エンコーディングバリデーションの必要性
- バリデーションですべきこと
- 実はこういった馬鹿げたコスト、をソフトウェアも払っています。良い例はPCREライブラリの文字エンコーディングバリデーションです。PCREはC言語レベルであれば、内部的な文字エンコーディングバリデーションを省略できる、様に実装されています。しかし、文字エンコーディングをバリデーションしないアプリが多いのでデフォルトでは文字エンコーディングバリデーションします。このため、本当は何百倍も高速に正規表現検索できるにも関わず、超遅い速度で実行している、が現実に起きています。 ↩
- 入力バリデーションはアプリケーション開発初期から実装する必要はありません。アドホックに追加できるので、コードが安定してきた開発後期から追加すれば良いです。 ↩
- Webアプリはテキストインターフェースで出来ているにも関わらず、文字列バリデーションが全く不十分であるデータ検証が多過ぎます。文字列データ型、であることを保障してもバリデーションにはなりません。 ↩
- 間違っていることは理解っているが、フレームワークが対応していないので、プロジェクトとして対応すると決まっていないので、と現状に甘んじている開発者の方も多数知っています。それでも、こういった方達はかなりの少数派であるようです。 ↩
- CERTはカーネギーメロン大学に設置されており、CERTのコンピューターサイエンス学科のコンピューターサイエンティストを一流のセキュリティ専門家とする事に異論がある方は居ないと思います。 ↩