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

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

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

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

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

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

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

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追記)

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

Date: 2015/06/17

Tags: security