月: 2018年3月

SQLクエリと識別子エスケープの話

Facebookでこんなやり取りをしました。元々公開設定で投稿した物で、議論させて頂いた浅川さんにも「ブログOK」と許可も頂いたので、そのやり取りの部分だけを紹介します。

テーマは「SQLクエリと識別子エスケープ」です。

とあるブログの結論として

“「安全な静的SQLの発行方法」を開発者に啓蒙すればいいだけだ。つまり

  • プリペアドクエリでSQL発行は行うこと
    この場合変数のバインドは必ずプレースホルダを用いること。

SQL文の文字列操作は禁止であり、これほどシンプルなことも無いだろう”

と書かれていました。しかし、私はこの意見に対して

実践的なSQLクエリを書いたことが全くない開発者なのでしょう??
ソートカラム、抽出カラムを指定するSQLクエリでは「識別子(カラム名)が変数」になります。
初歩的なSQLクエリですが”自分が書いたことないから”といって一般的ではないと勘違いしています。行のソート順、抽出カラムを指定するSQLクエリは業務アプリでは”一般的”です。当たり前ですが。

こうやってベストプラクティスもどきのアンチプラクティスが使われて、喜ぶのはサイバー犯罪者とセキュリティ業者だけですよ。

とコメントしました。SQLのテーブルやジョイン結果を「表」として表示した際に、任意のカラムのソート順を指定するUIは、自分で作ったことが無かったとしても、ごく一般的だと分かると思うのですが・・・

もっと読む

hash_hkdf()でわざわざバイナリキー/バイナリSaltを使うことに意味はない

PHP 7.1で追加された hash_hkdf() は出鱈目なシグニチャを持っています。バイナリキーを使うことを想定して、わざわざ既存のハッシュ関数とは異なり、バイナリハッシュ値だけを返せるようになっています。

暗号化がプログラム内で完結する、といった極一部の例外を除きhash_hkdf()でわざわざバイナリキーを使う意味はありません。

CSRFキーを守るURLを守るAPIキーを守る、といったWebアプリケーションで最も頻繁に使われる鍵導出ではバイナリキー/バイナリSaltは、遅いのでむしろ有害と言えます。わざわざバイナリを使う必要はありません。

参考: HMACハッシュの使い方のまとめ – HAMCですが、HKDFはHMAC based Key Derivation Functionです。多くがHKDFで置き換えられます。HKDFが使える場合、hash_hkdf()を使った方が速くなるでしょう。これはPHPの関数呼び出しのオーバーヘッドが比較的大きいことに起因します。

もっと読む

Computer Programming Fundamentals and Principles – Input Validation


I had discussion on PHP dev mailing list. It appeared that not few developers misunderstand “What is Input Validations“. Therefore, I summarize computer programming fundamentals and basics to help understanding validations.

Without fundamentals and basics understanding, discussion is meaningless. “Input Validation” is one of the most important countermeasure for cyber attacks. The idea is strongly supported by notable computer scientists (e.g. CMU’s CERT) and security specialists, yet it is misunderstood by majority of developers. Therefore, almost all web applications are missed to have proper “Input Validation” currently.

I came across this discussion too often, so I summarize why, “Input Validation”, “Input Data Validation” or “Application Input Data Validation” especially, is fundamental and mandatory requirement for applications.

TL;DR;

“Application Input Data Validation” and “Business Logic Validation” are 2 different validations by fundamentals and principles. Except few exceptions, ALL web application input data can be validated by “Application Input Data Validation” without user interactions. This achieves more secure state and cleaner/manageable code structure. Thus, applications should implement “Application Input Data Validation” always.

Note: “Application Input Data Validation” is NOT a replacement of “Business Logic Validation”.

もっと読む

「脆弱性を局所的に潰す」はアンチプラクティス

本物の「セキュアコーディング」(セキュアプログラミング)を知ればもう議論など必要ない、と思っています。本物の「セキュアコーディング」を「知ろうとしない」と幾らでもアンチプラクティスを作ってしまいます。

議論は終り、と思っていたのですがそうも行かないようなので紹介します。セキュアコーディングの概念を全く知ろうとしないで、セキュリティを作るのは「ただの無駄」です。多数のアンチプラクティス/間違いが含まれるスライドの中から(一々指摘するとキリがない)

  • 「脆弱性を局所的に潰す」

これ”だけ”だとアンチプラクティスです。

※ 契約プログラミングが流行らない理由はこいうアンチプラクティスも原因でしょう。特定の良いこと”だけ”を積み重ねても良い結果にならない、ことは合成の誤謬として知られています。

もっと読む

エンジニアなら理解る文字エンコーディングバリデーションの必要性

入力バリデーションで文字列の妥当性を検証(保証)しないと、不正文字問題の解決はできません。

よく「文字エンコーディングバリデーションは入力バリデーションしなければならない」と紹介はするのですが、その理由を詳しく解説していませんでした。これは文字エンコーディング攻撃の仕組みを理解してれば分かる事なのでしていませんでした。

しかし、文字エンコーディング攻撃の仕組みを理解していても必要なし、とする意見があるので理解り易く説明します。(理解りづらかったら教えてください)UTF-8のみですが、他の文字エンコーディングでも基本は同じです。

もっと読む

バリデーションですべきこと

このブログは、IPAは基礎的誤りを明示し、正しい原則を開発者に啓蒙すべき、の「追加の情報」として書いた物を別エントリとしてまとめた物です。

CERTセキュアコーディング

  • 入力バリデーション(原則1)
  • ”セキュアコーディング標準”による安全なロジック処理(+具体的な入力/出力処理)※ 原則10 「セキュアコーディング標準を採用する」=自ら作るモノ
  • 出力の無害化(原則7)※ IPA版は原則2

の3つが1つのセットとして成り立ちます。これ以外はセキュアコーディングではありません。

入力、ロジック、出力、これら全てにバリデーションが必要です。

参考: コンピュータは数値さえ正確に扱えない

もっと読む

IPAは基礎的誤りを明示し、正しい原則を開発者に啓蒙すべき

セキュアコーディングの第1原則は「入力をバリデーションする」です。セキュアコーディングの第1原則はソフトウェアセキュリティの一丁目一番地と言えるセキュリティ対策です。

入力バリデーションを第一のセキュリティ対策としているガイドライン:

セキュアプログラミング/セキュアコーディングを要求するセキュリティ認証:

  • ISMS – 国際情報セキュリティ標準 ISO 27000 の認証規格
  • PCI DSS – クレジットカード情報を取り扱う場合の認証規格

90年代初めからコンピューターサイエンティストのセキュリティ専門家は「入力バリデーション」が重要であるとしてきました。「入力バリデーション」は論理的にセキュアな構造のソフトウェアを作る為に欠かせない必須の要素だからです。防御的プログラミングから数えると四半世紀を越える月日が経っています。

しかし、残念ながらセキュアコーディングの第1原則の「入力バリデーション」は普及しているとは全く言えません。この状況には理由があります。

この状況に責任があるIPAは、IPAのセキュアプログラミング講座 1に基礎的な誤りがあったことを明示し、開発者に与えた誤解が正されるよう、最大限の努力をすべきでしょう。

IPAのあり得ないような基礎的誤りがどのような物だったか、ご覧ください。

追記: IPAは問題のページを更新/削除したようです。

もっと読む

ベストプラクティスもどきのアンチプラクティス TOP 10

ここ十数年で見聞きした、脆弱なアプリを作ってきたベストプラクティスもどきのアンチプラクティス、をリストアップしてみます。

限定された条件ではベストプラクティスと言える物でも、一般化するとアンチプラクティスになる物は多いです。

コード検査をしていると良く分るのですが、アンチプラクティスは強力な破壊力を持っています。ここに書いているアンチプラクティスを無くすだけでも、致命的な問題/脆弱なコードを多数無くすことができるでしょう。

特徴として原理や原則、適切な構造に合致しない物がアンチプラクティスになっています。

  • 原理:コンピュータープログラムは妥当な入力でしか、正しく動作しない
  • 原則:Fail Fast原則、失敗するモノはできる限り早く失敗させる、が守られていない
  • 構造:セキュリティ対策では境界防御、それも最外周の防御、が欠かせないがアプリケーション境界の防御が不十分・不適切

TOP 10と題しましたが、アンチプラクティスの順序と重要性(悪影響)にはあまり関連性はありません。

もっと読む

プログラムから「想定外」を無くす方法

ほとんどセキュリティ問題は「想定外の動作」が原因です。例えば、インジェクション攻撃は開発者にとって「想定外の動作」でしょう。ソフトウェア開発者が意図しない想定外の動作のほとんどは「想定外のデータ」が原因です。

この事実をから簡単に分かる「想定外」を無くす方法があります。たった2つの方法を”両方”行うだけで、現在あるアプリの9割程度の脆弱性が無くなります。

今まで出来る限り正確に「どうすれば想定外をなくせるか?」を紹介してきましたが、今回は出来る限り簡潔にどうすると良いのか、ダメなのか紹介したいと思います。 もっと読む

セキュリティを論理的に構築する方法

セキュリティの原理、原則、ベストプラクティスに自分でコメントを追加しました。以前、論理的にセキュリティ対策を検証する方法論理的なセキュリティ対策の評価方法は書いたのですが、論理的にセキュリティを構築する方法は書いていないことを思い出しました。追加したコメント欠陥だらけのソフトウェアセキュリティ構造を紹介したブログをベースにセキュリティを論理的に構築する方法を紹介します。

このエントリの解説はCERT、つまり米カーネギーメロン大学、の資料をベースにしています。

もっと読む

セキュリティの原理、原則、ベストプラクティス

「セキュリティの」と付けていますが、どの分野でも共通することだと思います。

何事でも論理的に何かのガイドライン/ルールを作る場合、まず変えることのできない

  • 原理 – 事物・事象が依拠する根本法則

を見つけ、その原理から導き出される

  • 原則 – 多くの場合に共通に適用される基本的なきまり・法則

を作り、さらに特定の条件下の具体的な事例として

を作ります。原理、原則、ベストプラクティスを理解していないと様々な問題がおきます。これらの基本的関係は

原理 > 原則 > ベストプラクティス

です。しかし、適用範囲の広さは

原理 < 原則 < ベストプラクティス

です。例えば、ベストプラクティスは”例外的”に原則に反した方法が”最善の方法”となる場合も少なくないからです。よく混乱や誤解の元になりますが、条件を絞った場合(例外的なケース)のベストプラクティスも在ります。

例外的なケース(一般的で無いモノ=例外的な物)をベストプラクティスにすることには異論もありますが、結構狭い条件でしかベストプラクティスにならないモノが”ベストプラクティス”と呼ばれていることは多いです。1

もっと読む

ソフトウェアはセキュリティの原理・原則から間違っている「入り口ノーガード設計」のままで良いのか?

現在のWebアプリケーションのほとんどは「入り口対策」がない「入り口ノーガード設計」です。

※ アプリケーションの入力処理、つまりMVCアーキテクチャーならコントローラーレベルで「入り口対策」がない設計が「入り口ノーガード設計」です。

このような設計になっているので、本来は自然数だけのハズのHTTPヘッダーのContent-Length(やContent-Type/Content-Disposition)にプログラムが書けてしまったStruts2 Webアプリにより国内ではクレジットカード情報が何十万件も盗まれる、米国では1億4千万件以上の信用情報が漏洩する、といった事件が発生しています。

幸い、「入り口対策」がない「入り口ノーガード設計」でもこういった大規模インシデントになるような脆弱性の攻撃は多くありません。しかし、話題にならないだけで多数のインシデントが世界中で発生していると考えられます。

先の事例はStruts2/フレームワークのセキュリティ問題、と捉えられていることが多いと思います。しかし、これは本質的にセキュリティ原則を無視した「入り口ノーガード設計」の問題です。

コード検査していると「入り口対策」をしていて、本当に良かったですね!というケースに出会うことが少なくありません。

2018年5月からEUでGDPRが施行されます。GDPR違反となると2000万ユーロまたは全世界売上の4%のどちらか高い方が罰金(組織によっては1000万ユーロまたは全世界売上の2%)となります。GDPRには様々な要件が要求されていますが、国際情報セキュリティ標準であるISO 27000で”普及している”とされた”セキュアプログラミング技術”の原則さえ採用しないシステムで個人情報漏洩が起きた場合の被害は、簡単に会社を潰すレベルの損害になる可能性があります。

もっと読む

出力対策の3原則 + 1原則

ソフトウェアの不具合/脆弱性を無くすためには、出力先に対して無害であることを保障する出力対策が重要です。どんな出力でも3つの方法で無害化できます。

このブログでは基本として、セキュアコーディングの概念に基き説明しています。先ずはよくある入力対策と出力対策の区別がついていない誤りから紹介します。

参考:IPAは基礎的誤りを明示し、正しい原則を開発者に啓蒙すべき

もっと読む

バリデーションには3種類のバリデーションがある 〜 セキュアなアプリケーションの構造 〜

バリデーション、と一言で言っても一種類/一箇所だけではありません。バリデーションには3種類のバリデーションがあります。

バリデーションは重要であるにも関わらず誤解が多い機能の筆頭だと思います。日本に限らず世界中でよくある議論に

  • バリデーションはモデルで集中的に行うべきだ!
  • なのでコントローラー(入力)でバリデーションなんて必要ない!
  • モデル集中型バリデーション以外の方法/場所でバリデーションするのは非効率で馬鹿馬鹿しい考えだ!

があります。どこかで見た事があるような議論ですが、世界的にこのような考えの開発者が多いことは、この入力バリデーション用のPHP拡張モジュールを書いた時の議論で分かりました。1PHP開発者MLで議論したのですが、紹介したような議論をした方が少なからず居ました。少し続くとすかさず「そもそもActiveRecordパターンでないモデルも多数あるし、ActiveRecordパターンのモデルだけのバリデーションだと遅すぎ、その間に実行させる機能が悪用されるケースは山程あって、しかもそれが奥深いライブラリのどこで起きるか分らんだろ」的なツッコミがあるところは日本での議論とは異なった点です。

実際、多くのWebアプリケーションフレームワークは入力バリデーション機能をデフォルトでは持たず、アプリケーションレベルでの入力バリデーションを必須化していません。開発者が上記のような考えになっても当然と言えるかも知れません。しかし、必要な物は必要です。何故?と思った方はぜひ読み進めてください。

流石にこの時の議論ではありませんでしたが、以下の様な議論も見かけます(ました)

  • 入力データはバリデーションはできない!
  • どんな入力でもWebアプリは受け付けて”適切”に処理しなければならない!
  • 入力バリデーションにホワイトリスト型は無理、適用できない!
  • ブラックリスト型とホワイトリスト型のバリデーションは等しいセキュリティ対策!
  • 入力バリデーションはソフトウェアの仕様でセキュリティ対策ではない!
  • 脆弱性発生箇所を直接または近い個所で対策するのが本物のセキュリティ対策である!

全てセキュアなソフトウェア構造を作るには問題がある考え方です。最後の「入力バリデーションはソフトウェアの仕様でセキュリティ対策ではない!」とする考え方の問題点は”セキュリティ対策の定義” 2セキュリティ対策=リスク管理、にはリスクを増加させる施策も含め、定期的にレビューしなければならないです。(ISO 27000/ISMSの要求事項)リスクを増加させる施策、例えば認証にパスワードを利用など、は定期的にレビューしその時々の状況に合ったリスク廃除/軽減策をタイムリーに導入しなければならない。リスク増加要因を管理しないセキュリティ対策=リスク管理は”欠陥のある管理方法”です。 を理解していないと問題点は見えないかも知れません。

  • セキュリティ対策(=リスク管理)とはリスクを変化させる全ての施策で、多くの場合はリスクを廃除/軽減させる施策だが、それに限らない。

このセキュリティ対策の定義はISO 27000/ISMSの定義をまとめたモノです。

TL;DR;

何事も原理と基本が大切です。基礎的な事ですがプログラムの基本構造と動作原理を正しく理解しておく必要があります。

セキュアコーディングの構造/原理/原則

入力対策と出力対策は両方必要でバリデーションはセキュアなソフトウェア構築には欠かせません。

  • 原理1: コンピュータープログラムは「妥当なデータ」以外では正しく動作できない
  • 原理2: 何処かでエラーになるから、ではセキュアにならない遅すぎるエラーはNG

アプリケーションの入り口で入力バリデーション(入力検証)をしていないアプリはセキュアでない構造です。

入り口以外に入力検証がないアプリもセキュアではない構造です。セキュアなアプリには最低限、入り口でのデータ検証と出口でのデータ無害化(エスケープ/無害化API/バリデーション)が必須です。

  • プログラムは妥当なデータでしか正しく動作できない入力バリデーションは原理的に必須
  • 出力対策は必須の物とフェイルセーフ対策の物があるフェイルセーフ対策の場合は下層の多層防御です。そもそも”データが妥当でない場合”(=フェイルセーフ対策)のエラーは起きてはならない。当然ですが出鱈目なデータを処理するのもNG。

多層防御 3ソフトウェアに限らずセキュリティは多層で防御します。必ず必要な対策と無くても大丈夫なハズの対策(フェイルセーフ対策)の2種類がある。フェイルセーフ対策は万が一の対策であり、本来フェイルセーフ対策は動作してはならない。動作した場合はプログラムに問題がある。「動作してはならない」は「必要ない」ではない。実用的なプログラムは複雑であり失敗してしまうケースは十分にある。入力バリデーションが甘い/無いプログラムだとフェイルセーフ対策が機能してしまうことは当たり前に起きる。 は重要なのに勘違いされているソフトウェアセキュリティ要素の1つです。

バリデーションには3つの種類があります。

  • 入力バリデーション正しく動作する為に必須(主に形式検証)
  • ロジックバリデーション正しく動作する為に必須(主に論理検証)
  • 出力バリデーション –  大半が上の2つに失敗した場合のフェイルセーフ対策(追加の対策 – 安全な特定形式のみ許可の場合)

※ 出力時のエスケープ/エスケープが不必要なAPIの利用によるデータの無害化は、必須の対策が半分、フェイルセーフ対策が半分です。

※ “入力ミスの確認”を”バリデーション”と考えたり、言ったりすると混乱の元です。”入力ミス/論理的整合性の確認エラー”は処理の継続、”あり得ないデータによるバリデーションエラー”では処理の中止、が必要なので区別する方が良いです。

※ ソフトウェア基本構造の入力処理では”あり得ないデータによるバリデーションエラー”、ロジック処理では”入力ミス/論理的整合性の確認エラー”、になります。

※ リスク分析の経験があれば自然にセキュアな構造を思い付くことも可能だと思います。

リスク分析とリスク対応をしよう

イメージ図:

参考:データもコードも一文字でも間違い/不正があるのはNG

https://blog.ohgaki.net/programs-cannot-work-correctly-one-char-is-enough

もっと読む

  • 1
    PHP開発者MLで議論したのですが、紹介したような議論をした方が少なからず居ました。少し続くとすかさず「そもそもActiveRecordパターンでないモデルも多数あるし、ActiveRecordパターンのモデルだけのバリデーションだと遅すぎ、その間に実行させる機能が悪用されるケースは山程あって、しかもそれが奥深いライブラリのどこで起きるか分らんだろ」的なツッコミがあるところは日本での議論とは異なった点です。
  • 2
    セキュリティ対策=リスク管理、にはリスクを増加させる施策も含め、定期的にレビューしなければならないです。(ISO 27000/ISMSの要求事項)リスクを増加させる施策、例えば認証にパスワードを利用など、は定期的にレビューしその時々の状況に合ったリスク廃除/軽減策をタイムリーに導入しなければならない。リスク増加要因を管理しないセキュリティ対策=リスク管理は”欠陥のある管理方法”です。
  • 3
    ソフトウェアに限らずセキュリティは多層で防御します。必ず必要な対策と無くても大丈夫なハズの対策(フェイルセーフ対策)の2種類がある。フェイルセーフ対策は万が一の対策であり、本来フェイルセーフ対策は動作してはならない。動作した場合はプログラムに問題がある。「動作してはならない」は「必要ない」ではない。実用的なプログラムは複雑であり失敗してしまうケースは十分にある。入力バリデーションが甘い/無いプログラムだとフェイルセーフ対策が機能してしまうことは当たり前に起きる。