追記:書き直しました。新しい方をご覧ください。
セキュアコーディングの原則1は「入力バリデーション」です。セキュアコーディングの原則1はソフトウェアセキュリティの一丁目一番地と言えるセキュリティ対策です。
入力バリデーションを第一のセキュリティ対策としているガイドライン:
- CERT Top 10 Secure Coding Practices
- OWASP Secure Coding ‐ Quick Reference Guide
- CWE/SANS Top 25 Monster Mitigations
- IPA セキュアプログラミング講座(NEW 2017年~)
90年代初めからコンピューターサイエンティストのセキュリティ専門家は「入力バリデーション」を重要であるとしてきました。「入力バリデーション」は論理的にセキュアな構造のソフトウェアを作る為に欠かせない必須の要素だからです。防御的プログラミングから数えると四半世紀を越える月日が経っています。
入力バリデーションと国際情報セキュリティ標準/ガイドライン
国際情報セキュリティ標準(ISO 27000/17799)は2000年からセキュアコーディングの原則1(入力バリデーション)の実装方法を具体的に記述&要求しいました。2013年の改定でセキュアプログラミング技術が体系化され普及したとし、セキュアプログラミング技術を採用するとした簡潔な記述になりました。
OWASPをはじめセキュリティガイドラインを公開している複数のセキュリティ機関がセキュアコーディング第1原則の入力バリデーションを第一のセキュリティ対策、最も重要なセキュリティ対策として紹介しています。
にも関わらず、「まともな入力検証を持ったアプリケーション」は日本のみでなく世界的に普及していません。
ソフトウェアセキュリティの一丁目一番地、と言えるセキュリティ対策がほとんどアプリケーションで実施されていない、その最大の理由はズバリ・・・
セキュアコーディングが流行らない最大の原因は”セキュリティ専門家”の誤解にある
まず誤解しないように書きます。本物のソフトウェアセキュリティ専門家はそもそも誤解などはしていません。ソフトウェアセキュリティが必要になったモリスワーム事件以降、90年代初めから論理的に妥当なセキュアコーディング(当時は防御的プログラミングと呼ばれる)を一貫して提唱しています。
国際情報セキュリティ標準(ISO 27000)やCERT、OWASP、SANS、MITREなどが公開している資料では、従来からセキュアコーディングで最も重要なセキュリティ対策は「入力のバリデーション」としています。この事から本物のセキュリティ専門家が誤解していないことが明らかです。
問題の原因は影響力が強い「セキュリティ専門家」と言われる人達の行動と勘違いだと思われます。
- セキュアコーディングの知らない、知るつもりがない
- ”セキュアコーディングではない設計”を”セキュアコーディング”だと勘違いしている
これらの事例を紹介する前に、本物のソフトウェアセキュリティ専門家であるコンピューターサイエンティストがなぜ「入力バリデーションを第一のセキュリティ対策としているのか」を簡単に解説します。
正しくプログラムを実行するには、コードが正しく処理できるデータが必須である
セキュアコーディングは「コードが確実に正しく動作するように書く」を実現することを目的にしています。”モグラ叩き的”に「脆弱性を作らないように書く」はセキュアコーディングではありません。
「脆弱性を作らないように書く」は悪いモノを定義し禁止するブラックリスト型の対策で仕組み的に脆弱です。「コードが確実に正しく動作するように書く」は良いモノを定義し許可するホワイトリスト型の対策で、「脆弱性を作らないように書く」とは比較にならないほど堅牢です。
脆弱性を利用した攻撃はプログラムが意図しないデータ(≒不正な入力)を与えて誤作動させることで行われます。そもそもプログラムが意図しない不正なデータを受け入れなければ(ホワイトリスト型のセキュリティであれば)攻撃そのものが不可能となるケースは多数あります。
「正しく動作するソフトウェア」=「脆弱性がないソフトウェア」
これの必須必要条件が「妥当な入力(正しい入力+入力ミス)」であることを保証する入力バリデーションです。
コンピュータの動作原理:妥当なデータでしか「正しく動作するソフトウェア」作れない
コンピューターは妥当なデータでないと整数でさえ正しく取り扱えません。より複雑な文字列の場合、未検証のデータは「ちょっとしたミス」でありとあらゆる問題の原因になります。
単純な形式のデータで厳格なバリデーションが可能な場合、ほぼ全てのインジェクション攻撃を無効化/防止することも可能です。
セキュアコーディングの知らない、知るつもりがない
この問題はかなり根が深いと思われます。一つ事例を紹介します。
2年ほど前に「IPAのセキュアプログラミング講座は、ISO 27000やCERTのいうセキュアプログラミング/セキュアコーディングではない。セキュアコーディング最大のセキュリティ対策である入力バリデーションがないセキュアコーディングはあり得ない」とIPAに指摘するメールを送りました。
椅子から転げ落ちるような間違いだけ紹介します。
第6章 入力対策
コマンド注入攻撃対策
(中略)コマンド注入攻撃のメカニズム
コマンド注入攻撃は、外部から取り込んだデータをコマンド文字列の一部に組み入れて、それをシェルに実行させる場面が狙われる。コマンド注入攻撃のメカニズム
図6-1: コマンド注入攻撃のメカニズム
例えば、次はsendmailコマンドを利用してメールを発信する例である。例(Perlスクリプト)
$to_address = cgi->param{‘to_address’};
$message_file = “/app/data/0012.txt”;
system(“sendmail $to_address <$message_file”);
「入力対策」と題した章なのに、コマンドインジェクションの例としてsystem()が利用されています。system()のパラメーター処理はOSコマンド用の「出力対策」であり、「入力対策」ではありません。
「入力対策」と「出力対策」が入れ替わっている、基礎的間違いです。
旧版IPAセキュアプログラミング講座では「入力バリデーション」には一切触れていません。これでISO 27000が要求する「セキュアプログラミング」とするのはお粗末すぎる内容です。
しばらくして、「確かにその通りなので現在のセキュアプログラミング講座は削除する」との旨の返信を頂きました。2016年になって誤りがあった旧セキュアプログラミング講座は更新され、現在はCERT Top 10 Secure Coding Practicesをベースにしたセキュアプログラミング講座に一新されています。1
IT技術者であればよくご存じの通り、IPAと言えば情報セキュリティ対策を啓蒙する組織です。国際情報セキュリティ標準であるISO 27000の策定にも関わっているIPAでさえ、今年になるまでセキュアコーディングの原則1の入力バリデーションをセキュリティ対策として広めていませんでした。
これは、IT専門家が「セキュアコーディングを知らない、知るつもりがない」の典型的な例と言えるでしょう。
※ IPAの標準規格を策定する部署と国内向けに情報セキュリティ対策啓蒙する部署は異なると聞いています。標準規格を策定しているセキュリティ専門家まで知らなかった、知るつもりがなかった、はさすがに無いはずです。ISO 27000には入力バリデーションの実装方法が詳しく記載されていましたし、2013年改訂版では「せユアプログラミング技術の体系化が進み広く普及した」として実装方法が省略され「セキュアプログラミング技術を採用する」と簡略したのですから。
”セキュアコーディングではない設計”を”セキュアコーディング”だと勘違いしている
これは「セキュアコーディングの知らない、知るつもりがない」と深く関連していると思われます。
セキュアコーディングの第一の原則は、信頼境界で入力をバリデーションする、です。第七の原則(IPA版は第二の原則)は、出力を無害化する、です。ISO 27000(ISO 17799)は10年以上に渡ってセキュアコーディング原則1の実装と管理方法を具体的に記載してきました。
CERTセキュアコーディングに準拠したプログラムにするには、全ての原則を実装する必要があります。以下はPHPカンファレンス2017の講演資料ですが、セキュアコーディングの第一の原則は重要でない、必要ない、とする内容になっています。
https://www.slideshare.net/ockeghem/php-conference-2017
セキュアコーディング原則の第一番目を無視するコーディング/設計はセキュアコーディングに準拠したコーディング/設計とは言えません。
残念ながら、スライドで紹介しているように、現在あるほぼ全てアプリケーションはセキュアコーディング原則第一番目を実装せず、セキュアコーディングではありません。セキュアコーディングではない物から、セキュアコーディングを学ぶことはできません。
まとめ
こんな事を書くとまた敵を増やすと思いますが、間違っている物は間違っています。
セキュアコーディングが要求する基本的なソフトウェアセキュリティ設計 2が、全くと言ってよいほど、普及していない原因はIPAや著名なセキュリティ専門家が公開している資料から明らでしょう。
- セキュアコーディングの知らない、知るつもりがない
- ”セキュアコーディングではない設計”を”セキュアコーディング”だと勘違いしている
- +”本当のセキュアコーディングでないモノ”を”セキュアコーディング”だと啓蒙している
IPAは重大な誤りの訂正告知もなく、何も無かったようにCERT TOP 10 Secure Coding Praceticesを現在のセキュアプログラミング講座に載せています。
ソフトウェアセキュリティで最も重要かつ基礎的な対策を啓蒙せず、このために日本中で高リスクのWebアプリケーションが作られる原因を作ってしまった、とホームページで明確に記載すべきではないでしょうか?それが公的機関の責務ではないでしょうか。
出鱈目な旧版セキュアプログラミング講座は今もGoogle検索で上位に表示されます。「この旧版セキュアプログラミング講座は”セキュアプログラミングではありません”」と全てのページに注意書きを入れるべきではないでしょうか?
セキュアコーディングの話をすると、「出鱈目な旧版セキュアプログラミング講座を引き合いに出して、本家CERTのセキュアコーディング概念で説明する大垣の話の方が間違っている」反論されたものです。今でも出鱈目なセキュアプログラミングを正しい、と信じている開発者は少くないはずです。
「本来のセキュアコーディング」を理解すると、IPAや例に挙げた”セキュリティ専門家”が「信じられないような基礎的誤解」に基き、危険なソフトウェア設計を安全であるように誤解させ、危険な設計を推奨していたことが解ります。
少なくない”セキュリティ専門家”が同じように「国際標準やセキュリティガイドラインに準拠しない危険なコーディングをセキュアコーディングとしていた」ことをIT業界、特にWeb関連業界に居る方なら体感できると思います。
お粗末もしくは入力検証の欠落で甚大な被害を発生させたWebアプリがどれだけあるでしょうか?例えば、東京都の納税サイトは「普通に入力検証」していれば数十万件もクレジットカード情報を盗まれませんでした。被害はこれだけではありません。
”専門家”から「セキュアコーディングとはこうだ」と説明されると普通は「そうなのだろう」と信じてしまいます。多くの一般開発者が「本当のセキュアコーディング」を知らず、ほぼすべてのアプリケーションがセキュアコーディングになっていないのも当然だと思います。。。
最後にハッキリと書きます。「入力バリデーション」が重要ではない、要らない、セキュリティ対策ではない、などと主張する人はコンピューターサイエンティスト/セキュリティ専門家として、どこからどう見ても、失格です。セキュアコーディングの基本概念さえ出鱈目で、10年以上も一体セキュリティの何を勉強してきたのか?分かりません。
何十年も前から結論が判っている事です。度重なる指摘でも理解をせず、出鱈目なセキュリティ対策の啓蒙でどれだけ多くの脆弱性/セキュリティ問題を開発者に造くらせてきたのか?を考えると非難されない方がおかしいでしょう。
関係者の皆様におかれましては、過去の重大な誤りを訂正し、正しいセキュアコーディングの概念を強力に啓蒙頂けることを期待しています。
蛇足
長くなり過ぎたので省略しました。折角書いたので蛇足として掲載しておきます。
データ検証は必須
C言語などでは整数型(8、16、32、64ビット整数など)の入力でさえデータバリデーションをしないと、オーバー/アンダーフローしないこと保証できません。整数オーバーフローは時として予想外の攻撃を可能にします。例えば、MySQLでは符号付きchar型、符号なしchar型の違いにより管理者権限でのログインができてしまう問題がありました。
任意精度整数をサポートするRuby/Python3を使っているから整数オーバーフローなど関係ない!?と考えるかも知れませんが、それは間違いです。Ruby/Python3が利用するライブラリの多くはCやC++で記述されています。一般にCやC++の関数は、任意精度整数は使いません。ライブラリ内では64/32/16/8ビット整数を使い、さらに符号の有り無しがあります。
単純な整数型でさえ、オーバーフローにより不正な動作を起すことが可能です。より複雑な文字列型データの場合、データバリデーションを行わないとありとあらゆる脆弱性のリスクが生まれます。
セキュリティ対策とはリスク管理です。できる限り効率的かつ効果的にリスクを排除・削減することを目標にします。入力バリデーションは”プログラムが意図通り動作するために必須”であると同時に、”プログラマが予想していない脆弱性さえ排除・削減”できます。つまり「正しく動作」するソフトウェアには入力データには欠かせないです。
入力バリデーションですべきこと
セキュアコーディング原則1では、全ての入力をホワイトリスト型でバリデーションする、ことが求められています。
先日リリースされた2017年版OWASP TOP 10がを例に、入力バリデーションで何をしなければならないのか紹介します。
2017年版OWASP TOP 10 A10はセキュアコーディング原則1を実装し
Establish effective monitoring and alerting such that suspicious
activities are detected and responded to in a timely fashion.
(疑わしい活動がタイムリーな形で検出され対応できる効果的なモニタリングと警告を確立する)
これができないシステムは脆弱なシステムである、としています。
検出すべき疑わしい活動には以下が含まれます。
• Penetration testing and scans by DAST tools (such as OWASP
ZAP) do not trigger alerts.
(OWASP ZAPなど、DASTツールによる侵入テストとスキャンが警告を発生させない)
※ OWASP ZAPはWebアプリに攻撃用の不正な入力を効率的に送信できる攻撃用プロキシアプリです。DAST – Dynamic Application Security Testing、動的アプリケーションセキュリティテスト
攻撃用の不正な入力を検出できないと脆弱なシステムとなります。
• The application is unable to detect, escalate, or alert for active
attacks in real time or near real time
(アプリケーションが現在進行中の攻撃を即時または即時に近い時間で検出、エスカレートまたは警告できない)
ZAPで簡単に生成できる攻撃用の不正な入力は、HTMLフォームの入力に限りません。HTTPヘッダー、クッキー、URLパラメーター、HTMLフォームには含まれない余計なパラメーターや改ざんされたパラメーターなども含まれます。
これらをアプリケーションの”どこで”、”どのように”検出し対応すべきでしょうか?もちろん「入り口」で検出します。OWASPでは「今のWebアプリは入り口対策は全くと行ってよいほどない」と考えています。
どこでどのように検出すべきか?の前にまず、入力バリデーションとは何か?OWASP Code Review Guide V2.0の説明を紹介します。
7.6 Input Validation
Input validation is one of the most effective technical controls for application security. It can mitigate numerous vulnerabilities including cross-site scripting, various forms of injection, and some buffer overflows. Input validation is more than checking form field values.
(入力バリデーションは最も効果的なアプリケーションセキュリティの1つである。入力バリデーションな数えきれない脆弱性、クロスサイトスクリプティング、様々な形式のインジェクション、そしてバッファーオーバーフロー攻撃を緩和できます。入力バリデーションとは単なるフィールド値のチェックではないです。)All data from users needs to be considered entrusted. Remember one of the top rules of secure coding is “Don’t trust user input”. Always validate user data with the full knowledge of what your application is trying to accomplish.
(全てのユーザーからのデータは信頼可能でなければならない。セキュアコーディングの最大のルールの1つ「ユーザー入力を信頼するな」を思い出してください。貴方のアプリケーションがユーザーデータで何をしようといているか、全ての知識を使い、常にユーザーデータをバリデーションしなければならない。)Regular expressions can be used to validate user input, but the more complicated the regular express are the more chance it is not full proof and has errors for corner cases. Regular expressions are also very hard from QA to test. Regular expressions may also make it hard for the code reviewer to do a good review of the regular expressions.
(正規表現はユーザー入力をバリデーションする為に利用できる。しかし、より複雑な正規表現はより多くの検証不足(訳注:バグ)とエッジケースの問題を持つ可能性が高くなる。正規表現はQAからテストすることが非常に困難でもある。正規表現はコードレビューワーが質の高い正規表現のレビューを困難にする。)訳注:要するに正規表現はリスク、多用するな、です。Data Validation
All external input to the system (and between systems/applications) should undergo input validation. The validation rules are defined by the business requirements for the application. If possible, an exact match validator should be implemented. Exact match only permits data that conforms to an expected value. A “Known good” approach (white-list), which is a little weaker, but more flexible, is common. Known good only permits characters/ASCII ranges defined within a white-list.
(システムに対する全ての外部からの入力(加えて、システム/アプリケーション間の入出力)は入力バリデーションしなければならない。バリデーションルールはアプリケーションのビジネス要求で定義される。可能であるなら厳格に一致するバリデーターを実装しなければならない。厳格な一致は期待している値のデータだけを許可することを保証できる。”良いモノ”を許可するアプローチ(ホワイトリスト)は少し弱いがより柔軟で一般的である。”良いモノ”を許可するアプローチはホワイトリストで定義された文字/ASCIIの範囲のみを許可する。)Such a range is defined by the business requirements of the input field. The other approaches to data validation are “known bad,” which is a black list of “bad characters”. This approach is not future proof and would need maintenance. “Encode bad” would be very weak, as it would simply encode characters considered “bad” to a format, which should not affect the functionality of the application.
(この範囲は入力フィールドのビジネス要求によって定義される。別のアプローチに”悪いモノ”、つまり”ダメな文字”をブラックリスト化しバリデーションする方法がある。このブラックリストアプローチは将来に於て有効ではなく、メンテナンスを必要とする。”悪いモノをエンコードする”は非常に弱い、何故ならこれは単に”悪い”と考えられる文字を、アプリケーションの機能に影響しないよう、別の文字に変換するだけだからである。)訳注:要するにブラックリストはダメ、サニタイズはもっとダメ。Business Validation
Business validation is concerned with business logic. An understanding of the business logic is required prior to reviewing the code, which performs such logic. Business validation could be used to limit the value range or a transaction inputted by a user or reject input, which does not make too much business sense. Reviewing code for business validation can also include rounding errors or floating point issues which may give rise to issues such as integer overflows, which can dramatically damage the bottom line.
(ビジネスバリデーションはビジネスロジックに関係している。ビジネスロジックバリデーションに関わる全てのビジネスロジックをコードのレビュー前に理解する必要がある。ビジネスバリデーションは値の範囲を制限したり、ユーザーによるトランザクションであったり、論理的に意味をなさない入力の拒否である。ビジネスバリデーションのコードレビューには丸め誤差や前提を劇的に破壊する整数オーバーフローなどを起こす浮動小数点問題が含まれる。)
入力バリデーションにはData Validation(データバリデーション)とBusiness Validation(ビジネスロジックのバリデーション)があります。この区別をしっかり理解している必要があります。
Data Validationは入力値のデータ形式をISO 27000が要求する方式でバリデーションします。データの論理的な正しさを検証する必要はありません。3形式だけで十分です。アプリケーションのData Validationはアプリケーションの信頼境界で行います。適切な場所はMVCモデルなら”コントローラー”です。
Business Validationはビジネスロジックとして、送信された日付が存在する日付か?ビジネスロジックとして正しい日付か?(例えば予約で過去の日付はあり得ない)などデータの論理的な妥当性をバリデーションします。適切な場所はMVCモデルなら”モデル”です。
- 2016年10月の改定ではCERT Top 10 Secure Coding Practicesは紹介されておらず、2017年6月の改定で追加されたように思います。前の版は参照できないようなので前の版(2016年10月版)のURLをご存じの方、教えてください。 ↩
- 信頼境界での入力バリデーション ↩
- クライアントが送ってくることが可能なデータであることをバリデーションします。Data Validationでの論理的バリデーションは必要ありません。クライアントが存在する日付だけ送ってる、クライアントは過去の日付を送ってこない、といった条件があり簡単に検証できるのであれば「存在する日付」「未来の日付」である論理的バリデーションを行っても問題ありません。というより、可能であるならこういったバリデーションをコントローラーで行った方が良い場合も少なくないです。 ↩