カテゴリー: Secure Coding

PostgreSQL 9.0から使える識別子とリテラルのエスケープ

PostgreSQL Advent Calender用のエントリです。

エスケープ処理が必要なのにエスケープ用のAPIが無い状態は良くありません。エスケープしないために動かないのはまだ良い方です。エスケープが必要なのにエ スケープをしなくても動いてしまい、セキュリティ上の問題となる場合もあります。全てのアプリケーション・ライブラリはエスケープが必要なデータに対するAPIを持っておくべき です。今回はPostgreSQL 9.0から追加されたエスケープ関数を紹介します。

PostgreSQL使い始めて最初の頃に気づくのはuserなどの予約語がフィールド名に使えない事かも知れません。例えば、

yohgaki@[local] test=# CREATE TABLE user (name text);
ERROR:  syntax error at or near "user"
行 1: CREATE TABLE user (name text);

と失敗してしまいます。これはuserがPostgreSQLの予約語であるためSQL文の識別子として使用できないからです。MS Accessからデータベースに入った方には識別子に日本語を使う場合も多いので、PostgreSQLでは日本語のテーブル名やフィールド名はそのままでは使えない事に気が付いた方も多いのではないでしょうか? もっと読む

gihyo.jp セキュリティ対策が確実に実施されない2つの理由

gihyo.jpで新しい記事が公開されました。

なぜ簡単な対策で防げる脆弱性でもセキュリティ対策が確実に実施されないのか?それには理由があります。

その理由とはこの2つではないでしょうか。

  • セキュリティ対策とコーディングのベストプラクティスは相反することを理解していない
  • セキュリティ対策の基本中の基本を理解していない

続きは

http://gihyo.jp/dev/serial/01/php-security/0044

でご覧ください。

こちらはその記事のはてなブックマークです。

http://b.hatena.ne.jp/entry/gihyo.jp/dev/serial/01/php-security/0044

コメント一つ一つにコメントを付けるつもりはありませんが、モノリシックなコードと処理が重複しているかいないかは関係ありません。またセキュリティ対策が重複していないと「多重のセキュリティ」を実装している事になりません。

バリデーションが仕様の話、という意味は理解できません。出力時のバリデーションは出力結果を利用するシステムが誤作動しないようにするためのセキュリティ対策です。出力はバリデーションするしか方法がない場合が多くあります。出力先は多岐にわたり、エスケープ関数もヘルパー関数も何もない、というケースはよくあります。

「多重のセキュリティ」とは同じチェックやセキュリティ対策をするということではありません。もちろん同じチェック・対策をしても構わないのですが、一般に異なるレイヤーや場所でセキュリティ対策を繰り返し行う事を「多重のセキュリティ」対策と言います。”重複”と記載したので分かりづらかったのかも知れないですね。

入力時のバリデーションコードと出力時のバリデーションコードは同じコードが使える場合もありますが別のコードを使うべきです。別のコードを使わないと「フェイルセーフ対策」の意味もなくなります。

システム構築にアーキテクチャとよいコーディングスタンダードが必要なのと同じで、セキュリティにもアーキテクチャとコーディングスタンダードが必要です。入力、ロジック、出力を別のシステムとして考えるのはアーキテクチャの話と言えると思います。入力を切り分けるのは比較的簡単ですが、出力は簡単ではありません。文字列を加工し一部がエスケープ処理済みだったり、ヘルパーを使って処理したり、別の関連システムとのやり取りがあったり、と一度にまとめて処理する事が難しい場合が多いです。フレームワークの制約があったりして、フレームワークのベストプラクティスに従うと出力する部分を切り出す事が不可能な場合もあります。このよう場合はコーディングの話と言えると思います。

よく知らないのに、というのも面白いコメントですね。Railsの基本仕様とそれに影響を受けたフレームワークの話をしています。誤読ですね。文章は一旦書くとひとり歩きする物ですからある程度は仕方ないのでしょう。仕事柄、Railsは最新版ではなくよく使われているバージョンを使っているのですが、3.2とかではバリデーションのアーキテクチャが改善されているでしょうか?またそのうち確認することにします。

入力のバリデーションと出力のエスケープが重複したセキュリティ対策であっても「多重のセキュリティ」として両方実施する、が理解できていないのは「多重のセキュリティ」を理解していないのでしょう。「PHPになぜ」という部分は「Webアプリになぜ」とタイトルを変えた方が良いのかも知れません。開発者に基本的なコンセプトや現状の理解が足りてないから脆弱なアーキテクチャの理解ができなかったり、プリペアードクエリがセキュリティ対策として不完全な対策であるという簡単な事も理解できないのだと思います。

RailsをDisっているからコミュニティは反応した方が、というコメントもありましたが逆にRailsを使い込んでる人なら同じ意見だと思います。プログラムなので、もちろん入力のチェックを最初に行う事は可能ですが、フレームワークが提供していた基本機能はデータベース保存前のバリデーションです。この仕様に困ったなあ、と思った事がある人こそ本当にRailsを使っていた人なのではないかな?

ところで、たしかプリペアードクエリが万能かのように説いていたIPAのセキュリティ対策の文書でも、最新版のSQLインジェクション対策では「エスケープ」を最初に解説しています。何が正しいのか、考え方の基本として正しいものはどう反論しても正しいので無駄な努力はやめた方が良いと思います。

追記 安全なSQLの呼び出し方(全40ページ、714KB)

この文書ではまずリテラルのエスケープ方法から解説し、3.3のまとめの図では正しく、エスケープで組み立てるしか無い場合はそちらを優先し、次にプログラムクエリが使える環境ではプリペアードクエリなどを使うような図になっています。RailsでもPHPのフレームワークでも同じですがquoteメソッドを使う場合、実際にはエスケープしています。エスケープを正しく理解していないとこれらの実装が正しいのかプログラマが判断できないので適切な解説だと思います。残念なのはPostgreSQLのエスケープ手法が解説されていない点です。今のPostgreSQLはSQL標準に則り、'(シングルクオート)は’(シングルクオート)でエスケープします。libpqにはリテラルを正しくかつ完全に処理できるようエスケープするPQescapeLiteralが追加されています。(PHPではpg_escape_literalとして利用できるようになります) これでエスケープすると E’文字列’ という形でエスケープを行い、SQL標準のエスケープである事が明示されます。おかしな使い方でSJISテキストを使っても誤作動することが無いようになっています。APIをサポートするプラットフォームがまだ少ないからこれは仕方がない部分でしょう。あって当然だった識別子のエスケープも解説されていないのは残念ですね。一般論として識別子のエスケープについては解説があった方がよいでしょう。プリペアードクエリを使っていてもエスケープが必要なケースです。紹介しないと完全な解説にはなりません。

同じ事はサニタイズに対する批判でも起きています。入力サニタイズがセキュリティ対策の切り札のように言われていた頃、私はホワイトリスト方式に入力のバリデーションこそが正しいセキュリティ対策で、ブラックリスト方式のサニタイズは不完全で誤った対策である、と言っていました。いろいろ反論もありましたが現在では「入力はバリデーションすべき」に反論する人はほぼ居ません。出力対策はエスケープが基本である、という持論に反対された方も多いですね。しかし、出力対策はエスケープが基本であるとすることに反論するようでは、分かってない人と思われるようになる日も遠くはないでしょう。

しかし、ネガティブなコメントには具体的な誤りの指摘や反論が皆無ですね。はてブの文化なのでしょうか?はてなのサービスは悪いものではないように思いますが、今ひとつメジャー感が出てこないのはこういう部分に原因があるのかも知れないですね。

セッションのクッキーを設定する場合のベストプラクティス

HTTPセッションは通常クッキーを利用して行います。クッキーを利用したセッションの場合、お薦めする設定は以下の通りです。

  1. ドメイン名は指定しない
  2. パスはルート(/)を指定する
  3. セッション管理用のクッキーはセッションクッキー(有効期間0)にする
  4. httponly属性を付ける
  5. 可能な場合は必ずsecure属性をつける
  6. 複数アプリケーションを利用する場合はsession.nameまたはsession_name()でセッションクッキー名で指定する (アプリケーションの固有名デフォルトで設定し、設定項目として変更できるようにする)

もっと読む

PHPセッションアダプションをスクリプト側で修正する方法

PHPのスクリプトを使ってアダプティブなPHPセッションをアダプティブにしない方法を紹介します。

このブログで紹介していたかどうか覚えていないですが、セッションアダプション対策としてsession_regenerate_id()が導入された時に議論・紹介されているので知っている方も多いと思います。(というより、PHPerの常識ですよね?)

まずはセッションアダプションの原理と対策の復習をしておきます。 もっと読む

OSC Tokyo – 今更聞けないSQLインジェクションの現実と対策

明日のOSC東京Fallでは「SQLインジェクション”ゼロ”のPostgreSQL利用法 – 今更聞けないSQLインジェク ションの現実と対策」と題したセッションを日本PostgreSQLユーザ会の講師として話をさせて頂きます。

SQLインジェクションはとうの昔に枯れた話題と思われていますが、古くても今の問題です。何年か前、日本PostgreSQLユーザ会のセミナーで手作業でのブラインドSQLインジェクションのデモをした事がありますが今回はツールを使ったデモもあります。書いている間に当初作ろうと思っていたプレゼンとは異なる物なってしまいました。多少紹介から期待する内容とは異なっているかも知れません。既にSQLインジェクションについては十分知っている方でも、それなりに(?)楽しめる内容になっていると思います。おかげ様で満員だそうですが、飛び込みでも少しは入れるのかな?

45分なのに60枚もスライドがある上、デモもあります。かなりハイペースで話すことになります。ネットで直ぐに見つかるような基本的な事はあまり書かなかったのですが、無いようで書くとSQLインジェクションについて色々在る物です。多少スライドは飛ばす事になります。

ほぼ同じ内容でOSC高知でも話をさせて頂く予定です。
来たくても来れなかった方は是非高知でお会いしましょう。

セキュリティ専門家でも間違える!文字エンコーディング問題は難しいのか?

一見徳丸さんのブログは分かりやすいように思えますが、それは単純な実験により分かりやすいように見えるだけで複数の間違いがあります。

その間違いとは

  • 意図の取り違い – 誤読
  • 言語の仕様と実装の理解不足
  • HTTPやPHP仕様の理解不足
  • セキュリティ対策をすべき場所の理解不足

です。(※0)

もっと読む

PHP:既知のセキュリティ脆弱性 – Session Adoption

追記:より新しい情報については間違いだらけのHTTPセッション管理とその対策をどうぞ。

PHPには広く知られているにも関わらず放置されている既知のセキュリティ脆弱性が幾つかあります。その一つがセッションモジュールのセッションアダプション(Session Adoption)脆弱性です。この脆弱性は現在広く利用されているWebアプリケーションの安全性に、非常に大きな影響を与える脆弱性です。

セッションアダプション脆弱性とはセッション固定化攻撃を可能とする脆弱性の一種です。セッションアダプションに脆弱なセッション管理システムは、ユーザ(ブラウザ)が送信してきた未初期化のセッションIDを受け入れ、セッションを初期化してしまいます。PHPに限らず、RailsやJavaのフレームワーク等、多くのWebフレームワークに発見されている脆弱性です。

セッションアダプション脆弱性を利用すると、攻撃者は長期間に渡って他人のIDを使う成りすましが可能になる場合があります。IDを盗みたい犯罪者には利用価値の高い脆弱性です。

この脆弱性は、10年以上前から問題視されている国別TLD(ccTLD)の属性ドメイン(国別Top Level Domain, co.jp, or.jpなどのドメイン)にも下位ドメインからクッキーが設定でき、サブドメインのクッキー設定が無視される(送信順序、優先順位がいい加減)、というとんでも無いクッキーの仕様と組み合わせると、大量の他人のユーザセッションIDを取得(設定)し、成りすます事ができます。

セッションアダプション問題は全てのPHP、PHP 4.4.9/PHP 5.2.8/PHP 5.3/PHP 6.0に共通する脆弱性です。

最近、影響範囲はかなり狭くなりましたが、まだまだ注意が必要な脆弱性であり、根本的な解決にはパッチと適切なセキュリティ対策が必要です。

もっと読む

ホワイトリストはどう作る?

まずホワイトリストの基本中の基本は”デフォルトで全て拒否するであることに注意してください。全て拒否した上で許可するモノを指定しないとホワイトリストになりません

例えば、CSPはホワイトリストで不正なJavaScriptの実行を防止する仕組みです。2016年のGoolgeの調査によると95%のCSP定義が、実際にはJavaScriptインジェクション脆弱性の防止に役立っていない、との調査結果を発表しています。原因はホワイトリストの作り方の基本、全て拒否した上で許可するモノを指定する、を理解していないことにあると考えられます。1

私はいつも基本的に能動的なセキュリティ対策2を選択するようにお勧めしています。能動的なセキュリティ対策とは全ての入力値の厳格なバリデーション処理であり、出力時に過剰とも言えるエスケープ処理です。入力/出力の両方にホワイトリスティング対策をお勧めしています。3

もっと読む

正しいメールアドレスのチェック方法

正しいメールアドレスのチェック方法がちょっとした話題になっているようです。Web屋のネタ帳でも取り上げられていますが、メールアドレスのチェック方法自体は解説していません。ついでなので書いておきます。

「本当に正しいメールアドレスかチェック」するには実際にメールを送信して、送信されたユーザしか知り得ない情報をユーザが知っている事により確認しなければなりません。これはWeb屋のネタ帳で解説されている通りです。

もっと読む

SET NAMESは禁止

MySQLには文字エンコーディングを変更する「SET NAMES」SQL文が用意されています。(PostgreSQLも同様のSQL文、SET CLIENT_ENCODINGがあります)この機能はSQLコンソールからは使ってよい機能ですが、アプリケーションからは使ってはならない機能です。SQLインジェクションに脆弱になる場合があります。

Ruby on Railsの本を読んでいて、ActiveRecordを説明している部分にMySQLの文字エンコーディングを変更する場合の例としてSET NAMESが利用されていました。アプリケーションからはSET NAMESは使ってはならない事を周知させるのは結構時間が必要かなと思いました。

PHPも5.2の途中からMySQLモジュールにlibmysqlの文字エンコーディング設定APIのラッパー関数が追加されていたりするので、たまたま最近読んだRoRの本だけでなく、多くの開発向け情報ソースにSET NAMESを利用した例が載っていると思います。

ストアドプロシージャだけ使っていれば安全ですが、アプリケーションからDBMSの文字エンコーディングを設定する場合、SQL文ではなく必ず文字エンコーディング設定APIを利用するよう紹介しなければならないです。MySQL4はストアドプロシージャが使えないので、フレームワークなどではエミュレートしています。ストアドプロシージャだけ使って防御している「つもり」で防御になっていない場合もあります。これもフレームワークを使っていてもアプリケーションが脆弱になる良い例ですね。

脆弱性の説明は面倒ですが注意事項は簡単です。「DBMSをアプリケーションから利用する場合、文字エンコーディング設定は必ずAPIを利用する」つまり「SET NAMES(PostgreSQLのSET CLIENT_ENCODING等も)は禁止」です。

PHPのMySQL:

PHPのPostgreSQL:

PHPのPDO:

<?php
// MySQL
$pdo = new PDO(
    'mysql:host=yourhost;dbname=yourdb;charset=sjis',
    'user', 'password'
);

// PostgreSQL
$pdo = new PDO(
    "pgsql:host=yourhost;dbname=yourdb;options='--client_encoding=sjis'"
);

Rails:

config.encoding = 文字コード

 

解答:まちがった自動ログイン処理

問題:まちがった自動ログイン処理の解答です。このブログエントリは最近作られたアプリケーションでは「問題」にしたような実装は行われていないはず、と期待していたのですがあっさり期待を破られたのでブログに書きました。このブログの方が詳しく書いていますけが「Webアプリセキュリティ対策入門」にも正しい自動ログイン処理を書いています。

参考:自動ログイン以外に2要素認証も重要です。「今すぐできる、Webサイトへの2要素認証導入」こちらもどうぞ。HMACを利用した安全なAPIキーの送受信も参考にどうぞ。

もっと読む