web-dev-qa-db-ja.com

Jfactory :: getDBOおよびsetQuery()を使用したSQLインジェクション

$db = JFactory::getDBO();
$searchP = JRequest::getVar('key');
$sql = "SELECT name FROM people LIKE " . "'%" . $searchP . "%'";

$db->setQuery($sql);
$fileR = $db->loadObjectList();

同じ文字列に2つのSQLステートメントがあると、setQuery()はエラーをスローしますか?

たとえば、私のコードによると、次のクエリパラメータまたは同様のものを渡すことにより、テーブルの削除コマンドを実行できます。

key=a'; DROP TABLE people; # 

さらに次のようなものを使用します

$db = JFactory::getDBO();
$query = $db->getQuery(true); 
$query ->setLimit('1');
$query ->select($db->quoteName('name'));
$query ->from($db->quoteName('people'));
$query ->like($db->quoteName($searchP));
$db->setQuery($query);

クエリオブジェクトのクエリ制限が1に設定されているため、インジェクションを防止しますか?

5
Jay Shri

quote()(またはq())とquoteName()(またはqn())を使用する場合、SQLインジェクション攻撃について心配する必要はありません。メソッドを適切に。

から https://docs.joomla.org/Secure_coding_guidelines#Secure_on_search

安全な検索

ワイルドカード文字%を含むLIKE句には、サービス拒否攻撃の可能性を回避するために特別なエスケープが必要になるため、特に注意が必要です。 LIKE句は次のように処理できます。

//ユーザーが指定した文字列をエスケープし、必要に応じて手動で%ワイルドカード文字を追加して、検索語を作成します。

_$search = '%' . $db->escape( $search, true ) . '%' );
_

// SQLクエリを作成します。ダブルエスケープを防ぐために、Quoteのデフォルトの動作を抑制します。

_$query = 'SELECT  * FROM #__table WHERE `field` LIKE ' . $db->quote( $search, false );
_

->like()は、私が調査した限りでは存在しません。したがって、上記のドキュメントの推奨事項に基づいて、name列を検索することを想定して、次のコードブロックを提案します。

_$db = JFactory::getDBO();
$query = $db->getQuery(true)
            ->select($db->qn('name'))
            ->from($db->qn('people'))
            ->where($db->qn('name') . ' LIKE ' . $db->q('%' . $db->escape($searchP, true) . '%', false));
$db->setQuery($query);
_

LIKEクエリを実行する場合、結果セットで複数行のデータを受け取るのが論理的であることがよくあります。セキュリティ対策としてsetLimit()メソッドを使用していたと思いますので、クエリを改善するために削除します。


inf3rnoのコメント の記述にかかわらず、 最新のドキュメント によるbind()メソッドはありません。 (私はとにかく_:needle_と_?_の両方をプレースホルダーとして使用してスニペットをテストし、受信しました:致命的なエラー:nullのメンバー関数bind()への呼び出し) Joomla-landに入る前に、クエリに供給されるすべての外部/信頼できないデータのプレースホルダーを備えた準備されたステートメントを使用するので、この方法でなかったらいいのにと思います。

2014年のLodderからの関連記事 Joomlaで準備されたステートメントについて。

上記のコードブロックのquote(escape())メソッドの目的/効果は、クエリに渡される文字列に関係なく、文字列が常に式の単一の値として扱われるようにすることです。これはmysqli_real_escape()と同等のようです(ただし、Joomlaの内部では確認していません)。残念ながら、多くのStackOverflow開発者はmysqli_real_escape()に次善のフラグを立て、代わりにプレースホルダーを使用した準備済みステートメントを推奨しています。 bind()メソッドが利用可能になり次第、すべてのJoomlaプロジェクトを更新します。


Joomla 3.8.6で次のテストを実行しました。

_$needle = "key=a'; INSERT INTO [... redacted query that would be successful on its own ...]; #";
try {
    $db = JFactory::getDbo();
    $sql = "SELECT [redacted] FROM [redacted] WHERE [redacted] LIKE " . "'%" . $needle . "%'";
    $db->setQuery($sql);
    var_export($db->loadAssocList());
} catch (Exception $e) {
    echo $e->getMessage();
}
_

そして受け取った:

1064 SQL構文にエラーがあります。 MySQLサーバーのバージョンに対応するマニュアルで、 'INSERT INTO'の近くで使用する正しい構文を確認してください

これは、JoomlaのsetQuery()メソッドが複数のクエリで窒息することを示しています。

7
mickmackusa