2

私は、oracle-db を使用する大規模な php アプリケーション (純粋な php、フレームワークなしなど) を持っています。すべてのクエリは次のように実行されます。

oci_parse($conn_id,"insert into table (bla) values ('bla')");
oci_execute($stmt)

私はこれが悪いことを知っています!「バインドを使用する」などのことを指摘する必要はありません。それはわかっていますが、これを変更することはできません。

私たち全員が知っていることは、文字をエスケープする必要があるということです。この質問は特にキャラクターに関するもの'です。

次のようなクエリがたくさんあります。

$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
$query2 = "UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'"

確かに、通常はそれほど多くはありませんが、これ'はデモンストレーション用です。

質問へ: PHP でクエリ文字列全体を検証/エスケープする方法はありますか? どう考えても、これを達成する方法を考えたり見つけたりすることはできません。

'- に置き換えるだけで、クエリ文字列を作成する前にすべての値を簡単にエスケープできることは明らかですが、''クエリ全体を文字列としてしか持たない場合 (上記の例のように) は可能ですか? 個人的には「普遍的な解決策」は思い浮かびません...

4

6 に答える 6

2

これは、クエリが既に構築されている時点で、従来の手段では解決できないと思います。

  1. すべてのアポストロフィに単にスラッシュを追加しようとしても、もちろん機能しません。これは、区切り記号のアポストロフィと「値内」のアポストロフィをエスケープしているためです。
  2. どれが値内のアポストロフィで、どれが値を区切るアポストロフィかを判断する関数や正規表現はありません。
  3. パーサーでさえ役に立ちません。パーサーの仕事の一部は、クエリに無効な構文が含まれている場合に通知することですが、その構文を修正することではありません。場違いなアポストロフィにぶつかり、次の文字がコンマでない場合、すぐにボークします。

2番目の例の一部を見てみましょう:

field3 = 'mimi'm', field4 = 'mu's'c'hle'

通常のクエリ パーサーでは、field3値の'mini'後に誤った が続くように見えますがm、ここではコンマが必要です。これは、パーサーが処理するように設計されたものではありません。

したがって、これを処理するために何かカスタムを作成するとします。アポストロフィの後にコンマが続かない場合、アポストロフィが値の一部である必要があると判断したとしましょう。それは問題ありませんが、次のアポストロフィは区切り文字として意図されているのでしょうか?

実際にはアポストロフィの後にコンマが続く値を含むのではなく、アポストロフィが区切り記号であるかどうかを、コードはどのように判断するのでしょうか? 実際、値には、クエリの残りの部分とまったく同じように見えるものが含まれている可能性があります。(さらに、このようにクエリ自体の構造に疑問を持ち始めると、実際に無効なクエリをどのように検出するのでしょうか)。

tl;dr

GIGO = ガベージ イン、ガベージ アウト

任意の混乱を整理する (従来の) ソフトウェアを作成することはできません。

于 2013-02-05T16:47:20.293 に答える
2

さて、これは間違いなくフェイルプルーフでもエレガントでもありませんが、いわば「概念の証明」として、指定されたクエリで機能します...

本番サーバーで関数を使用しないでください..すぐに壊れます(遅くはありません;))

<?php


$query = "INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')";
$query2 = "UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'";

function clean_given_query($qry)
{
    if(strpos($qry , " VALUES "))
    {   
        //the easy way, since we know exactly how many fields we have here
        $qra = explode('VALUES', $qry);
        if(count($qra) == 2)
        {
            // qra[0] = "INSERT INTO table (field1, field2,field3,field4)"
            // qra[1] = "('bla,bla','blub', 'mimi'm', 'mu's'c'hle')";
            $qtemp = explode('(', $qra[0]);
            $qtemp = $qtemp[1]; // we can loose the insert -part for now
            $fieldcount = count(explode(',',$qtemp)); // now we know how many fields we want to populate
            $qra[1] = explode("','", $qra[1]); // dirty values....
            if(count($qra[1]) === $fieldcount) //make sure we have the correkt value count
            {
                $values = array();
                foreach($qra[1] as $i => $val)
                {
                    if($i==0)
                        $val = substr($val, 3); // we know $val is a string and index 0 starts with (' which we need to remove!
                    if($i == count($qra[1])-1) // last item  needs to be cropped at the end
                        $val = substr($val, 0, count($val)-3); //also a string as we know.

                    $val = addslashes($val); //escape the string according to your needs
                    $values[] = $val;
                }
                return $qra[0]." VALUES ('".implode("','", $values)."')";
            }

        }
    }
    else if (strpos($qry, "SET"))
    {
        $qra = explode('=', $qry);
        // $qra[0] = "UPDATE table SET field1";
        // $qra[1] = "'bla,bla', field2";
        $save = $qra[0]."='";

        foreach($qra as $i => $mixed)
        {   
            if($i == 0) // qra[0]  holds nothing to edit!
                continue;

            $parts = explode(',', $mixed); // [0] 'bla    [1] bla'  [2] field2
            $nextfield = array_pop($parts);

            $val = implode(',', $parts); // $val = 'bla,bla'
            if(strpos($nextfield , "WHERE"))
            {
                list($val, $nextfield) = explode("WHERE",$nextfield);
                $nextfield = " WHERE ".$nextfield;
            }
            $val = trim($val);
            $val = substr($val, 1, count($val)-2); //$val  bla,bla
            $val = addslashes($val); // escape according to your needs

            if($val!=="" and strpos($nextfield , "WHERE") === false)
                $save .= $val."', ".$nextfield."='";
            elseif($val!=="" and strpos($nextfield , "WHERE"))
                $save .= $val."' ".$nextfield."='";
            else
            {
                $val = trim($nextfield);
                $val = substr($val, 1, count($val)-2); //$val  bla,bla
                $val = addslashes($val); // escape according to your needs
                $save .= $val."'";
            }
        }
        return $save;
    }
}

echo $query.PHP_EOL;
echo clean_given_query($query).PHP_EOL;

echo $query2.PHP_EOL;
echo clean_given_query($query2).PHP_EOL;

?>

出力:

INSERT INTO table (field1, field2,field3,field4) VALUES ('bla,bla','blub','mimi'm','mu's'c'hle')
INSERT INTO table (field1, field2,field3,field4)  VALUES ('bla,bla','blub','mimi\'m','mu\'s\'c\'hle')
UPDATE table SET field1 =  'bla,bla', field2 = 'blub', field3 = 'mimi'm', field4 = 'mu's'c'hle' WHERE field5 = 'lol'zj'd'
UPDATE table SET field1 ='bla,bla',  field2 ='blub',  field3 ='mimi\'m',  field4 ='mu\'s\'c\'hle'  WHERE  field5 ='lol\'zj\'d'

少しの努力と、単純な爆発/破裂の代わりに reg_exp を修正し、必要に応じて適切なエスケープ関数を使用すると、特定のクエリをクリーニングできる関数を構築できます。

于 2013-02-05T18:32:15.380 に答える
0

シンプルな操作を行うだけで使用できますstr_replace()。いいえstr_replace("'", "\'", $string);

編集:あなたもできる

$str = "INSERT INTO table(field1, field2) 
                        VALUES (
                                replace(" . $value . ", Chr(39), Chr(39) & Chr(39)), 
                                replace(" . $value . ", Chr(39), Chr(39) & Chr(39))
                               );";

Chr(39) は ' を指します。

于 2013-02-05T16:17:48.133 に答える
-1

あなたの問題を理解していれば、うまくいくはずです

$name = addslashes("mu's'c'hle");
$query = "INSERT INTO teste (teste) VALUES ('$name')";
于 2013-02-05T16:28:26.073 に答える
-1
$query = "INSERT INTO table(field) Values('".addslashes("'")."')";

私はそれがフェイルセーブだと思うか、さらに良い

$query = sprintf("INSERT INTO table(field) Values('%s')", addslashes("'"));

いつか挿入を拡張したい場合に備えて、それは最も読みやすいからです。

[編集] 私が知る限り、文字列をエスケープしたいだけの場合は、どの種類の SQL を使用してもかまいませんが、念のため、addslashes はここでも同様に機能します。はい... phpには特殊なsql-escape関数がいくつかあります。

そして..質問を読み直して..クエリ文字列を持っているだけで、初期値を持っていないため、すべてを適切にエスケープするのはかなり困難です。

于 2013-02-05T16:23:42.520 に答える
-1

クエリを解釈してエラーがどこにあるかを判断し、適切な修正方法を何らかの方法で判断できるものを作成したくない場合を除き、方法はありません。

さらに、これを行っても、より大きな問題である SQL インジェクションはまだ修正されていません。

于 2013-02-05T16:29:01.950 に答える