ユーザーや開発者はIPA・専門家の責任にしてWebアプリなどに”本物”のセキュアコーディングを適用する方がよい

(Last Updated On: )

非エンジニアのユーザーに現在のほぼ全てのWebサーバーは送信されてくるデータが妥当かどうか確認していない、と説明すると驚きます、「そんな仕組みでマトモに動くソフトウェアが作れるのか?」と。当然の疑問でしょう。

実際、コンピュータサイエンス・システムエンジニアリングの世界では一貫して入力データの妥当性検証を重要なセキュリティ対策として実装するように求めています。

現在のISO 27000ではセキュアプログラミング技術の採用を要求しています。セキュアプログラミングで最も重要な事は入力データバリデーションです。2013年にISO 27000が改定されるまで、入力データバリデーションだけは具体的な仕様が解説されていました。2013年の改定で普及したので「セキュアプログラミングを採用する」と簡易にされました。(ハンドブックではないJIS Q 27000:2014の冒頭の改定の経緯解説に書かれています)

安全(=意図通り)に動作する仕組みはコンピュータサイエンス・システムエンジニアリングの世界では60年代、70年代に活発に研究されており、その成果の一つに「契約プログラミング・契約による設計」(以下、契約プログラミング)があります。契約プログラミングは

  • 入力データのバリデーション
  • 状態のバリデーション
  • 出力データのバリデーション

を徹底して安全なソフトウェアの実装をサポートする仕組みです。80年代には契約プログラミングをサポートする機能持った最初の言語(Eiffel)が開発されています。契約プログラミングの考え方は非常にシンプルですが強力です。このため契約プログラミングで最も効果が高い入力データのバリデーションを徹底して行える仕組みを提供しているプログラミング言語がほとんどです。

契約プログラミングの有用性を正しく理解するには形式的検証(Formal Verification)を理解するのが早道です。基本は簡単です。形式的検証には

  • 総当り方式の検証
  • 論理的な検証

の2種類があります。ここで重要なのは総当り方式の検証です。

総当り方式の検証は名前の通り「あり得る状態(入力及び内部状態)」全てを総当りして正しく動作する事を検証する方法です。容易に予測できるように「あり得る状態」が多すぎると総当りの試行回数が多くなりすぎてどんなに速いコンピューターを使っても全て状態を試す総当りができなくなります。この為、総当り方式の検証では「あり得る状態」(≒入力データ)を厳格に狭め、できる限り少ない状態(≒できる限り少ない入力パターン)になるようにしてから検証します。

そもそも、コンピューターでも人間でも、計算できないモノをデータとして与えられても計算できません。そういった出鱈目なデータは出来る限り早い段階で排除しないと、より安全(=意図通りに動作)、より効率的(=効率的に実行&実装&テスト)にソフトウェアは作れません。

本物のセキュアコーディングは上記のようなコンピューターサイエンス・システムエンジニアリングの成果を踏まえて考案、定義されています。

なぜWebアプリではコンピューターサイエンス・システムエンジニアリングの成果が適用されていないのか?

これには2つの理由があります。

  • Webシステムの爆発的増加とシステム開発者の分断
  • システムエンジニアリングを無視した「独自概念のセキュリティ」

Webシステムの爆発的増加とシステム開発者の分断

Webアプリケーションもクライアントサーバー型のネットワークアプリケーションの一つです。通信に汎用テキスト型プロトコルであるHTTPを使っているだけで、それ以前のクライアントサーバー型のネットワークアプリケーションと基本構造は同じです。

Webシステム以前のクライアントサーバー型のネットワークアプリケーションではプロトコルレベルでのデータバリデーションが厳格に行われていました。それを容易にする為にインターフェースを定義する言語(IDL)が作られ、その仕組みで作ったネットワークアプリケーションはアプリケーションプロトコルレイヤー(アプリ専用のプロトコル)で入力データバリデーションが行われ、

  • データの長さ
  • データ型
  • 形式
  • 数値データの妥当性
  • プロトコルとしてのデータ整合性
  • パラメーターの過不足

といった条件は厳格にバリデーションされていました。その専用プロトコル上でプログラミングするアプリケーションプログラマーは「基本的な入力データバリデーションは既に行われている事」を前提にプログラミングできました。(CORBAなどと異なり、ftpやsmtpといったインターネットの古典的プログラムはこういった構造ではなく、とにかく動けばよい、といった作り方で入力データバリデーションはいい加減でした)

そこにWebシステムが登場します。最初のWebシステムはクライアント(ブラウザ)がリクエストしたら、サーバーはリクエストされた保存済みHTMLテキスト(と画像などのリソース)を返すだけしたが、CGI(Common Gateway Interface – Webサーバーがプログラムを利用してレスポンスを返す仕組み)が開発されるとWebアプリケーションが爆発的に利用されるようになります。

Webシステムからネットワークアプリケーションのプログラミングを始めた開発者が大量に生まれました。ここで分断が起きます。Webシステムは汎用のテキストプロトコルであるHTTPとCGIを使って”専用プロトコルなし”でプログラミングできます。それ以前のクライアントサーバーシステム開発では入力データバリデーションの責任は「プロトコル開発者」でしたが、Webシステムでは入力データバリデーションの責任は「アプリケーション開発者」になりました。

クライアント(Webブラウザ)から送られてくるデータが妥当(=サーバープログラムで処理可能なデータ)である限りWebアプリケーションは意図通りに動作します。例えば、数値データにSQLやJavaScriptを含むデータは送られず、普通は妥当なデータしか送ってきません。このため悪意のあるクライアントからの不正なデータ送信を全く考慮しないでWebシステムを作ることが一般化してしまいました。

システムエンジニアリングを無視した「独自概念のセキュリティ」

Webアプリが一般化した頃には情報システムのセキュリティ概念はエンジニアリング的に標準化(ISO 17799, 13335)が行われていました。

しかし、その頃には悪意のあるクライアントからの不正なデータ送信を全く考慮しないでWebシステムを作ることが一般化(=エンジニアリング的にセキュアでないアプリが一般化)していました。

状況を更に悪くさせる状況もありました。今の開発者とは異なり昔の開発者は貧弱なコンピューターリソースに適応するために1命令を削減することに血道を上げた開発をしていました。出来る限り効率化する、というベストプラクティスがセキュリティ対策のコンテクストではアンチプラクティスになります。セキュリティ対策は「多層・多重」で防御するのがベストプラクティスですが、当時の開発は「不必要・重複した操作は出来る限り徹底して排除」でした。

情報システムセキュリティを理解していたコンピューターサイエンティストもシステムエンジニアも、まず最初に入力データバリデーションをしなさい、とアドバイスしたのですが「不必要・重複した操作は出来る限り徹底して排除」という習慣から「バリデーションしたデータは信用できるので追加対策は無駄・不必要」と考えてしまいます。

そもそも、悪意のあるクライアントからの不正なデータ送信を全く考慮しないWebシステムだったので不完全な入力データバリデーションだけしても穴だらけで攻撃者からは攻撃し放題になります。

そこで応急措置として「フェイルセーフ対策の徹底」が提唱されるようになります。デフォルトで安全に出力する(=出鱈目なデータだろうが、とにかく出力先に対して無害な形にして出力する)フェイルセーフ対策が実装されるようになります。

Webページの出力時に自動的に全てHTMLエスケープ処理するテンプレートシステム、SQL文出力時に自動的にクエリパラメーターを分離して(=安全)に出力するプリペア文の利用といった対策が提唱され効果を上げます。悪意のあるクライアントからの不正なデータ送信を全く考慮しないでWebシステムだったので効果は覿面でした。

その結果

  • 入力データバリデーションはセキュリティ対策として効果が低い(”一部の専門家”はセキュリティ対策ではない、とさえ主張)
  • フェイルセーフ対策で対策するのが効率的(「不必要・重複した操作は出来る限り徹底して排除」の習慣とも適合)

と認識し

  • 不正操作を最終的に防止する対策(=フェイルセーフ対策)がセキュリティ対策

とエンジニアリング的に標準化されたセキュリティ概念とは異なるモノがソフトウェアのセキュリティ対策だと誤認されるようになってしまいました。

日本の遅れたITセキュリティ事情の原因はIPA

一般の方が想像する通りエンジニアリング的なセキュリティ対策では入力データバリデーションは必須かつ最重要対策です。しかし、その入力データバリデーションに対するIPAの解説は出鱈目でした。

2015年頃にIPAの「セキュアプログラミング講座」の入力対策と出力対策は「入力と出力があべこべな上に出鱈目」と指摘し改修する旨の返答をもらいました。現在の「セキュアプログラミング講座」では入力データバリデーションはセキュアコーディングの第1原則としています。

こうなれば時間と共に問題は解決するだろう、と思っていたら

といった、エンジニアリング的なセキュリティ対策を知っている者からすると「何を言っているんだ?」と思える解説が行われています。

不思議に思っていたらJVN(これもIPA管理下)のCWE-20(不十分な入力確認)の英訳が出鱈目でした。

JVNが翻訳し改悪したCWE-20の日本語訳を見れば

  • 入力バリデーションにエスケープやフィルタリングが含まれる

といったおかしな曲解をしても仕方ないかも知れません。(専門家であれば、原文や他のガイドラインを見て間違えないはずですが…)

更にIPAの「安全なWebアプリの作り方」は今でもセキュアコーディングを全く無視した内容のままで、エンジニアリング的にセキュアな内容になっていません。2016年頃に「セキュアプログラミング講座」を改定して、セキュアコーディング原則、を啓蒙しているにも関わらずにです。

IPAは「セキュアプログラミング技術の採用」を要求するISO 27000を啓蒙する立場でもあります。現状のJVNのCWE-20解説や安全なWebアプリの作り方が、ISO 27000の要求する「セキュアプログラミング技術」ではないです。(IPAは小さな組織ではないので、部署の沢山あり整合性が取れない場合があっても仕方ないでしょう。しかし、セキュアコーディング原則の最初の一歩から間違っている出鱈目なガイドラインを公開するのは大問題です)

ユーザーや開発者はIPA・専門家の責任にしてWebアプリなどにセキュアコーディングを適用する方がよい

ソフトウェアセキュリティ対策として最も重要とされている対策を実装しないで問題が起きた場合、システム運営者や開発者は非常に苦しい立場に置かれます。裁判所などなら巨額の損害賠償責任は仕方ないと判断される可能性も高いです。

しかし、今ならまだIPAが出鱈目なセキュリティガイドラインを公開中です。もしセキュアコーディング原則1番目の入力データバリデーションを正しく実装していなくても、IPAと専門家の責任してしまえます。エスケープでもフィルタリングでも入力バリデーションだとしているのですから。

既にCWE-20解説の問題はJVNには指摘済みです。IPAのセキュアコーディングを無視した「安全なWebアプリの作り方」の問題も指摘するつもりです。あまり時間は残っていないかも知れないので早めに対策されることをお勧めします。形式的検証やセキュアコーディングを採用・適用している組織は粛々とやっています。形式的検証でかなり高度な検証をしている開発会社もありますが、自社の強みをわざわざ教えないのが普通です。

まず最初にすべきことは?

CWE-20を管理しているMITREが2011年版CWE/SANS Top 25でセキュアコーディング原則1の入力バリデーションを詳しく解説しています。セキュアコーディング原則1はこれでOKです。

US CERTがセキュアコーディング原則(CERT Secure Coding Practices)を公開していますが、今はIPAもセキュアプログラミング講座で日本語訳して公開しています。CWE-20でも順序を変えて余計な事をしていますが、残念ながらIPA版のセキュアコーディング原則も余計なお世話で順序が変わっています。IPA版の2番目の原則は「出力の無害化」ですが、CERT版では出力の無害化は7番目です。”全ての出力は無害化すべし”とした上でCERT版で出力の無害化の順位が低い理由は「当たり前に無害化すべき出力データは無害化されているはず。本来は出力の無害化が不必要なデータは上流のバリデーションなどで排除されているべきであり、フェイルセーフ対策である出力の無害化に”だけ”に頼るべきではない。」と考えているからだと思われます。

※ 動画が見つかりませんが確かCERT20周年記念(?)の講演でも所長が質疑応答でホワイトリスト型の厳格なバリデーションの重要性を強調していました。

投稿者: yohgaki