おかしなCWE-20の読み解き方(CWE-20入門)

(Last Updated On: 2019/02/17)

徳丸さんが独自のCWE-20(≒入力バリデーション)解説を行っているので、CERT(1989年に米カーネギーメロン大学に設置された世界最古のコンピューターセキュリティ専門機関)が30年くらい前から提唱し、ISO 27000/NIST SP-800-171/PCI DSS等で要求されているCWE-20の解説を改めて書きます。

CWE-20(入力バリデーション)がなぜ重要なのか?それはCERT/MITRE/ISOが入力バリデーションをどのように解説しているかを見れば解ります。いずれも最も重要/一番最初の対策としています。(※ MITREはCWEを管理する組織で、CWEの本家と言える組織です)

徳丸さんのブログより前に、このブログでもCWE-20について以下のブログで既に書いています。CERT(≒米カーネギーメロン大学のコンピューターサイエンス学科)が提唱するセキュアコーディング/コンピューターサイエンスの基盤となる基礎概念の紹介では十分ではなかったかも知れません。

本来の趣旨を歪める引用と解説

CWE-20とは
本稿のテーマCWE-20は、インジェクションも包含する大分類になっています。先程引用した図からCWE-20関連のみを抽出したものを以下に示します

(略)

前述のインジェクションに加えてパストラバーサルなども含まれていますね。すなわち、外部からの入力値に起因する脆弱性がCWE-20としてまとめられています。
それにしても、CWE-20は「不適切な入力確認」(Improper Input Validation)と説明されていますが、これらはバリデーションの問題でしょうか。
そうではありません。パストラバーサルはバリデーションで対策可能ですが、インジェクション系のXSSやSQLインジェクションがバリデーションにより対策できない(完全な対策にならない)ことは明らかです

出力対策によるセキュリティ対策が完全な対策である、とする自論の為の前振りの文章です。おかしな部分は、(入力)バリデーションではインジェクション対策として完全な対策にならないことが明らかである、従ってCWE-20に関連する脆弱性として分類されるXSS(JavaScriptインジェクション)やSQLインジェクションに対して有効ではない、と示唆している事です。入力と出力、両方の対策がないとインジェクション対策は十分になりません。これについては後程より詳しく説明します。

続く文として

なのに、どうして、CWE-20は「不適切な入力確認」なのでしょうか。その答えは、本家のCWE-20の解説中にあります。

Some people use “input validation” as a general term that covers many different neutralization techniques for ensuring that input is appropriate, such as filtering, canonicalization, and escaping. Others use the term in a more narrow context to simply mean “checking if an input conforms to expectations without changing it.”

CWE – CWE-20: Improper Input Validation (3.2)より引用
私訳を以下に示します。
フィルタリングや正規化、エスケープなど、入力が適切であることを確実にするためのさまざまな無効化手法をカバーする包括的な用語として「入力検証(Input Validation)」を使用する人もいます。他の人達は、より狭い文脈、すなわち、単に「入力を変更することなく、期待される値であることを確認する」という意味でこの用語を用います。

ということで、Input Validationはエスケープやフィルタリングを含む包括的な用語として使われる場合があることがわかります。CWE-20のInput Validationはこちらの意味でしょう。そうでないと、SQLインジェクションやXSS等をカバーする理由を説明できません。

これはCWE-20入門の解説としては完全にアウト、「本来の趣旨を歪める恣意的引用と解説」です。なぜでしょうか?それはCWE-20全体を見れば明らかです。

上記のCWE-20引用部分はCWE-20のNotes(備考)の項のGlossary(用語)に記載されている文章です。これが何処に記載されているか?MITREのCWE-20のページ全体のスクリーンショットの一番下の青枠で囲った部分です。

この引用部分をMITRE(=CWE)の意図通り引用/解説すると

Notes

Terminology

The “input validation” term is extremely common, but it is used in many different ways. In some cases its usage can obscure the real underlying weakness or otherwise hide chaining and composite relationships.
Some people use “input validation” as a general term that covers many different neutralization techniques for ensuring that input is appropriate, such as filtering, canonicalization, and escaping. Others use the term in a more narrow context to simply mean “checking if an input conforms to expectations without changing it.”

多少の意訳を含めて訳すと、以下のようになります。

備考

用語

”入力バリデーション”は非常によく利用される用語である。しかし、これは多くの異なる意味で利用されている。一部のケースでは実際の脆弱性を目立たなくしたり、脆弱性の繋がりや構成関係を隠したりする意味で使われている。一部の人々は”入力バリデーション”を入力が適切であることを保証する、多くの異なる脆弱性無効化テクニック、例えばフィルタリング、正規化やエスケープ、の一般的な用語として利用している。他の人々はこの用語を更に狭いコンテクストで利用し、単純に”入力が修正無しに期待するモノと一致するかのチェック”の意味で使っている。

この”備考”の”用語”が意図していることは、CWE-20で定義している”入力バリデーション”とは”異なる意味で利用している人々が居る”ことの紹介であることは明らかです。CWE-20の定義と解説は”備考”の前に解説されています。(話を単純にするため、その定義/解説は省略。もっと良いCWE-20入門文書を後で紹介します)

結構長いCWE-20の解説本文の意図を無視した上、最後に誤解防止の為に記載した”異なる意味での利用”がある、とする第一文も無視した引用と解説になっています。

重要なので誤解ないよう繰り返しますが、

”入力バリデーション”は非常によく利用される用語である。しかし、これは多くの異なる意味で利用されている。

と最初に書かれているいる通り、”入力バリデーション”はCWE-20やCERTセキュアコーディングで解説している意味で利用されておらず、別の意味で利用している人々/ケースがある、だから誤用に注意するように、とする備考です。

この備考は”誤用防止”の為の”他の用語の使われ方”(=体系的ソフトウェアセキュリティとしては”誤用”にあたる使われ方)の解説文であることは全体を読めば解ります。CWE-20の実装要求に「エスケープする」とも「フィルタリングする」とも記載されていません。にも関わらず徳丸さんはこの備考の用語の”他の人々の使い方”(※ 用語定義ではない)を利用し

ということで、Input Validationはエスケープやフィルタリングを含む包括的な用語として使われる場合があることがわかります。CWE-20のInput Validationはこちらの意味でしょう。

と結論付けています。この解釈は明らかにおかしいです。CWE(MITRE)やCERT、ISO、OWASPのInput Validationにエスケープやフィルタリングは含まれません。

※ 特に2017年版OWASP TOP 10のA10は誰にでも明確に理解るように”フィルタリング”(無効な値の無視)はソフトウェア脆弱性だとしています。 「エスケープやフィルタリング」を入力バリデーションに含める定義は見た事がありません。より詳しいブログも書いたので詳しくはそちら。

切り取って誤解を与える、を通り越して全く異なる意味で引用/解説しています。”CWE-20入門”としながらCWE-20の解説を全てすっ飛ばした上に、”備考”に書かれた別の用途/意味での利用状況の説明を、自論に都合が良いように解釈し正反対の意味で引用するのは頂けません。

CWE-20本来の意味を理解り易く解説している入門文書は、CWEを管理しているMITRE自身が作ったCWE/SANS TOP 25のMonster Mitigations M1です。CWE-20入門ならこれを参照すべきです。

因みにCWE/SANS TOP 25のMonster Mitigations M1のCWE-20解説では、標準入力バリデーション(Standard Input Validation)は以下を行うとしています。

Use a standard input validation mechanism to validate all input for:
length
type of input
syntax
missing or extra inputs
consistency across related fields
business rules

全ての入力に対して標準入力バリデーション機構を利用する:
長さ
入力種別
文法(※ 形式)
少すぎる/多すぎる入力
関連するデータの整合性
ビジネスルール

エスケープやフィルタリングなどは含まれません。余計なデータをフィルタリングするどころかバリデーションすべし(=妥当でなければエラー/拒否)としています。ISO 27000に記載されていた入力妥当性確認の要求事項もエスケープやフィルタリングは含まれません。

CWEのツリー構造を取り上げて、”大分類”であるハズのCWE-20が脆弱性として取り上げられるのはおかしい、ともしています。

CWE-20が大分類だとすると、個別脆弱性がCWE-20に分類されるのはおかしいですね。上記はどのようなものなのでしょうか。

CWEのツリー構造は単なる大中小分類と最終的な対策ではありません。分類となるCWEはビューとして明確に区別されています。例えば、CWE-700の7PKがビューです。当然ですが、CWE-20はビューではありません。セキュリティ専門家なら常識として知っているべきことです。

後述する業界標準のソフトウェアセキュリティ分類(7PK)で詳しく紹介しますが、ソフトウェアセキュリティとはCWEとして定義されている脆弱性に対して、何らかの対策をすれば完了するモノではありません。適切に部品化(構造化)した上で、適切に結合させる(複数を組み合わせる)ことによって初めて十分なソフトウェアセキュリティを達成できます。

CWE-20を正しく理解するには、セキュアコーディング/コンピューターサイエンスの基礎の基礎の理解が必要

CERTが提唱するセキュアコーディング/セキュアプログラミングの概念、作法やガイドラインはコンピューターサイエンスに基き、エンジニアリングとして体系的にセキュアなコード/プログラムを作れるよう考えられています。一言でいうと

  • どうやってエンジニアリング的に正しく動作するコードを書くか?

を考えて作られています。

  • どうやって脆弱性を作らないか?潰すのか?

といった考え方では作られていません。これら2つは似ている様で根本的な部分で異なる別のモノ(概念)です。

前者は正しいモノを定義するホワイトリスト型の概念で、後者はダメなモノを定義するブラックリスト型の概念です。ブラックリスト型の対策は構造的に脆弱で間違い易い、というより間違える(=不十分である)ことが必至の対策です。このためCERT/MITRE/ISOなどのコンピューターサイエンスに基づくソフトウェアセキュリティを提唱するセキュリティガイドラインでは、入力バリデーションを含め、必ず厳格なホワイトリスト型のデータ検証を第一の対策として実施するように求めています。

正しく動作するコードを書くための鍵となる基本概念は次の概念です。

  • 妥当性検証 – プログラムは正しい”コード”と正しい”データ”の両方がないと正しく動作できない。これはコンピュータープログラムの不変の動作原理である。セキュアコーディング/セキュアプログラミングは「正しい”コード”と正しい”データ”」であることをできる限り保証できるプログラムとなるよう体系的に構築されている。
  • ホワイトリスト – 正しく動作するコードとデータであることを保証するには、ホワイトリスト型の妥当性検証が欠かせない。ダメなモノ(正しく動作しないコード/データ)を禁止するブラックリスト型の妥当性検証では容易に漏れが生じる。セキュアコーディング/セキュアプログラミングはアンチパターンも例示するが、正しいコードをとはどのようコードなのか?を示すことが本来の目的である。
  • ゼロトラスト – コードもデータも妥当性検証済みのモノ以外は全て信頼しない。妥当性検証済みのモノでも「検証の範囲内」でしか信頼できない。「多層」「複数」の検証が必要となる場合が多い。場合によっては妥当性検証済みのモノでも信頼しない。(≒多層防御)
  • フェイルファースト – 失敗するモノはできる限り早く失敗させる(できる限り早く妥当性検証する)。主たる対策は失敗するモノをできる限り早く失敗させる(できる限り早く妥当性検証する)対策となる。それ以降の対策は追加の多層防御となる。(信頼可能な範囲は「検証の範囲内だけ」である点に注意。検証範囲外のモノは更に検証が必要)できる限り早く失敗させず、失敗するモノを処理してもセキュリティ問題の原因となるだけで何のメリットもない。
  • 多層防御 – ゼロトラスト+フェイルファーストで対策していても、ITシステムは人が完全に最適化された状態に管理することが不可能であるくらいに複雑である。妥当性検証漏れ(データ妥当性検証バグ)、妥当性検証の過信や仕様バグ(コードロジックのバグ)を完全に排除することは難しい。これらのバグによる問題を防止する為、追加の対策として多層防御、複数の検証、可能な限りの出力の無害化を行う。
  • 境界防御 – 信頼境界で行う防御策で、ソフトウェアの場合は入力バリデーションと出力無害化が主な境界防御である。入力バリデーションと出力無害化は”独立した対策”として扱うのがソフトウェアセキュリティの原則である。

これらの概念は基礎的すぎるためか、セキュアコーディング/セキュアプログラミングの解説でも十分に解説されることがありません。とは言っても

プログラムは正しい”コード”(ロジック)と正しい”データ”の両方がないと正しく動作できない

は不変の動作原理であり、この原理から妥当な(≒正しい)コードと妥当な(≒正しい)データであることを保証するセキュアなコードの作り方は自ずと明らかで、上記の考え方が必要になります。

妥当なコード(=正しく動作するコード)をどう作るのか?

答えは既に説明済みです。

  • 妥当なデータが必要
  • 妥当なコード(ロジック)が必要

データの妥当性検証は容易です。CWE-20対策を一言で言うと

全ての外部入力(=信頼できない入力)を全てホワイトリスト型で妥当性検証する

です。

妥当なコードであることの研究は「形式的検証」(Formal Verification)として60年代〜70年代にかけて活発に研究されました。大別して

  • 論理的(数学的)に妥当性を検証
  • 総当たりで妥当性を検証

の2つに分けられます。

数学的なアルゴリズムが論理的に正しいと証明することは比較的容易です。「比較的容易」とは言ってもバブルソートのような簡単なアルゴリズムでも、数学的に正しくソートできることを証明することを”容易だ”を感じる方は少ないでしょう。論理的に正しいコードであることを証明できればそれに越したことはありません。しかし、現実のコード(特に業務ルールなど)が数学的に正しいと証明することは容易ではありません。

そこで総当たり方式でコードの妥当性を検証する手法も考案されています。取り得る入力を総当たりでプログラム/コードに与えて期待する結果/出力となるか検証するシンプルな方式です。コンピューターに処理させれば済むことなので、簡単に検証できる、とはなりません。実用的なプログラムの入力組み合わせは膨大になり、コンピューターを使っても処理することが非現実的となる組み合わせ爆発が容易に発生するからです。

※ ユニットテストと”形式的検証の総当たり方式”は似ていても異なるモノです。

論理的(数学的)な妥当性を検証の場合、妥当なデータ以外は全て有害なゴミ入力でしかありません。検証の前に妥当なデータ以外は全て排除することが大前提です。

総当たりの妥当性検証の場合も、妥当なデータ以外は不必要に組み合わせ爆発を誘発させるゴミ入力でしかありません。そもそもゴミデータがプログラム/コードに入り込まないよう全て排除することが大前提です。

セキュアなコードの探求はコンピューターサイエンスの歴史と同じくらい長いです。”コンピューターサイエンティスト”が生まれる前の科学者は数学者でした。このため昔は実用的でないとされていた関数型言語のLISPを使ったプログラミング/研究が盛んに行われました。(※ LISPは最古のプログラミング言語の一つ)70年代には欧州を中心に”形式的検証”の研究開発が精力的に行われ、80年代には契約プログラミング/契約による設計をサポートしたEiffelも開発されました。現在ではほとんどのプログラミング言語が何らかの契約プログラミングサポート機能を持っています。

構造的に出力対策”だけ”ではソフトウェアセキュリティは実現できない

単純にプログラム/コードは妥当な入力(プログラム/コードが期待する妥当なデータ)でなければ、絶対に正しく動作できません。動いているように見えても正しく動作していません。

  • 出鱈目なデータを無視して動作している
  • 出鱈目なデータを処理/保存している
  • 本来はフェイルファーストで対処すべき出鱈目なデータが”多層防御”機能で本来エラーとなるべき場所以外でエラーになっている(例: SQLを実行した時に構文エラーや制約エラーとなる)

データを出力する時点で、データの形式的妥当性と論理的妥当性を効率良く体系的に検証する方法はありません。

  • SQLインジェクション対策にはプリペアードクエリ/プレイスホルダ”さえ”使っていれば良い

これは長年正しいセキュリティ対策かのように誤解されてきましたが、コンピューターサイエンティストは何十年も前からこのような事を主張したことはありません。原理的/論理的な誤りがある、あり得ない主張だからです。

※ なぜ?と思った方は、 SELECT user_specified_col FROM user_specified_tbl ORDER BY user_specified_sort_col、 といったクエリを正しく(安全に)実行する方法を考えてみてください。user_specified_* は全てユーザーが設定可能なSQLの”識別子”とします。

ソフトウェアセキュリティ業界標準の脆弱性分類と入力バリデーションの解説

ソフトウェアセキュリティ業界標準の脆弱性分類と言えば7PKでしょう。名前を聞いた事がなくても7PKに則ったもしくはほぼ同じソフトウェア脆弱性分類はかなり広く利用されています。

7PKはソフトウェア脆弱性の包括的な分類として2005年に提唱された分類方法です。CWE-700としても定義されており、MITREのサイトから論文全文を参照できます。

この論文の優れた点は単純に分類するだけでなく、その分類を作った背景や意図も解説し、その解説が秀逸であることです。

「APIの乱用」では、契約プログラミングの考え方の例に挙げ

APIはコーラー(Caller – 呼び出し側)とコーリー(Callee – 呼び出される側)の契約である。最も多いAPIの乱用はコーラーがコーリーの契約を守らない形で起きる。

と解説しています。プリペアードクエリを例にすると

  • SQL文とSQL文のパラメーターを分離し(契約1)、SQLデータベースサーバーで実行する(契約2)

となり、それ以外の問題は契約外(仕様外)です。従って、プリペアードクエリは

  • パラメーターが不正な値であることは契約外。当然、構文/制約エラーとなることも関知しない。(例: 整数値に英字、0〜140までの年齢に150、抽出レコード数制限に1億、など)
  • パラメーター以外が変数である場合の問題は契約外。”識別子”(カラム名/テーブル名など)や”SQL語句”(ASC/DESCなど)に対する防御はない。

といった問題が発生します。その上、今時のSQLデータベースは正規表現、JSON、XML、配列といったデータも保存でき、これらにインジェクション攻撃ができます。(詳しくは、完全なSQLインジェクション対策を参照)

  • SQLインジェクション対策にはプリペアードクエリ/プレイスホルダ”さえ”使っていれば良い

として入力バリデーションせずに仕様すると、明らかなAPIの乱用になります。

「セキュリティ機能」では、「セキュリティ機能を使うことはソフトウェアセキュリティではない」と次のように解説しています。

ソフトウェアセキュリティとはセキュリティソフトウェアではない。欠かせないセキュリティ機能として頼れるモノではあるが、全ての暗号機能は魔法のようなあなたのコードを安全にする為に役立たない。ネットワークトラフィックを保護する為にSSLを使うと決めたとしよう。しかし、開発者は簡単にセキュリティを滅茶苦茶にできる。残念ながら、これは何時でも何処でも起きている。セキュリティ機能を分解/結合させたとき、開発者は認証、アクセス制御、機密性、暗号、権限管理やCISSP試験で必要とされる全ての要素、これらの課題について考慮しなければならない。これらのモノを全て正しく実装することは難しい。

プリペアードクエリも”セキュリティ機能” の一つで、プリペアードクエリの利用も同じで、プリペアードクエリを使うだけではSQLデータベースのセキュリティは確保できません。任意のSQL文を実行させるSQLインジェクション攻撃を完全に防止するにも入力バリデーションが欠かせません。 ※ 先ほど例示した、SELECT user_specified_col FROM user_specified_tbl ORDER BY user_specified_sort_col、だけで明白です。

セキュリティ機能を分解/結合させたとき…CISSP試験で必要とされる全ての要素、これらの課題について考慮しなければならない

ソフトウェアセキュリティは「◯◯機能を使えば万事OK、全て解決する」といったモノは”ほとんどありません”。ほぼ全てのソフトウェアセキュリティ対策は複数のセキュリティ機能を適切に分解(部品化)し、適切に結合させる必要があります。

CERT Top 10 Secure Coding Practicesの第7位の出力対策では次のように解説しています。

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

つまり適切な入力バリデーション(形式的および論理的)と出力対策は独立したソフトウェアセキュリティ対策であり、”複数のセキュリティ機能を適切に分解(部品化)し、適切に結合させる必要があります”、の一例となっています。体系的に全て実施しないとソフトウェアセキュリティは確立できないのです。

入力バリデーションは必須の対策として7PKの1番目の悪質な問題として挙げられ、以下のように解説されています。

Input validation and representation (入力バリデーションと表現)
メタ文字、異なるエンコーディング、数値表現などは入力バリデーションと表現の問題を発生させる。開発者が単純に一切の入力バリデーション実施を忘れてしまう事も少くない。もし入力バリデーションを実施すると決めたなら、ホワイトリスト型を使いなさい、ブラックリストでなく。
過度に入力を信頼することが大きな問題を生み出す。 バッファーオーバーフロー、XSS、SQLインジェクション、キャッシュ汚染など、スクリプトキディ(攻撃用ツールを使えるだけのレベルの低い攻撃者)が大喜びするほぼ全てのレベルの低い攻撃に利用される

過度に入力する(≒適切な入力バリデーションを行わない)アプリケーションは”スクリプトキディ”が大喜びするとしています。”スクリプトキディ”にはアプリケーション外部から脆弱性診断を行うセキュリティ業者も含まれます。脆弱性診断を行うセキュリティ業者も犯罪者と同じ方法で脆弱性を見つけているので喜ばないはずがありません。

紹介した徳丸さんのブログの内容は一見すると「筋の通った話」に見えるかも知れません。しかし、コンピューターサイエンスの基礎の基礎を考慮していない、CWE-20の記述を無視した、とてもおかしな解説になっています。科学的/論理的なソフトウェアセキュリティの視点からは、どう考えてもCWE本家のMITREがCWE-20入門の解説ブログとして”適切な内容である”と評価されることはないでしょう。

参考: CWEを管理するMITRE自身がCWE-20の解説

参考: CWE-700として定義されている7PK

参考: セキュアコーディングのおかしな解釈

参考: OWASPが言っていない事をOWASPの主張かのように…

まとめ

未検証入力、不十分な検証の入力があると何をやってもセキュアなソフトウェアは作れません。

  • 正しく(=セキュアに)動作するソフトウェアには妥当なコードと妥当なデータの両方が必要

だからです。(※ ISO 27000の定義では、セキュアなITシステムは機密性/完全性/可用性/信頼性/真正性/責任追跡性(否認防止)を保つ必要があります。これらの特性維持に「妥当なデータであることの検証」が不可欠です)

「こうやった方がセキュアだ」と思うことは自由です。他人が書いたモノ、セキュリティ標準とされるようなモノとは異なる概念であることも自由です。

しかし、他人が書いたモノ、特にセキュリティ標準とされるようなモノを「恣意的に引用」し、本来の意図とは大きく外れ、正反対の意味であると解釈するものである、とするのはおかしいです。

MITRE/CERT/ISOの文書をしっかり読めば理解ることですが、大半の開発者は忙しく、セキュリティは重要と理解っていても「まとめ解釈」に頼っているのではないでしょうか?適切なまとめであれば問題は少ないですが、本来の意図から外れるようでは有害である、とするしかありません。

マスコミ/ネットで発言や文書の一部を切り取り、本来の趣旨を歪めて引用するテクニックが問題になっていますが、徳丸さんの「CWE-20入門」と題するブログも同じテクニックを使っています。私が知る限りではOWASP TOP 10の初版で第一位の脆弱性としていた「Unvalidated Input(未検証入力)」が削除された時にも同じテクニックを使っています。

IPAの「安全なウェブサイトの作り方」も同類の問題を持っています。IPAの「安全なウェブサイトの作り方」は体系的なソフトウェアセキュリティ対策の考え方からは出鱈目と言える内容で、危険なソフトウェアの作り方の紹介になっています。”妥当なデータ”は安全なソフトウェアには必須なのに、一切無視しているからです。

IPAの「セキュアプログラミング講座」も同じ問題を持っていました。2015年頃にその問題を指摘し修正、正確には旧版廃止、の旨の返信を得ていました。2017年頃に刷新され、2018年には公開状態のままだった旧版のWebページも修正されました。「安全なウェブサイトの作り方」の修正はいったい何時になるのでしょうか?

Facebook Comments
Pocket