なぜPHPアプリにセキュリティホールが多いのか?

第46回セキュリティ対策を考える上で欠かせないコンテクスト

円滑なコミュニケーションには、共通の用語・概念が必要です。用語・概念が違うようではコミュニケーションは不可能です。

前回「バリデーションがセキュリティ対策である」ことを主題として、セキュリティ対策に対する考え方の基本について解説しました。前回の記事でセキュリティ対策とは何か理解できた方も多いと思います。しかし、まだ理解できていない方も居るようなので、セキュリティ対策についてもう少し解説します。次になぜコンテクストが重要なのか解説します。

今回も「ISO/IEC TR 13335−1 ITセキュリティマネジメントのガイドライン - 第一部:ITセキュリティの概念及びモデル」の解説になります。ISO規格ではITセキュリティ関連規格は27000シリーズに集約されますが、ITセキュリティの概念はこちらのほうがわかりやすくまとまっています。ITセキュリティの概念としては、ISO/IEC 13335-1では6つの要素(機密性、完全性、可用性、責任追跡性、真正性、信頼性)に分けていたものを、ISO/IEC 27001では3つの要素(機密性、完全性、可用性)にまとめています。責任追跡性、真正性、信頼性がITセキュリティの要素からなくなったのではなく、それぞれ機密性、完全性、可用性に集約されたと考えるべきでしょう。

ISO/IEC TR 13335-1はITセキュリティの概念・マネジメントプロセスの説明になっており、より具体的な対策や要件を詳しく定義しているISO/IEC 27000-2よりITセキュリティの全体像を理解しやすいでしょう。ISO/IEC TR 13335-1を理解してからISO/IEC 27000-2を読むとよりITセキュリティの全体像を理解しやすいと思います。

この連載はWebセキュリティ、PHPセキュリティについての連載であるので、特に明記がない限りセキュリティとはITセキュリティのことを意味します。

セキュリティ対策とは?

ITセキュリティ対策とは普遍的なもので、システムよって変わるものではありません。ISO/IEC 13335−1では「ITセキュリティ」は次の要素の定義・達成・維持に関わるすべて⁠のセキュリティだとされています。

機密性(Confidentiality)

許可されたユーザやプログラム以外に情報を非開示・使用不可にすること

完全性(Integrity)

許可されていない方法でデータの改ざん・破壊がされず、本来果たすべき機能を滞りなく実行すること

可用性(Availability)

許可されているシステムが利用可能であること

責任追跡性(Accountability)

ユーザやプログラムの動作を一意に追跡できること

真正性(Authenticity)

操作を要求しているユーザ・プログラムがそのユーザ・プログラム自身であること

信頼性(Reliability)

矛盾なく計画通りの動作と結果を確保すること

ITセキュリティ対策とはITセキュリティを守るための対策であり、上記の特性を守る対策⁠すべて⁠がセキュリティ対策です。

ISO/IEC 13335-1では保護すべき資産を選定し、その脅威、脆弱性、影響、リスク、セーフガード、残存リスク、制約事項を明らかにし、必要なセーフガードを選択し実施するよう求めています。一般にセーフガードのことをセキュリティ対策と呼ぶ場合がありますが、セーフガードはセキュリティ対策の一部です。

セキュリティ対策とセーフガード

一般に「セキュリティ対策」と言う場合、ISO/IEC 13335-1文書全体で定義されているセキュリティ対策を指す場合とISO/IEC 13335-1で用語として定義されている「セーフガード」を指す場合があります。

セーフガード(Safeguard)の定義
リスクを低減する実践、手順、又はメカニズム

プログラマやITエンジニアの視点から見れば、⁠セキュリティ対策」「セーフガード」と考えてもあまり問題がないので、⁠セーフガード」の意味で「セキュリティ対策」が使用されることが多いです。多いと言うより「セーフガード」と呼ばずに「セキュリティ対策」と言う場合がほとんどでしょう。

「セキュリティ対策」が2つの意味で利用されていることもセキュリティ対策を分かりづらくしている一因かも知れません。ITセキュリティ対策とはITセキュリティのリスク対策(セーフガード)のみではありません。ISO/IEC 13335-1ではITセキュリティ管理のモデルとして、ITセキュリティマネジメントは次のような機能を持つと記載されています[1]⁠。

  • 組織のITセキュリティの目的、戦略、及び対策の決定
  • 組織のITセキュリティ要件の決定
  • 組織内のIT資産に対する、セキュリティ上の脅威の識別及び分析
  • リスクの認識及び分析
  • 適切なセーフガードの指定
  • 組織内の情報とサービスの費用対効果に優れた方法で保護するために必要な、セーフガードの実施及び稼働の監視
  • セキュリティ意識向上プログラムの開発及び実施
  • 偶発事件の検出及び対応

(原文のまま)

これらのマネジメントプロセスすべてがITセキュリティ対策と言えます[2]⁠。⁠セーフガード」の指定・実施はセキュリティ対策の一部ですが、正確にはほかの要素もすべて含めて「ITセキュリティ対策」と言うべきです。

この記事の中では一般的な用法に従って、ITセキュリティ対策もセーフガードもセキュリティ対策としています。文意からセーフガードのことを指しているのかそうではないのかはすぐ分かると思いますが、このような用法がセキュリティ対策の意味を分かりづらくしているのかも知れません。

セーフガード(セキュリティ対策)には必要条件しか求められていない

セーフガードは「リスクを低減する実践、手順、又はメカニズム」と定義されています。この定義では「セーフガード(セキュリティ対策⁠⁠」となる対策は必要条件しか求めていません。必要なセーフガード(セキュリティ対策)は保護すべき資産やリスク評価が変わると変化しますが、セーフガード(セキュリティ対策)であるものがセーフガード(セキュリティ対策)でなくなる訳ではありません[3]⁠。

また、セーフガードはリスクを低減するだけで構いません。つまりセーフガードは完全な対策でなくても構いません。多くの場合、複数のセーフガードを組み合わせて初めて完全なセーフガードになります。個々のセーフガードはリスクを低減するだけで有効なセーフガードとなります。

例えば、プリペアードクエリはSQLインジェクション対策として有用でリスクを低減します。しかし、識別子のエスケープはできず、SQL語句が入力パラメータである場合の対策としても機能しません。文字エンコーディングのバリデーションが必要な処理系もあるでしょう。プリペアードクエリはSQLインジェクションのリスクを低減しているすぎません。エスケープとバリデーション、必要な場合は文字エンコーディングのバリデーションを組み合わせて初めて完全なセーフガード(セキュリティ対策)になります。

特定の要件にのみ必要な対策であっても、セーフガードは常にセーフガードです。例えば、SQL文を実行した場合の「責任追跡性」を達成するためには、どのプロセスやユーザがSQL文を実行したのか記録する「監査ログ」を持たなければなりません。⁠セーフガード(セキュリティ対策⁠⁠」である「監査ログ」がないアプリケーションは脆弱性を持つアプリケーションであることになります。しかし、SQL文実行の「責任追跡性」がないアプリケーションは脆弱なアプリケーションでしょうか? 多くのWebアプリは「責任追跡性」を必要としておらず(リスクを許容しており⁠⁠、⁠監査ログ」は保護すべき資産のセキュリティ対策として必要ないセーフガード(セキュリティ対策⁠⁠」であるだけです。

「監査ログ」機能は明確にセーフガード(セキュリティ対策)です。例に挙げた多くのWebアプリのような場合に「セーフガード(セキュリティ対策)でない」と定義を変更してしまうようでは混乱するだけです。ですから「セーフガード(セキュリティ対策⁠⁠」となる対策には必要条件しか必要ありません。ISO規格のガイドラインではセキュリティ維持に役立つセーフガード(セキュリティ対策)はすべてセーフガード(セキュリティ対策)であり、守るべき資産やリスクによって⁠必要な⁠セーフガード(セキュリティ対策)を選ぶようになっています。ある対策がセーフガード(セキュリティ対策)になったり、ならなかったりするような定義ではありません。

同様の考え方は医療でも利用されています。例えば、健康対策です。⁠運動」は健康対策として広く薦められており、実際多くの方にとって運動は健康維持に有用です。しかし、心臓や血管に問題がある方には健康対策として幅広い分野で役立つ「運動」が命に関わる問題となり得ます。このような場合には健康にとって有害と言える「運動」ですが、有害な場合があっても「運動は健康対策ではない」とは言いません。

健康維持に役立つ対策はすべて健康対策であり、症状や状態によって必要な健康対策が変わるだけです。

医者が健康対策であるものを、ある時は「健康対策⁠⁠、ある時は「健康対策ではない」と説明すると患者が混乱するだけです。⁠運動」が逆にリスクを増やす場合、その患者に対して必要な対策ではないこと、不要な対策であることを説明することあっても、広く一般に「運動は健康対策ではない」などと言う医者は居ないでしょう。ITセキュリティのスペシャリストも医師が健康対策を考える場合と同じように、セーフガード(セキュリティ対策)を考えています。

セキュリティとリスクとセキュリティ対策の関係

セキュリティとリスク(脆弱性⁠⁠、セーフガード(セキュリティ対策)は次の図のような関係になります[4]⁠。分かりやすいようにかなり簡略化しています。

図1 セキュリティと脆弱性とセキュリティ対策[5]
図1 セキュリティと脆弱性とセキュリティ対策

ITセキュリティの専門家であればこの関係をよく理解しています。教科書的なセキュリティ入門書では、リスク分析で必要なセキュリティとリスクを洗い出し、回避すべきリスクと許容すべきリスク(脆弱性)を識別し、回避すべきリスク(脆弱性)に対してセキュリティ対策(セーフガード・安全対策)を適用するように解説してることが多いと思います。このプロセスはセキュリティとセキュリティ対策を正しく理解する上で重要です。

これから説明する3つの図は、例示するために簡略化した図です。

必要なセキュリティとして「機密性」が必要な場合、機密性に関連する脆弱性を識別し、識別した脆弱性のためのセキュリティ対策を選びます。

図2 機密性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係
図2 機密性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係

この場合、機密性→インジェクション→入力バリデーション、出力エスケープ、出力ヘルパーの利用という関係を持つことになります(既に説明したとおり、分かりやすいよう、図と関係は簡略化しています⁠⁠。

セキュリティ対策として真正性が必要な場合は次の図のようになります。Webアプリケーションに「真正性」が求められる場合、CSRFがリスクとなり、セキュリティトークンの利用が対策になります。

図3 真正性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係
図3 真正性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係

真正性→CSRF→セキュリティトークン、という関係を持つことになります。

「可用性」が求められる場合は、サービス不能がリスクとなり、処理・仕様の簡略化が対策の1つとなります。

図4 可用性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係
図4 可用性が必要なシステムにおけるセキュリティと脆弱性とセキュリティ対策の関係

可用性→サービス不能→処理・仕様の簡略化、という関係を持つことになります。

セキュリティ・リスク(脆弱性⁠⁠・セキュリティ対策(セーフガード)の要素が変わることはありません。変化するのはどのようなセキュリティを求め、どのようなリスク(脆弱性)に対処または受け入れ、それらに対して必要なセキュリティ対策(セーフガード)を選択するかが異なるだけです。システムによって必要または認識するセキュリティ・リスク(脆弱性⁠⁠・セキュリティ対策(セーフガード)が変わるだけで、セキュリティ・脆弱性・セキュリティ対策自体が変化する訳ではありません。

これ以降、⁠セキュリティ対策(セーフガード⁠⁠」と書かず単に「セキュリティ対策」と書きます。

環境と共に変わるセキュリティ対策の常識

セキュリティ対策の定義が変わらない限り、ある場面でセキュリティ対策とされるものがほかの場面でもセキュリティ対策であることに変わりません。しかし、セキュリティ対策の常識が変化することはよくあります。進化が非常に速いコンピュータの世界では、数十年前のセキュリティ対策の常識が完全に非常識となっている場合もあります。しかし、特定のケースで非常識になってしまったセキュリティ対策でも⁠セキュリティ対策でなくなる⁠ことはありません。

例えば、25年ほど前の1980年代半ばまで、銀行のキャッシュカードはカード自体の磁気データに暗証番号が記録されていました。今であれば少なくともハッシュ化したデータを利用すると思いますが、ハッシュすらも利用されていません。暗証番号がそのまま記録されており、カードリーダーさえあれば簡単に読み取れました。今のコンピュータの環境で考えればとんでもなく脆弱な設計だと言えます。

しかし、ATMが開発された当時は大型コンピュータであっても今のパソコンと比べると処理速度も通信速度も格段に劣る貧弱なものでした。このため、処理速度からもネットワーク帯域からもハッシュ化したデータのやり取りはもちろん、暗証番号の照合でさえ許されませんでした。負荷集中によるサービス不能状態を回避するセキュリティ対策として処理・仕様の簡略化を行ったのだと考えられます。今のコンピュータの性能とネットワーク環境ではあり得ないようなセキュリティ対策ですが、当時としては妥当なセキュリティ対策であったと言えます。

今のATMシステムでは「暗証番号をカードに記録する対策は無効なセキュリティ対策」であることに異論はないと思います。こんな馬鹿馬鹿しいセキュリティ対策をしているようなシステムは今はないはずだと思われるかも知れません。しかし、現在のWebシステムでもこれと同レベルの対策を採用しているサイトが多く存在します。SSL通信に対応していないサービスがその一例です。

通信の秘密が担保できない回線、例えば公衆Wi-Fiなどでは、SSL通信を用いないと通信の機密性は保てません。Wi-Fi基地局の設置者はセッションIDを含めた機密情報を簡単に盗聴できます。SSLを用いないサービスは脆弱なサービスであると言えます。

しかし、DoSのリスクを回避するためSSLを使わないサービス仕様も現状ではまだまだ十分有効なセキュリティ対策です。SSL通信による負荷にシステムが耐えられないため、暗号化をしないHTTP通信を利用するサービスは多くあるでしょう[6]⁠。最近、GoogleがすべてのサービスにSSL通信を使うようになってから、サイト全体・サービス全体にSSL通信を使うケースも増えましたが、まだ当たり前になっているとは言えない状況です。

20年後の新人ITエンジニアに「昔はSSL通信を行わずにWebサイトを構築するのが当たり前だった」と紹介すると皆さんが「昔のキャッシュカードの暗証番号」の話を聞いたときと同じ感覚を感じると思います。20年も経つと処理速度や記憶容量の制限がなくなり、⁠処理・仕様の簡略化」は必要なセキュリティ対策として残っていないかも知れませんが、アプリケーションはハードウェアの進化と共に肥大化してきたのでどうなっているかは分かりません。

どの対策がセキュリティ対策でどの対策がセキュリティ対策でないか議論することは無意味であることがこの例からも分かると思います。セキュリティ対策を議論するのであれば、実際の制約や要件において有用であるか有用でないかの議論をしなければ意味がありません。

「セキュリティ対策ではない」の本当の意味

セキュリティ対策は完全でないことも多く、具体的なシステムにセキュリティ対策を行う場合、ITセキュリティの定義からはセキュリティ対策であるのに「セキュリティ対策ではない」と言われることがよくあります。これも初心者が「セキュリティ対策は難しい」と感じてしまう主な原因の1つではないでしょうか?

セキュリティ対策であるのに「セキュリティ対策ではない」と言う場合、言葉の一部が省略されています。

  • (有効な)セキュリティ対策ではない
  • (必要な)セキュリティ対策ではない
  • (十分な)セキュリティ対策ではない
  • (完全な)セキュリティ対策ではない
  • (効果的な)セキュリティ対策ではない

もしかすると「セキュリティ対策」という用語自体が日本人には曖昧であるため直感的に分りづらいのかも知れません。ISO/IEC 13335-1では「セキュリティ対策」という用語ではなくセーフガードを用いています。JISではカタカナで「セーフガード」をそのまま用いていますが、日本語に訳すとすると「安全対策」が妥当だと思います。こちらのほうが分かりやすいかも知れません。

  • (有効な)安全対策ではない
  • (必要な)安全対策ではない
  • (十分な)安全対策ではない
  • (完全な)安全対策ではない
  • (効果的な)安全対策ではない

どうでしょうか?

  • 「HTTP Basic認証はセキュリティ対策ではない
  • 「セキュリティ処理・仕様の簡略化はセキュリティ対策ではない

にあまり違和感を覚えない方でも

  • 「HTTP Basic認証は安全対策ではない
  • 「セキュリティ処理・仕様の簡略化は安全対策ではない

と書くと違和感がわかりやすいかも知れません。

  • 「HTTP Basic認証は(経路の安全が確保できない場合は信頼できる)安全対策ではない
  • 「セキュリティ処理・仕様の簡略化は(よほどの事情がない限り選択すべき)安全対策ではない

と表現するとわかりやすいのではないでしょうか?

円滑なコミュニケーションには共通の用語・概念が欠かせません。本来は〇〇なセキュリティ対策ではない」という意味で使われるべきところで単に「セキュリティ対策ではない」と言われていることには注意が必要です。明示した上で独自の用語・概念を用いることまで止めるべきだとは考えていませんが、基本的には標準規格・業界標準とされる用語・概念を共通の用語・概念とすべきでしょう(ISO 13335-1は先進国で構成されるOECDでの合意に基づき作られた国際基準です。共通の用語・概念とするには十分です⁠⁠。

セキュリティ対策を特別扱いする理由

前回の記事でセキュリティ対策だけ特別扱いする理由を解説しています。簡単におさらいをします。

図5 バグと脆弱性とセキュリティホールの関係
図5 バグと脆弱性とセキュリティホールの関係

脆弱性やセキュリティホールはアプリケーション要求仕様によって大きくなったり、小さくなったりしますが、必ずバグ対策よりセキュリティ対策のほうが小さくなります。

ソフトウェアは作ったようにしか動作しません。思ったように動作するソフトウェアを作る作業は非常に難しい作業です。その難しい作業の中で、特に重要な部分で問題が発生しないように対策するものがセキュリティ対策です。セキュリティ対策はバグ対策のサブセットとなるのでアプリケーション構築に必要とされる最低限の前提知識として区別するために特別に扱います。

セキュリティ対策とコンテクスト

必要なセキュリティ対策はコンテクストによって変化します。先ほど紹介したキャッシュカードの例がよい例です。システムの性能上の制限からキャッシュカードの磁気テープに暗号化されていない暗証番号を組み込こんだセキュリティ対策は、現在では有効なセキュリティ対策とは言えません。しかし、現在と環境(コンテクスト)が異なった当時は十分に妥当なセキュリティ対策でした[7]⁠。

特定システムのセキュリティ対策を考える場合にはコンテクストが非常に重要です。コンテクストが変わると必要なセキュリティ対策が変化するからです。キャッシュカードの例のようにコンテクストが変わると「⁠⁠必要な)セキュリティ対策」であった対策が「⁠⁠不必要な)セキュリティ対策」に変わってしまう場合もあります。

セキュリティ対策のコンテクスト

Webアプリのセキュリティ対策のコンテクストも多種多様です。必要となるセキュリティ対策も多種多用です。いくつか例を挙げてみます。

アプリケーションの種別
プロトタイププロトタイプではセキュリティ要件はまったくないことが多い
情報公開型アプリ公開されている情報の改ざんを防げれば十分である場合が多い
情報収集型アプリ適切な権限を持ったユーザが情報を登録・編集・削除できるように制限する
金融関連アプリ 機密性、完全性、可用性を確保。すべての処理の監査ログを保存する

アプリケーションの種別によってセキュリティ要件は大きく異なります。アプリケーションが必要とするセキュリティは種別によってまったく違うことに説明は必要ないと思います。

開発の種別
新規開発プロジェクト言語、ライブラリ、フレームワークなどのシステムの仕様の自由度が高い
再構築プロジェクト既存資産を有効活用する場合、システム仕様の自由度が低くなる
既存プロジェクトメンテナンスフェーズの場合、システム仕様の自由度はほぼない

開発の種別が異なると選択できるセキュリティ対策が異なります。条件がない新規開発では自由度が高くなりますが、既存プロジェクトのメンテナンス、特にセキュリティ問題の修正のみ、のような場合は自由度はほとんどありません。

開発プロジェクトの場合、予算も大きな要素です。セキュリティ標準では開発者などのセキュリティ対策のトレーニングや専門家によるソースコード監査を要求していますが、トレーニングやソースコード監査を行っていないプロジェクトが多くあります。

開発環境
言語言語によって必要なセキュリティ対策が異なる場合がある
ライブラリ同じ目的のライブラリでもセキュリティ対策が異なったり、バージョンによって異なるセキュリティ対策が必要な場合がある
フレームワークフレームワークが異なっても共通している部分もあるが、セキュリティ対策が大きく異なる場合もある

開発環境によってもセキュリティ対策が変わってきます。C/C++でアプリケーションを作る場合とPHPやRubyなどで作る場合とでは必要なセキュリティ対策はかなり異なります。ライブラリやフレームワークが異なるとライブラリ、フレームワーフを安全に利用するために必要なセキュリティ知識は異なります。

役割
開発者主にプログラムの作成のセキュリティを担当する
運用者主にシステム環境、運用環境のセキュリティを担当する
利用者自らの利用するシステム環境(ブラウザやプラグイン、OS)と利用方法のセキュリティを担当する

役割が異なると選択肢として考慮すべきセキュリティ対策がまったく異なります。運用者はWAF(Webアプリケーションファイアーウォール)やIPS(侵入防止システム)をセキュリティ対策として検討します。しかし、ソースコードを設計、記述する開発者は通常、WAFやIPSが存在することを前提にアプリケーションは作りません。DoSなどを除けばWAFやIPSが無くても正常に動作するよう構築します[8]⁠。

デザインパターンとしてのセキュリティ対策

セキュリティ対策を、ベストプラクティスを実践するためのデザインパターンのように捉えている方も多いのではないでしょうか? 実際、セキュリティ対策をデザインパターンのように捉えることも可能です。この考え方は新規開発の場合には適用しやすいですが、既存のシステムに適用しづらかったり、できなかったりします。この意味では欠陥がある方法でもあります。

デザインパターンの欠点

  • デザインパターンは新規プロジェクトに向いているが、セキュリティ対策は新規プロジェクト以外にも必要

  • 想定しているデザインパターンを利用していてセキュリティ問題があった場合の修正は可能だが、想定しているパターンを利用していない場合、パターンが適用できない場合がある

  • デザインパターンの要素自体がアプリケーションやライブラリで実装されている場合、その実装が正しいか確認するための情報が提供できていない場合がある

  • 元々デザインパターンはベストプラクティスとなるパターンを定義するものであるため、セキュリティ対策の文書であってもベストプラクティスのみ解説している場合がある
  • 多くのコンテクストに対応しようとするとセキュリティ対策の解説が煩雑になってしまい、分かりづらくなる場合がある
  • セキュリティ対策の作業は既に構築済みまたはレガシーアプリケーションのメンテナンスである場合も多く、デザインパターンとしてセキュリティ対策を定義すると漏れが発生したり、既存コードのチェックの指針にならない場合があります。また、多様なコンテクストに対して十分なパターンを定義せず、不完全な解説になってしまう場合があります。

    セキュリティ対策をデザインパターンとしてとらえて解説している例は、IPAの安全なSQLの呼び出し方です。この文書ではエスケープ処理でSQL文を組み立てた場合に発生するSQLインジェクションを例にあげて、SQLインジェクションの原理を解説しています。SQLインジェクション対策としてJDBC型のAPIを持つプリペアードクエリとプレイスホルダの例を紹介しています。このアプローチには次の問題点があります。

    • JDBC型のAPIを持たないシステムやライブラリのことが考慮されていない

    • JDBC型のAPIでは定義されていないが、必要なセキュリティ対策の解説が省略されている

    • JDBC型のAPIを持っていてコードもある場合、そのコードの実装が正しいか確認する方法の解説が省略されている

    利用されることが多いSQLデータベースには、プリペアードクエリが使えるようなったのが比較的最近のものもあります。データベースではサポートしていても、アクセス用のライブラリが対応していなかったものも多くあります。まだまだプリペアードクエリを利用しないアプリケーション/コードは数多く存在します。このような場合、JDBC型のAPIを想定したパターンは役に立ちません。実際、PHPの場合でJDBC型のAPIでJDBCと同等の動作をするライブラリは少なく、PEARのMDB2くらいのようです。

    JDBC型のAPIを持っていても、識別子(テーブルやフィールド名)やSQL句(LIMITやORDER)のセキュリティ対策は別途必要です。識別子やSQL句がパラメータに含まれる可能性がある場合、エスケープやバリデーションによるセキュリティ対策が必要になります。

    JDBC型のAPIを持つようなライブラリをアプリケーションやサードパーティ製ライブラリで実装している場合、その実装自体が適切な実装であるか確認する必要があります。JDBC型APIの利用方法を解説するだけでは実装が適切であるか確認する方法の説明が抜けてしまいます。

    特定の脆弱性に対して、必ずしも1つのセキュリティ対策で完全な対策にならなければいけないわけではありません。しかし、SQLインジェクション脆弱性は出力時の対策で完全なセキュリティ対策が実施できる脆弱性です。セキュリティ対策の解説としては完全な対策となる解説のほうが好ましいと考えられます。

    原理・原則のセキュリティ対策

    セキュリティ対策は多くのコンテクストに対応した対策であるほうが好ましいです。多くのコンテクストに対応するためには、セキュリティ対策の原理や原則を定義し、それを適用し、必要な場合には例外や補足を定義するほうが解りやすい場合が多いです。

    セキュリティ対策で最も重要な対策は入力時と出力時の対策です。例えば、整形テキスト出力で脆弱性が発生する原理とセキュリティ対策の原則は以下の通りです。

    出力時にセキュリティ脆弱性が発生する原理

    • 出力を受け入れるプログラムの入力仕様に従ったデータを出力しないため、出力先のプログラムが誤作動を起こす

    出力時のセキュリティ対策の原則

    • エスケープ可能なパラメータはすべてエスケープ処理する
    • ヘルパー関数などが利用できる場合は利用する
    • エスケープもヘルパー関数も利用できない場合はバリデーションする

    補足

    • 出力先の入力仕様、エスケープ仕様、ヘルパー関数などの仕様を正しく把握すること。出力先の入力仕様には最大データ長、文字エンコーディングの取り扱い、入力のタイミング[9]などが含まれることに注意する。

    この原則はほとんどの出力先に利用可能です。SQLインジェクション対策はもちろんJavaScriptインジェクション対策やXMLインジェクション対策などにも適用できます。

    原理・原則だけでは具体的に特定のコンテクストに対してどのようなセキュリティ対策を行えばよいのかあまり明確ではありません。しかし、脆弱性の原理とセキュリティ対策の原則を説明した上で特定のコンテクストに対応したセキュリティ対策例を解説すると、ほかのコンテクストにおいても漏れのないセキュリティ対策実施の手助けになるでしょう。

    幅広いコンテクストに対応できるのが原理・原則に基づくセキュリティ対策ですが、それだけでは具体性に欠けるところがこのアプローチの欠点です。

    IPAの安全なSQLの呼び出し方を修正するなら、JDBC型のAPIの解説の次に、エスケープとバリデーションによるセキュリティ対策を追記します。こうすれば、必要なセキュリティ対策の漏れもなくなり、APIを独自実装している場合の確認も行えるようになります。影響を受けるアプリケーショは多くありませんが、コネクションプーリング(PHPの永続的データベース接続など)とプリペアードクエリを一緒に使った場合、データベースサーバのリソースが枯渇する可能性があることも触れたほうがよいでしょう。データベースが提供するネイティブのプリペアードクエリを利用していれば、プリペアードクエリがリソース枯渇の原因になることを理解しやすく気がつく方も多いでしょう。セキュリティ対策を行ったために別のセキュリティ問題が発生することはよくあることです。開発者が気づかない場合も多いので補足しておくとよいと思います。

    ヘルパー関数やプリペアードクエリ型APIなど出力先の入力仕様を抽象化した、いわゆるモダンなコーディングスタイルを否定しているわけではありません。特に初心者にはこれらのAPIの利用を勧めることはセキュリティ対策として効果的であり、新規プロジェクトなどでは積極的に採用すべきだと考えています。同時に、筆者はより完全なセキュリティ対策を実施できるようになるため、原理や原則を理解した上でセキュリティ対策を行うべきであると考えています。例えば、出力に関しては「エスケープ処理を行う」が原則であり、まずエスケープ処理を知りましょうと提案しています。エスケープ処理を知ることが、出力先の入力仕様を知ることになるからです。入力仕様を正しく知れば、確実に安全な出力とはどのような出力なのか理解でき、開発者が独自に出力先の抽象化を行うような場合でも正しい処理を行えるようになります。

    セキュリティ対策は利用しているDBMSサーバやライブラリ、フレームワークによって異なります。特定の環境に対するセキュリティ対策であればデザインパターン的なセキュリティ対策が効果的です。特定の環境を想定しないセキュリティ対策であれば原理・原則を理解するセキュリティ対策が効果的です。どちらが優れているというものではなく、デザインパターン的なアプローチ、原理・原則に基づくアプローチは適材適所で利用すべきアプローチです。

    まとめ

    セキュリティ対策(セーフガード)は必要条件と十分条件の両方を満たしていなければならない、とお考えの方も居たのではないでしょうか? セキュリティ対策には必要条件しか求められていません。何らかの形でセキュリティに役立つ対策であれば何でもセキュリティ対策です。セキュリティ対策の十分条件は実際のプロジェクトにおいて要求される条件です。

    必要条件しか求められていないので、セキュリティ対策(セーフガード)はいつでもセキュリティ対策です。 特定のシステムに適用する場合は⁠必要な⁠セキュリティ対策が要件によって変化するだけで、セキュリティ対策自体は、セキュリティ対策の定義が変わらないかぎり、普遍です。ISO/IEC 13335-1やISO/IEC 27001-2では必要な対策を「選択」するようにと記述されています。標準規格ではこのように必要条件だけで定義し、実際に実施する場合には定義された用語に制限や条件を付けて利用することはよくあります。このように定義した方がブレがない定義になるので当然です[10]⁠。

    実際にセキュリティ対策を実施する場合、十分なセキュリティを確保する必要があります。十分なセキュリティを確保するためにはコンテクストが重要です。セキュリティ規格やセキュリティの教科書ではリスク分析を行うように求めています。リスク分析とはコンテクストを理解するための分析でもあります。多くのリスクはリスクの存在を知っていて初めて対策できます。未知のセキュリティ脅威に対する対策はあまり多くありません。

    セキュリティ対策をデザインパターンとして定義する方法は、特に新規プロジェクトのセキュリティ対策指針として定義すると非常に効果的です。しかし、セキュリティ対策が必要なプロジェクトは新規プロジェクトばかりではありません。既存のソフトウェア資産に対するセキュリティ対策はその資産に適応したセキュリティ対策の指針が必要です。

    セキュリティ対策を原理・原則から考えて対策する方法は一見遠回りに見えます。しかし、十分なセキュリティ対策を行うためには原理・原則から考えるほうが近道である場合も多いです。特に、仕様書に記載された内容をコードにするだけのプログラマから仕様まで考えられるプログラマになるためには、原理・原則から理解したほうが近道です。

    一つ一つのセキュリティ対策は難しいものではありません。セキュリティ対策がとらえどころがなく難しく感じられる原因の一つは、用語の定義が曖昧だからではないでしょうか? セキュリティ対策(セーフガード)とはリスクを軽減する対策すべてである、と理解すれば、より簡単に感じられるのではないでしょうか?

    おすすめ記事

    記事・ニュース一覧