IPAは”旧セキュアプログラミング講座は更新しない”とWebサイトに記載していましたが、次のブログで「IPAは旧セキュアプログラミングガイドの基礎的誤りを明示し、正しい原則を開発者に啓蒙すべき」と指摘したところ修正されたので第二弾です。
※ 2018年3月に指摘し、少なくとも秋頃には修正されていました。因みに現在セキュアプログラミング講座はCERTのセキュアコーディング習慣(原則)に則った科学的/エンジニアリング的に妥当な解説になっています。
第一弾では「入力処理セキュリティ対策の解説が出力処理のセキュリティ対策の解説になっており、出鱈目である」と指摘しました。修正後のページは改善はされていますが、まだ入力処理と出力処理のセキュリティ対策とを一緒に説明している点はダメなままです。 入力対策と出力対策は実施する場所が異ります。分けて説明すべきでしょう。CERT Top 10 Secure Coding PracticesもCWE/SANS Top 25 Monster MitigationもOWASP Secure Coding Quick Reference Guideも分けています。全て1番目が入力対策でが、IPAの旧セキュアプログラミング講座では入力対策の重要性が理解らないでしょう。
”入力対策”の解説としていた項目が”出力対策”の解説になっていたモノを無理矢理”入力・注入対策”にした、といった事情もあると思います。
しかし、なぜCERTがセキュアコーディング原則の第一番目としている入力対策が独立した項目ではないのでしょうか?OWASP TOP 10:2017を策定する際に「ほぼ全てのWebアプリが十分な入力対策を行っていない」と指摘されています。この現状に異論はないと思います。入力対策の不備がWebアプリにとって大きなリスクとなっています。これは今に始まったことではなく、昔からですが。入力対策解説の不備は第三弾としてブログを書くかも知れません。
今回はSQLインジェクション対策の問題点を指摘します。
現在のSQLインジェクション対策の解説
前回のようにIPAが更新するかも知れないのでWebアーカイブのURLを記載しておきます。このページから「SQL注入」のリンクをクリックするとSQLインジェクション対策のページを参照できます。
なにが欠けているのか?
先ず、入力バリデーションの効果の解説がおかしいです。
(1) 入力値チェックの徹底
入力値チェックを徹底することは、SQL注入対策に一定の効果をもつ。
”一定の効果”を持つのではなく”必須の対策”です、特にSQLインジェクション対策では。
現在のSQLインジェクション対策ページで欠けているモノは以下です。
- ”入力値チェックの徹底は一定の効果を持つ”のではなく”必須の対策”であること
- 出力コンテクストに応じたエスケープ対策
出力コンテクストの違いを理解していなかった為に基礎的な間違いをした?
SQLに限らず、出力データのコンテクストは単一とは限りません。複数のコンテクストがあったり、コンテクストが多重化している場合があります。SQLデータベースの機能としてJSON、XMLサポート機能は今では当たり前にあります。書かれた当時のことを考えるとJSON/XMLの記載がないことは理解できます。
しかし、識別子のエスケープの解説が無いこと、は理解不能です。SQLデータベースの基本機能です。 ※ パラメーターのエスケープが必要なことが実際のアプリではあるので、これが欠けている点も理解不能ですが議論の簡易化のため省略します。
SQL識別子のバリデーションとエスケープの解説は一般的SQLインジェクション対策として必須です。普通のDBMSアプリケーションは
SELECT this_col FROM this_table ORDER BY that_col
といった形で”識別子をSQLに埋め込んで使う事”が当たり前にあります。
識別子が厳格にバリデーションされていたとしても、そのまま埋め込むのはアンチプラクティスです。変数の識別子は必ずクオートし、エスケープすべきす。 ※ 入力対策と出力対策は独立した対策とし、それぞれで必要な対策を実施する。識別子のエスケープはセキュアコーディング原則の第8 縦深防御を実践する にあたる。
識別子エスケープを行わない問題:
- 本来は識別子として利用可能な文字列が利用できない
- 予約語を識別子として利用できない
- スペースなどの文字を利用できない
- 日本語などの文字を利用できない
- 万が一、入力バリデーションに不備があった場合でも影響を緩和できない
細かい仕様はDBMSによって異なりますが、識別子のエスケープをしないと本来利用できるハズの識別子名が利用できません。 ※ ここではこれらの識別としてクオートしてSQL文に埋め込める識別子名利用の是非は考慮しません。ただ、SQLアクセスライブラリなどを作る場合、不必要な制限を設けるのはアンチプラクティスと言えます。ライブラリは”汎用的”に作るモノです。
厳格かつ正確なデータバリデーション無しでSQLインジェクション攻撃を完全に防ぐことは不可能ですが、識別子のエスケープは一定の緩和効果があります。セキュリティ対策として利用しないのは非合理的です。
※ 最もよく見かける、ORDER BY col、の場合は識別子エスケープでSQLインジェクションリスクを完全に排除可能です。
識別子エスケープを解説しないSQLインジェクション対策は許容範囲なのか?
ご存知の通り、一般的なプリペアードクエリでは識別子の分離はできません。特定アプリで識別子名に制限を課しクオート/エスケープが不必要なアプリなら構わないです。しかし、
- 一般的SQLセキュリティ対策として”識別子のエスケープ”を解説しないのは著しい瑕疵があると言えるのではないでしょうか?
セキュアコーディングでは、出力対策に2つの役割(より詳しくは3つある)があります
- フェイルセーフ対策として出力データを無害化
- 必須のセキュリティ対策として出力データを無害化
フェイルセーフ対策として利用される出力無害化は、フェイルセーフでしかなくそれだけでは主たるのセキュリティ対策になりません。しかし、緩和策となる識別子エスケープでもセキュリティ対策として重要な対策です。(自由にSQL文をインジェクションできる状態とは比較にならない) フェイルセーフ(&多層防御)も必要なセキュリティ対策です。(CERT Secure Coding原則8の 縦深防御を実践する )
因みにMITRE(CVEやCWEを管理する米政府外郭団体)作成のCWE/SANS Top 25では出力対策を怪物的セキュリティ対策として第2番目に挙げています。それはCWE-116で”Improper Encoding or Escaping of Output”(不適切な出力のエンコーディングまたはエスケープ)です。
現在のISO 27000でいう所の体系的にまとめられたセキュアプログラミング技術にはCWEも含まれていると考えられます。
「入力値チェックはSQL注入対策に一定の効果をもつ」?
話を戻してSQLインジェクション対策における入力バリデーションの重要性です。SQLインジェクション対策には厳格な入力バリデーションが必須です。
例えば、次のようなクエリでは厳格な入力バリデーション、許可する識別子をホワイトリストで限定するバリデーション、がないとSQLインジェクション仕放題です。
SELECT this_col FROM this_table ORDER BY that_col
このクエリのthis_col, this_tableがユーザー入力パラメーターである場合、プリペアードクエリは無力で、エスケープしても意味がありません。どのテーブルのどのカラムのデータでも、自由にデータを取得できます。
カラム名とテーブル名の両方が外部から制御可能なケースは一般アプリケーションでは多くないはずですが、カラムを指定して抽出するクエリは一般的です。テーブル内の秘密情報を盗まれる可能性があります。
(1) 入力値チェックの徹底
入力値チェックを徹底することは、SQL注入対策に一定の効果をもつ。
入力バリデーションは”一定の効果”を持つのではなく”必須の対策”です、特にSQLインジェクション対策では。
- 入力バリデーションは”一定の効果”を持つ、では”必須”だと初心者に解らないのではないでしょうか?
しかも、入力バリデーションの解説には”識別子のバリデーションも必須である”と書かれておらず、パラメーターのバリデーションのみ解説されています。
入力バリデーションが「一定の効果をもつ」なら、プリペアードクエリも「一定の効果」しか持たない
わざわざ誤解を招く「一定の効果」を是とするのであれば、プリペアードクエリもSQLインジェクションに対して「一定の効果」しか持たないことを明言すべきでしょう。
SQL文のパラメーターを分離できても、
- その先のコンテクスト、LIKEクエリ/正規表現/配列/JSON/XMLといった要素経由したインジェクション攻撃にプリペアードクエリは無力
- 識別子に対して何の対策もない
- パラメータ分離だけでは意味がない。
- 無効/有害な数値に対して何の対策もない。 例: SELECT * FROM tbl LIMIT 999999999999;
- 無効/有害な文字列データに対して何の対策もない。
- 有害な壊れた文字エンコーディングデータを保存する可能性がある (DBMSで文字エンコーディングをバリデーションしていない場合)
- 分離が出来てもSQLエラーとなるようでは問題の原因となる (遅すぎるエラーは多種多様な問題の原因となる。エラーとなるからOK、ではセキュアコーディング/セキュアプログラミングではない)
といった問題があります。問題点を並べてみるとプリペアードクエリも「一定の効果」しかないことが一目瞭然です。
誤解が無いようプリペアードクエリも「一定の効果がある」と明示すべきしょう。
個人的には、パラメーター対策、識別子対策、プリペアードクエリ、エスケープ、そしてバリデーションも「必須の対策」とする方が誤解なく「セキュアプログラミング」が伝わると思っています。
※ セキュアコーディング/セキュアプログラミングは「脆弱性を作らない」といったブラックリスト思考の脆弱な考え方は採用していません。「アプリが正しく動作することを保証する」を目標とし、ホワイトリスト思考/フェイルファースト/ゼロトラストでアプリ/コードを作ります。この為には、できる限り早い段階での入力データバリデーションが絶対に欠かせない、とエンジニアなら理解るはずです。
注入(インジェクション)対策かつ出力対策とするなら、エスケープの説明が不十分、は許されない
「入力・注入対策」となっている点も許容範囲とは思えませんが、注入(インジェクション)対策かつ出力対策として解説されているSQLインジェクション対策にエスケープの説明が不十分である点は許されないでしょう。
※ コマンド注入(インジェクション)対策では信頼できるエスケープ処理が難しいのでエスケープを勧めないのは納得できます。しかし、バリデーションの記述がないのは何故でしょう?
IPAの新版セキュアプログラミング講座では「出力の無害化」はセキュアコーディング第二番目の原則とし、力の入れようが分かります。にも関わらずエスケープの記述があまりにも不十分過ぎます。
MITREとSANSが作ったCWE/SANS Top 25 Monster Mitigations #2は出力対策の不備です。以下のように記述されています。
M2: Establish and maintain control over all of your outputs.
Associated CWEs:
CWE-116 Improper Encoding or Escaping of Output
M2: 出力の制御維持を全体的に実施する
関連 CWEs:
CWE-116 不適切な出力のエンコーディングまたはエスケープ
CWEプロジェクトの本家のMITRE(CWEプロジェクト)が作ったガイドラインで怪物的なセキュリティ対策(注:ISO 27000のリスク対応定義から緩和策もセキュリティ対策です)#2とする項目が「エンコーディングまたはエスケープ」です。
在っても無くても構わないプリペアードクエリ実装の説明などを削除してでも、エスケープ/エンコーディングの説明が必要でしょう。でなければISO 27000に対応できるセキュリティガイドラインである、と胸を張って言えないでしょう。
実際のアプリケーションにおける実際の脆弱性
現実問題として、ソースコード検査を行ってSQLインジェクションに脆弱なコードの大半が
- 必要な入力バリデーションを行っていない
- 必要な識別子のエスケープを行っていない
が原因となっています。これらの脆弱性の多くは「外部からのWebアプリ診断」で簡単に検出できる状態です。つまり、簡単に攻撃者からSQLインジェクション攻撃できてしまう状態です。
入力値チェックを徹底することは、SQL注入対策に一定の効果をもつ。
”一定の効果をもつ”とし”あまり効果がない”と誤解させる文言は、ソースコード検査を行っている者の1人として許容範囲外です。
入力バリデーションが甘いアプリケーションの安全性保証は困難
入力データバリデーションが甘い/無いWebアプリケーションは、インターネットとの接続点にファイアーウォールがないネットワークと同じです。安全性保証が飛躍的に困難になります。
現在、ファイアーウォールなしでインターネット接続するネットワークは皆無と言ってよいと思います。しかし、Webアプリケーションには入力バリデーションが甘い/無いものが大半です。
ISO/CERT/MITRE/NIST/OWASP/SANSといったセキュリティガイドラインを提供している組織は当たり前のセキュリティ対策として入力バリデーションを要求しています。それも四半世紀くらい前から。
にも関わらず、セキュリティ専門家とされる人まで含め
- 入力バリデーションはセキュリティ対策ではない
- 入力バリデーションはセキュリティ対策というよりアプリ仕様である
- 入力バリデーションは内部の脆弱性を隠す対策でよくない (であればWAFも要らない)
などと、訳の分らない出鱈目な主張がまかり通っています。 (IPAも出鱈目な”入力対策”を長年啓蒙した実績があり責任は重いでしょう)
セキュリティ業者や攻撃者が得をするようなセキュリティ対策は要らないです。計らずも、だとは思いますが上記3つ誤った考え方はセキュリティ業者の得にしかならないです。
東京オリンピックでサイバー攻撃対策の必要性が増していますが、最も効果的な対策は「厳格な入力バリデーション」であることは間違いないです。これは私が勝手に思っているのではなく、CERTやMITREのセキュリティ専門家も同じ意見です。 ※ 参考: CWE/SANS TOP 25 ほぼ全てのWebアプリがマトモな入力データバリデーションを実装していないので効果は抜群でしょう。 ※ 参考1: セキュアなアプリ構造、参考2:OWASP TOP 10 A10:2017
修正提案
現在のIPAセキュアプログラミング講座のページでは「※上記以外の旧版資料については更新を行いません」と旧版セキュアプログラミング講座を更新しない旨が記載されています。しかし、今年の秋頃にはおかしな”入力対策”を修正しています。
IPAには以下の修正を提案します。
- 入力対策(入力バリデーション)を独立した対策として記載する (そもそもは”入力対策”の項目があり”出力対策”の項目がなかったので、”出力対策”を作るべきだった)
- SQLインジェクション対策を出力コンテクストを考慮した対策に修正する (出力コンテクストを考慮しない出力対策は出鱈目と言えます。下記ブログ参照)
「入力バリデーションをする」は初歩かつ基礎かつ必須の対策であることを明記すべきでしょう。入力データのバリデーションはインジェクション対策の「おまけ」ではありません。 ※ CWE-20
パラメーターのエスケープの解説が今一つな点も改善すべきです。エスケープの代わりにプリペアードクエリを勧める点には問題ないですが、エスケープを適切に紹介していないのは問題です。 ※ CWE-116
その他
ついでですが、CERT Top 10 Secure Coding Practicesの順番を変えるのは良くないです。「セキュアコーディング原則の◯番」として覚えている人には無用な混乱を生みます。また、2番目に格上げした「出力の無害化」はセキュアコーディングに於てそれほど重要視すべきモノでもないです。誰でも自由に設定できるデータが危険であることは初心者にとっても解りやすいです。(解りやすい、というより現在は多くの開発者が「セキュリティ対策は出力対策が一番の対策!」と勘違いしているケースが多いです) 元の通り、「出力の無害化」は7番目にすべきだと思います。
※ 出力時点で無効なデータを無害化しても意味がない、出力時にバリデーションで拒否しても遅すぎます。下流からのデータ処理だけ考えるセキュリティ対策ではマトモに動作するアプリ構築が遠退くばかりです。出力対策が必須であっても優先度が低い理由は明らかですが念の為。
今回は入力対策の話ではないですが、SQLインジェクション対策としても、他のインジェクション対策として「入力対策での文字エンコーディングバリデーション」は必須です。これは「入力対策」に必須事項として記載すべきしょう。つい最近でもPlayStation Networkが不正文字エンコーディングと思われるDoS攻撃を受けました。修正内容からWebサイトから不正文字エンコーディングのデータをインジェクションされたと推測できます。個人的には10年以上前から文字エンコーディングバリデーションは必須セキュリティ対策だ、と啓蒙してきましたがセキュリティ専門家とされる人の中にまで「セキュリティ対策ではない」とか「ライブラリや言語が対応する問題」などと出鱈目な主張がまかり通っています。 ※ ライブラリや言語まかせでは「フェイルファースト」にならない
”専門家”とされる人を含め、おかしなセキュリティ概念を啓蒙/対策し、ワザと脆弱なシステムを作らせるようなセキュリティ対策を放置してよいのでしょうか? IPAは「未だにおかしな主張をする”専門家”を名指しで間違いを指摘し、力ずくでも出鱈目なセキュリティ対策を駆逐する」くらいの努力をすべきではないでしょうか? 「そこまでは」と感じるかも知れませんが、CVEというシステムを使い脆弱なシステムを名指しで「脆弱だ」「問題だ」としていますよね? インジェクション対策では最も重要といえる入力対策/出力対策において、IPAは自らもおかしな入力対策/出力対策を長年啓蒙していた実績もあり、責任は重いです。
現セキュアプログラミング講座がPDFだけであることも問題です。Googleで検索すると旧セキュアプログラミング講座が普通に表示されます。通常でWebページの検索して直接参照できるようにするか、旧セキュアプログラミング講座を大幅に改訂しないとISO 27000が要求する「セキュアプログラミング」で開発者がシステム開発できないと思います。いっその事、全ての旧セキュアプログラミング講座のページに「旧セキュアプログラミング講座の内容ではセキュアプログラミングはできません」と明示した方が手っ取り早く、誤解の解消も早いのでは?
別コンテンツですが「安全なWebサイトの作り方」、このページに記載されている内容も問題が多いです。これでGDPRやNIST SP800-171の”重要な基礎的対策”だけでも対応可能でしょうか?