Composerのバージョン指定方法でのチルダ(~)とキャレット(^)の違い

少し前(1.0.0-alpha10)からComposerのバージョン指定でキャレット(^)がサポートされるようになり、デフォルトのバージョン指定もチルダ(~)からキャレット(^)に変更されました。

キャレット(^)での指定はチルダ(~)と微妙に違い混乱するので、整理しておきます。

指定 対象となるバージョン
~1.1 1.1.0以上、2.0.0未満
^1.1 同上
~1.1.5 1.1.5以上、1.2.0未満
^1.1.5 1.1.5以上、2.0.0未満
~0.3 0.3.0以上、1.0.0未満
^0.3 0.3.0以上、0.4.0未満

要するにキャレットはセマンティックバージョニングに従って互換性が維持されるような範囲を指定するということですね。

^1.1^1.1.5の場合は、メジャーバージョンが変わらず互換性が維持される間、バージョンがあがります。

バージョン1.0未満のバージョンではマイナーバージョンの変更でも互換性が維持されない可能性があるので、そこはあがりません。

まあ、使ってるパッケージがセマンティックバージョニングにきちんと従っているかどうかはパッケージの作者によりますし、セマンティックバージョニングに従っているというパッケージでもバグで後方互換性が破られる可能性もあるわけですので、あまり信用しすぎないことをお薦めしますが。

ちなみに、その他のバージョン指定方法については、次の記事がわかりやすいです。

参考

関連

Tags: php, composer

今思いついている「インジェクション攻撃が防げるバリデーション関数」の残存リスク

昨日の記事で紹介した「ほぼ全てのインジェクション攻撃が防げるバリデーション関数」に残るリスクですが、フィードバックなどをいくつか得ました。twitterなどでコメントしてくださった方々、ありがとうございます。

いただいたフィードバックなども踏まえ、今のところ私が思いついている攻撃できるケースは以下です。気になって夜も眠れない人がいるかも知れませんので公表することにしました。

  1. SQL文のカラム名に外部からの入力をそのまま渡している場合、想定外のカラム名を指定されて情報が漏洩
  2. UnicodeのU+00A0(nbsp)のような別の文字や見えない文字によりユーザを騙す(例えば、なりすましなど)
  3. 表示の際に全角→半角変換するサイト(昔の携帯サイトなど)での全角文字によるXSS(徳丸さんのご指摘)

カラム名などの識別子の指定

1.は元記事にありますが、以下のようなコードがあった場合(これは設計ミスですが)、攻撃者はカラム名を自由に指定できますので、カラム名がわかればそのカラムの情報を表示させることができるかも知れません。

$sql = "SELECT ".$_GET['field_name']." FROM mytable";

ORDER BY句のカラム名についても上記同様文字列として受け取るようなコードの場合(これも設計ミスです)、想定外のカラムでソートされ予期しない情報が漏洩する可能性があります。

Unicode文字による詐称

2.は「validation」と「vaIidation」のような紛らわしい文字によりユーザを誤認させるという昔からある攻撃です。Unicodeを使うと「kenjis」と「ken​jis」のような人間には判別不能な表示が可能になります。

一応、PoCのコードを書いておきます。以下の結果は「Different」です。コピペすれば動くと思います。

<?php

if ('kenjis' === 'ken​jis') {
    echo 'The same' . PHP_EOL;
} else {
    echo 'Different' . PHP_EOL;
}

また、U+0020などが区切り文字として解釈されインジェクションが成立する処理系があるのではないか?というコメントもいただきました。そういう処理系があるのかどうかはわかりませんが。

全角半角変換

3.は半角記号はバリデーション関数で弾いていますが、全角の「<」「>」などは通りますので、表示の際に文字を半角に変換をすればXSSが可能になる余地があります。このケースは対応がちょっと難しいですね。もし、出力するHTMLを表示の際に一括で変換していたら設計ミスということになりましょうか。

ということで、今のところこの程度です。

もっと、データをぶっこ抜くとか派手なのができるといい?んですが、今のところやはり無理そうです。

これは!という攻撃方法を思いついた方は是非お教えください。

Tags: security, validation

ほぼ全てのインジェクション攻撃が防げるバリデーション関数の残存リスク

以下のブログに「ほぼ全てのインジェクション攻撃が防げるバリデーション関数」が紹介されています。

ちなみに、「全てのインジェクション攻撃が防げるバリデーション関数」ではないので注意してください。

また、記事には以下のように記載されています。

入力対策の次に重要な対策は出力対策です。プログラムから何らか出力を行う場合、確実に全ての出力が安全に行わなければなりません。 入力と出力のセキュリティ対策は独立したセキュリティ対策であることを忘れないようお願いします。

厳格な入力バリデーションをしていても、出力で完全に安全にするべき です…

さて、具体的なソースコードは以下です(一部修正)。

validate.php

<?php
/**
 * Basic input validation.
 *  - Input must be UTF-8.
 *  - PHP must be 5.6 and up.
 */

// Called upon any validation error.
function validation_exit($message, $val='') {
    http_response_code(403);
    trigger_error('Validation error: '.$message.'[' .rawurlencode($val).']', E_USER_ERROR);
    exit(1); // Make sure exit script.
}

// Default relatively safe validation function for all kinds of injections.
// Single line alpha numeric and UTF-8 is allowed.
// To allow more chars, use $regex_opt.
function validation_default($val, $min_len = 0, $max_len=60, $regex_opt='') {
    if (!is_string($val)) {
        validation_exit('Invalid type', gettype($val));        
    }
    if (strlen($val) < $min_len || strlen($val) > $max_len) {
        validation_exit('Too long value', strlen($val));
    }
    // Only UTF-8 is supported.
    // WARNING: This code assumes UTF-8 only script.
    if (ini_get('default_charset') != 'UTF-8') {
        validation_exit('Only UTF-8 is supported', $val);
    }
    if (!mb_check_encoding($val, 'UTF-8')) {
        validation_exit('Invalid encoding', $val);
    }
    // Allow only alpha numeric and UTF-8.
    // UTF-8 encoding:
    //   0xxxxxxx
    //   110yyyyx + 10xxxxxx
    //   1110yyyy + 10yxxxxx + 10xxxxxx
    //   11110yyy + 10yyxxxx + 10xxxxxx + 10xxxxxx
    // Since validity of UTF-8 encoding is checked, simply allow \x80-\xFF.
    if (!mb_ereg('\A[0-9A-Za-z\x80-\xFF'.$regex_opt.']*\z', $val)) {
        validation_exit('Invalid char', $val);
    }
}

// Test by GET value. Use "php -S 127.0.0.1:8080" or like, then
// access "http://127.0.0.1:8080/validate.php?v=TEST_VALUE_HERE".
error_reporting(-1);
ini_set('display_errors', 'On');
validation_default($_GET['v']);
echo 'Reached here: '.rawurlencode($_GET['v']);

ここから本題ですが、記事にはこのバリデーション関数を使っていても攻撃できるケースが示唆されています。

ブコメでも

ほぼ全てのインジェクション攻撃を無効化/防止する入力バリデーション | yohgaki's blog

これ何の時に使うバリデーション?まさか「汎用です安全にお使い頂けます」?それなら入力制限きつい割に普通に脆弱性つくれるけど…

2015/06/15 21:21

のように攻撃できることが示唆されているコメントがありスターも結構ついてますが、具体的な方法が示されているコメントはなぜか一切ありません。

個人的には、結構制限がきついのでいい攻撃方法を想定できません。とても気になるので、どなたでも攻撃方法を思いついた方はお教え願いたいです。

(2015-06-18 追記)

思いついた残存リスクについて書きました。

Tags: security, validation