セキュアコーディングを理解できていない例

(更新日: 2017/03/24)

追記:解りづらい、とご指摘があったので「セキュアコーディング方法論再構築の試み」を再構築してみるとして書き直してみました。このエントリの方が詳しいですが、よろしければこちらもどうぞ。

セキュリティの専門家と呼ばれる人であってもセキュアコーディング/セキュアプログラミングを正しく理解していない例は散見されます。今回はそのケースを紹介します。

参考:セキュアコーディングについて詳しくない場合、このブログを読む前にセキュアコーディング/セキュアプログラミングの歴史は理解しておた方が良いかも知れません。

最近目に留まったセキュアコーディングを理解できていないケースはこれです。※以下、「スライド」と呼びます

セキュリティ専門家の仕事はソフトウェア開発者が間違えやすいケースを挙げて、間違えないようにするのも仕事の1つです。このスライドの内容を文字通りに理解すると、正反対になるように読めます。セキュアコーディング/セキュアプログラミングの基本概念を曲解して解説しています。

このスライドの意図はソフトウェアセキュリティ専門家が考えているセキュアコーディング、特に入力バリデーションと信頼境界線の考え方が間違っている、あるいは効果的ではない、と理解させることだと思われます。

主な問題点

  • 信頼境界線の考え方が間違っている
    • 信頼境界線の引き方が理解されていない
    • 信頼境界線に入力と出力があることが理解されていない
    • 入力と出力のセキュリティ対策が独立であることが理解されていない
  • CERTの資料を引用しているのに重要な事項が抜けている(出力対策は独立)
  • OWASPのセキュアコーディングの資料として引用する資料が不適切

まず代表的なセキュアコーディングの解説としてCERT Top10 Secure Coding Practicesが紹介されています。このトップ10のセキュアコーディング/セキュアプログラミング習慣はその優先順位を含め、非常に注意深く考えられた良い指針になっています。これを紹介するのは良いのですが、理解が全く間違っていたり、重要な部分を解説していません。

CERT Top 10 Secure Coding Practicesでは第1のセキュリティ対策として「入力をバリデーションする」を挙げています。第7位のセキュリティ対策として「他のシステムに送信するデータを無害化する」を挙げています。

スライドでは項目名しか記載されていませんが、その内容は以下の通りです。

1. 入力をバリデーションする

全ての信頼できないデータソースからの入力をバリデーションする。適切な入力バリデーションは非常に多くのソフトウェア脆弱性を排除できる。ほぼ全ての外部データソースに用心が必要である。これらにはコマンドライン引数、ネットワークインターフェース、環境変数やユーザーが制御可能なファイルなどが含まれる。

7. 他のシステムに送信するデータを無害化する

コマンドシェル、リレーショナルデータベースや商用製品コンポーネントなどの複雑なシステムへの渡すデータは全て無害化する。攻撃者はこれらのコンポーネントに対してSQL、コマンドやその他のインジェクション攻撃を用い、本来利用してない機能を実行できることがある。これらは入力バリデーションの問題であるとは限らない。これは複雑なシステム機能の呼び出しがどのコンテクストで呼び出されたか入力バリデーションでは判別できないからである。これらの複雑なシステムを呼び出す側は出力コンテクストを判別できるので、データの無害化はサブシステムを呼び出す前の処理が責任を持つ

重要な部分は太字にしました。出力対策のセキュリティ処理の責任は出力を行うコードにある、ということです。SQLならSQLクエリを送信するコード、HTMLならHTMLを出力するコードが出力のセキュリティ対策を行う必要があります。

スライドの12ページ目ではこのように解説されています。

Screenshot from 2016-07-22 08-33-12

入力処理のセキュリティ処理と出力処理のセキュリティ処理は”独立”した対策であり、CERT Top 10 Secure Coding Practicesの出力処理のセキュリティ対策でも

  • リレーショナルデータベースや商用製品コンポーネントなどの複雑なシステムへの渡すデータは全て無害化する
  • データの無害化はサブシステムを呼び出す前の処理が責任を持つ

と明記されています。次のページ(13ページ)では「こうですか、わかりません」と記載され×が付けれられています。入力のセキュリティ対策をすることだけがセキュアコーディングではありません。

Screenshot from 2016-07-22 08-45-19

CERT Top 10 Secure Coding Practicesを紹介しているにも関わらず、

  • リレーショナルデータベースや商用製品コンポーネントなどの複雑なシステムへの渡すデータは全て無害化する
  • データの無害化はサブシステムを呼び出す前の処理が責任を持つ

を全く無視しています。この場合、”出力コード”がSQLを出力する前にエスケープ、安全なAPI、バリデーションのどれかをしないとセキュアコーディングになりません。

スライド10ページではCERT Secure Coding StandardのJava版のIDS00-Jの解説を例に挙げて「こうですか、わかりません」という論理展開になっています。

Screenshot from 2016-07-22 08-49-42

IDS00-Jは前半部分で「信頼境界線を越える入力のセキュリティ対策(バリデーション)」、後半部分で「信頼境界線を越える出力のセキュリティ対策(エスケープ、安全なAPI利用、バリデーション)」解説しています。(”コマンドインタプリタやサーバに渡される文字列データはすべて”、に”渡される”と記載されており出力対策であることは明らかです)

スライド19ページ目に「こうだった」と記載されていますが、

Screenshot from 2016-07-22 08-59-57

セキュアコーディングで最も重要な指針の1つであるCERT Secure Coding Practicesでは、そもそもリレーショナルデータベースの出力は安全化すると記載されています。IDS00-Jは後半部分でも「信頼境界線を越える出力のセキュリティ対策(エスケープ、安全なAPI利用、バリデーション)」を行いなさい、と解説しています。

「こうだった」ではなく、そもそもCERTのセキュアコーディング/セキュアプログラミングの考え方では入力と出力のセキュリティ処理は独立した対策であり、このスライドの信頼境界線は出力の境界でありCERTの資料でも「出力時に安全な出力(SQL呼び出し)」をしなさい!と書かれています。

「入力時と出力時のセキュリティ対策を同時に書くから解りづらくなっている!」と思うかも知れませんが、ここの記載は”信頼境界線”での対応方法が解説されています。信頼境界線には入力と出力があることは自明です。

解説は省略しますが、スライドの中では”間接SQLインジェクション”を使い、信頼境界線には意味がないかのような説明がなされています。しかし、データベースも信頼境界線の外にある外部システムです。データベースを信頼境界線の中に入れてしまう間違いは、ソフトウェアセキュリティを理解していない場合に”よくある間違い”の1つです。

ソフトウェアの信頼境界線とは「自分のコードの中と外」の境界が信頼境界線になります。※ ソフトウェア開発者にとって最も重要な信頼境界線は自分が作っているソフトウェアの入出力部分です。アプリケーションならアプリケーションへの入出力(ブラウザ、データベース、OSなど)、ライブラリならAPIの入出力が最も重要な信頼境界線になります。

※ 自分のコードで書いたモノ、コード中のリテラルなど、以外は全て信頼できないモノ

以下はソースコード検査に耐えるコードとは?の25ページの画像です。赤い枠が正しい信頼境界線の引き方/考え方になります。(モジュール/関数レベルでの入出力の考え方は24ページ参照)

Screenshot from 2016-07-22 09-27-01

スライドの中では”セキュアプログラミング/セキュアコーディング”のガイドとしてOWASP Top 10 Proactive Controlsが紹介されていますが、OWASPのセキュアコーディング/セキュアプログラミングガイドと言えば、OWASP Secure Coding Practices – Quick Reference Guideです。

OWASP Top 10 Proactive Controlsは実際の開発を行う場合で実施すべき行動(制御 – Contorl)のガイドと捉えるべきでしょう。 現在のOWASPのガイドは特定の目的にフォーカスしたガイドになっています。例えばOWASP Top 10(Webアプリ脆弱性のTop10)は当初、入力バリデーションが第1の脆弱性としていましたが、脆弱性に焦点を当てるためにリストから削除しています。これは入力バリデーションが脆弱性を排除/緩和する範囲が大きすぎる1こと、このエントリで取り上げているように「入力バリデーションだけしていればOK」と誤解/曲解されるケースがあること、が理由だと思われます。

参考:OWASPに対して失礼な誤解 – 入力バリデーションは重要なセキュリティ対策

信頼境界線、入力と出力対策など、セキュアコーディングの考え方を正しく理解すれば、脆弱性に詳しくなくても、初心者でも自動的により安全なコードが書けるようになります! 本物のセキュアコーディングを実践しましょう!

参考:エンジニア必須の概念 – 契約による設計と信頼境界線

 

解りづらい場合、ネットワークのセキュリティ対策と比較してみる

ソフトウェアの最も外となる信頼境界線での入力対策を行わないのは

  • ファイアーウォール無しでネットワークを守る

ことと同じです。ファイアーウォールが無いネットワークの安全性を保つには、ネットワーク上のデバイス全ての既知/未知の脆弱性を修正しなければなりません。これにはトンデモないリソースが必要であるとともに、現実性もありません。

ソフトウェアも同じです。ソフトウェアの最も外の信頼境界線で入力対策を行わない場合、自分が作っているソフトウェアの脆弱性のみでなく、フレームワーク/ライブラリ/インフラまで含めた全ての既知/未知の脆弱性を修正しなければなりません。

ソフトウェアの最も外となる信頼境界線での入力対策を行わないで得をするのは、攻撃者、アプリケーションファイアーウォールを売るセキュリティ業者、外部からセキュリティ検査をするセキュリティ業者だけです。セキュアコーディングが要求する厳格な入力バリデーションにはコストが必要ですが、その他のコストやリスクを考えると安いモノです。

アプリには入力は数も多いし、変化するので入力バリデーションは現実的でない!と主張される方も居るかも知れませんが、オブジェクト指向言語にインターフェース機能があるようにインターフェースは比較的安定しています。入力バリデーションは未知の脆弱性にも対応できます。ソフトウェアに潜む未知の脆弱性を全て洗い出すコストは膨大で、実施は不可能です。仮に実現したとしても、アプリが利用するフレームワーク/ライブラリ/インフラは常に変化し続けるので継続的に維持するコストは膨大です。一方、入力バリデーションは確実に実現できます。

書きたい事はまだまだ沢山あるのですが、今日のところはここまでにします。

 

まとめ

重要な部分だけおさらいします。

  • 信頼境界線の防御には入力と出力の二種類がある。
  • データの無害化はサブシステムを呼び出す前の処理が責任を持つ。つまり入力と出力のセキュリティ対策は独立した対策であり、入力バリデーションの有無に関わらず、出力のセキュリティ対策は行うモノです。
  • OWASP Secure Coding Practices – Quick Reference Guide がOWASPのセキュアコーディングガイド

ここで紹介した考え方はISO 27000/ISMSで要求されているセキュアコーディングの考え方になります。多少間違った考え方でもISMS認証が取れないことはないですが、顧客にISMS対応を要求されたソフトウェアで間違っていると問題になる可能性があります。

このブログに書いたような誤解が生まれる一因は、IPAのセキュアプログラミング講座の資料かもしれません。IPAの資料では世界標準で言うセキュアコーディング/セキュアプログラミングと「入力」と「出力」のセキュリティ対策があべこべになっています。(入力対策と出力対策が入れ替わっている。これだと混乱して当然です。)

入力と出力が反対になっているのは公的機関の資料として出鱈目がひどすぎるのでIPAには報告し、該当の資料は削除予定である旨の連絡を頂いていますが、今のところ削除はされていないようです。

 

 


  1. SANS/CWE TOP 25でもMonster Mitigations(怪物的セキュリティ対策)の一番目として入力バリデーションを挙げています。 

Comments

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です