DBに接続せずにmysql_real_escape_stringの代替


91

データベースに接続せずにmysql_real_escape_stringとして動作する関数を使用したいのですが、DB接続なしでドライテストを実行する必要がある場合があります。mysql_escape_stringは非推奨であるため、望ましくありません。私の発見のいくつか:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064



1
+1私は自分でMySQLクラスを作成しており、パラメータバインディングの目的でmysql_real_escape_string()を使用しています。すべてのホスティングでサポートされているわけではないので、mysqliの使用は避けます。マルチファイルとマルチクラスのライブラリも避けています。私が必要なのは、清楚な単一クラスだけです。ありがとうございました!
ベトナム、

私も+1します。私の使用例は、APIを介してSQLのフラグメントをリモートのSugarCRMインスタンスにプッシュする必要があるSugarCRM APiです。それは厄介ですが、それは私が作業しなければならないことです(いくつかのSugarCRM開発ヘッドを一緒にノックしてください)。APIを使用し、SugarCRMインスタンスの背後にあるデータベースから完全に分離されているアプリケーションで、SQLの文字列をエスケープする必要があります。
Jason

回答:


75

DB接続なしで文字列を安全にエスケープすることは不可能です。mysql_real_escape_string()準備されたステートメントは、適切な文字セットを使用して文字列をエスケープできるように、データベースへの接続が必要です。そうでない場合でも、マルチバイト文字を使用してSQLインジェクション攻撃が可能です。

テストのみを行う場合は、mysql_escape_string()SQLインジェクション攻撃に対して100%保証されるわけではありませんが、DB接続なしで安全なものを構築することは不可能です。


1
+1メモをありがとう。マルチバイト文字を使用してSQLインジェクション攻撃をテストする方法がよくわかりません。
ベトナム、

2
更新する古いコードがいくつか与えられました。mysql_escape_string接続なしで使用します(まだ理由を理解しようとしています)。その関数は廃止されているので、どうすればそれを置き換えることができるのかと思っています。接続を開かずに "適切な文字セット"を置き換える関数でそれを指定できることは確かに理にかなっているようです。
JohnK 2013年

3
不可能な?mysql_real_escape_stringは、手動で同等の関数に渡すことができる構成データではないデータベース接続から何を取得しますか?編集:以下を読むと、MySQL内でライブラリ関数が呼び出されるため、PHPの外部で処理が行われます。それはまだ移植可能かもしれませんが、それを最新に保つことはそれ自体プロジェクトです。
Jason

2
DB文字セットが事前にわかっている場合はどうなりますか?
jchook 14年

7
ええ、もしあなたが文字セットを知っているなら、何も接続なしでエスケープを行うのを防ぐのでしょうか?
ヨハン

66

mysql_real_escape_string関数のリファレンスページによると、「mysql_real_escape_string()は、MySQLのライブラリ関数mysql_real_escape_stringを呼び出します。これは、\ x00、\ n、\ r、\、 '、 "、および\ x1aをエスケープします。」

それを念頭に置いて、投稿した2番目のリンクで提供される関数は、必要な機能を正確に実行する必要があります。

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}

6
ありがとう。他のことをお勧めします:function escape($ aQuery){return strtr($ aQuery、array( "\ x00" => '\ x00'、 "\ n" => '\ n'、 "\ r" => '\ r'、 '\\' => '\\\\'、 "'" => "\'"、 '"' => '\"'、 "\ x1a" => '\ x1a')) ; }
ベトナム、

1
なぜ\ x1aが\\ x1aではなく\\\ x1aに置き換えられるのですか?これはタイプミスですか?
Michael Z

16
-1これは非常に危険です。データベース接続がマルチバイト文字セットを使用している場合、このような単純なバイト単位の置換は、データの破損(エスケープ/引用文字を含む)を引き起こす可能性があります-これは、悪意のある攻撃者が意図的に悪用して任意のSQLを挿入する可能性があります。
eggyal 2014

これで文字セットが間違っていると、危険な場合があります。マルチバイト文字セットの場合、mysqlがそれを使用している場合、誰かがバイトを入れて\\をキャンセルできます。マルチバイト文字セットは、mysqlの\\を含む2番目のバイトがスタンドアロン\\ではなくマルチバイト文字の一部として認識しないため、多くの場合、何でも取ることができます。UTF8で何が起こるかわかりません。[0xB0、 '\\']を使用すると、無効なバイトにヒットしたときに、それを飲み込むのではなく、そのバイトで停止して再び開始するだけです。
jgmjgm 2018

1
文字セットがutf8であることを知っている場合、これを使用してmb_strpos()(およびとmb_substr()同様の動作を作成してsubstr_replace())安全ですか?
SOFe 2018年

28

私の他の答えに直接反対すると、この以下の関数は、マルチバイト文字を使用しても、おそらく安全です。

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

上記のコードが機能しない理由を、私自身よりも知識のある誰かに教えてもらいたい...


+1余分な労力をありがとう。マルチバイト関連のSQLインジェクションの詳細を調べます。
ベトナム

$ return。= '\ x'になるはずです。dechex($ ord); 代わりに
ベトナム、

1
原則として、単一引用符で囲まれた文字列でも「\\」を使用することをお勧めします。注意しないと、単一の「\」が次の文字に影響を与える可能性があるからです。私はおそらく再びOCDをやっています。
phpが多すぎる

1
この関数はmysqlのエスケープルールに従っていないため、データの整合性が失われます。「MySQLは、表9.1「特殊文字のエスケープシーケンス」に示すエスケープシーケンスを認識します。他のすべてのエスケープシーケンスでは、バックスラッシュは無視されます。つまり、エスケープされた文字はエスケープされなかったものとして解釈されます。たとえば、「\ x」は単に「x」です。」- dev.mysql.com/doc/refman/5.6/en/...
velcrow

2
\ xAAは実際にはMySQL文字列リテラルのテキスト "xAA"以外のものを意味しますか?ドキュメントには、\ xには特別な意味がないと記載されているため、\は無視されます。dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason

6

さらなる研究から、私は見つけました:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

セキュリティ修正:

SQLインジェクションのセキュリティホールがマルチバイトエンコーディング処理で発見されました。バグはサーバーにあり、mysql_real_escape_string()C API関数でエスケープされた文字列を誤って解析していました。

この脆弱性は、OSDBコンソーシアムのプロジェクト間セキュリティコラボレーションの一環として、Josh BerkusとTom Laneによって発見および報告されました。SQLインジェクションの詳細については、次のテキストを参照してください。

討論。SQLインジェクションのセキュリティホールがマルチバイトエンコーディング処理で見つかりました。SQLインジェクションのセキュリティホールには、ユーザーがデータベースに挿入するデータを提供したときに、サーバーが実行するデータにSQLステートメントを挿入する場合があります。この脆弱性に関して、文字セットを認識しないエスケープが使用されている場合(たとえば、PHPのaddlashes())、一部のマルチバイト文字セット(SJIS、BIG5、GBKなど)でエスケープをバイパスすることが可能です。その結果、addslashes()などの関数はSQLインジェクション攻撃を防ぐことができません。サーバー側でこれを修正することは不可能です。最善の解決策は、アプリケーションがmysql_real_escape_string()などの関数によって提供される文字セット対応のエスケープを使用することです。

ただし、MySQLサーバーがmysql_real_escape_string()の出力を解析する方法にバグが検出されました。その結果、文字セット対応関数mysql_real_escape_string()を使用した場合でも、SQLインジェクションが可能でした。このバグは修正されました。

回避策。MySQLをmysql_real_escape_string()解析のバグの修正を含むバージョンにアップグレードできないが、MySQL 5.0.1以降を実行している場合は、回避策としてNO_BACKSLASH_ESCAPES SQLモードを使用できます。(このモードはMySQL 5.0.1で導入されました。)NO_BACKSLASH_ESCAPESは、SQL標準互換モードを有効にします。このモードでは、バックスラッシュは特殊文字とは見なされません。その結果、クエリは失敗します。

現在の接続にこのモードを設定するには、次のSQLステートメントを入力します。

SET sql_mode='NO_BACKSLASH_ESCAPES';

すべてのクライアントに対してモードをグローバルに設定することもできます。

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

このSQLモードは、サーバーの起動時にコマンドラインオプション--sql-mode = NO_BACKSLASH_ESCAPESを使用するか、サーバーオプションファイル(たとえば、my.cnfやmy.iniなど)にsql-mode = NO_BACKSLASH_ESCAPESを設定することで自動的に有効にすることもできます。 、システムによって異なります)。(Bug#8378、CVE-2006-2753)

Bug#8303も参照してください。


1
これはずっと前に修正されました。
常識

2
また、NO_BACKSLASH_ESCAPES 他の脆弱性をもたらすことに注意してください。
eggyal 2014

2
5.1.11で修正された-リンクが壊れていた、ここでのアーカイブは次のとおりです。web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/...
バスティオン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.