ホームページ  >  記事  >  データベース  >  SQL インジェクションを回避するために PDO を使用して mysql にクエリを実行する方法

SQL インジェクションを回避するために PDO を使用して mysql にクエリを実行する方法

jacklove
jackloveオリジナル
2018-06-09 14:03:501643ブラウズ

従来の mysql_connect および mysql_query メソッドを使用してデータベースに接続してクエリを実行する場合、フィルタリングが厳密でないと SQL インジェクションのリスクがあります。 mysql_real_escape_string() 関数はユーザーが送信した値をフィルタリングするために使用できますが、これにも欠陥があります。 PHPのPDO拡張機能のprepareメソッドを使用することで、SQLインジェクションのリスクを回避できます。

PDO (PHP Data Object) は、PHP5 に追加された主要な新機能です。PHP 5 より前には、php4/php3 には、php_mysql.dll など、さまざまなデータベースに接続して処理するためのデータベース拡張機能が多数含まれていたためです。 PHP6 もデフォルトで PDO を使用して接続し、mysql 拡張機能が補助として使用されます。公式アドレス: http://php.net/manual/en/book.pdo.php

1. PDO の設定

PDO 拡張機能を使用する前に、まず php でこの拡張機能を有効にする必要があります。 ini、「extension=php_pdo.dll」の前の「;」番号を削除します。データベースに接続する場合は、PDO に関連するデータベース拡張子 (通常は php_pdo_mysql) の前の「;」番号も削除する必要があります。 .dll が使用されます)、Apache サーバーを再起動できます。

extension=php_pdo.dll 
extension=php_pdo_mysql.dll

2. PDO は mysql データベースに接続します

$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password");

データベースへの長い接続を使用したい場合は、最後に次のパラメータを追加できます。

3. PDO 設定プロパティ

PDO には 3 つのエラー処理メソッドがあります:

PDO::ERrmODE_SILENT はエラー メッセージを表示せず、エラー コードのみを設定します

PDO::ERrmODE_WARNING は警告エラーを表示します

PDO::ERrmODE_EXCEPTION は例外をスローします

次のステートメントを使用して、例外をスローするエラー処理メソッドを設定できます

$dbh = new PDO("mysql:host=localhost;dbname=mydb","root","password","array(PDO::ATTR_PERSISTENT => true) "); 
$dbh = null; //(释放)

データベースが異なると、返されるフィールド名の大文字と小文字の処理が異なるため、PDO は PDO を提供します::ATTR_CASE 設定項目 (PDO::CASE_LOWER、PDO ::CASE_NATURAL、PDO::CASE_UPPER を含む) を使用して、返されるフィールド名の大文字と小文字を決定します。

PDO::ATTR_ORACLE_NULLS タイプ (PDO::NULL_NATURAL、PDO::NULL_EmpTY_STRING、PDO::NULL_TO_STRING を含む) を設定して、データベースから返される NULL 値に対応する値を php で指定します。

4. 一般的な PDO メソッドとその応用

PDO::query() は主に記録された結果を返す操作、特に SELECT 操作に使用されます

PDO::exec() INSERT、UPDATE、その他の操作など、結果セットを返さない操作の場合、

PDO::prepare() は主に前処理操作です。前処理の SQL ステートメント。このメソッドはパラメーターをバインドでき、非常に強力です (SQL インジェクションの防止はこれに依存します)

PDO::lastInsertId() は最後の挿入操作を返し、主キーの列の型は最後に自動インクリメントされます。 ID

PDOStatement::fetch() はレコードの取得に使用されます

PDOStatement::fetchAll() はすべてのレコードをコレクションに取得するために使用されます

PDOStatement::fetchColumn() は取得に使用されます結果フィールドで指定された最初のレコード、デフォルトは最初のフィールドです

PDOStatement::rowCount(): 主に、PDO::query() および PDO の DELETE、INSERT、および UPDATE 操作の影響を受ける結果セットに使用されます::prepare()。PDO::exec() メソッドおよび SELECT 操作では無効です。


5.PDO 操作 MYSQL データベース インスタンス

$db->setAttribute(PDO::ATTR_ERrmODE, PDO::ERrmODE_EXCEPTION);
<?php 
$pdo = new PDO("mysql:host=localhost;dbname=mydb","root",""); 
if($pdo -> exec("insert into mytable(name,content) values(&#39;fdipzone&#39;,&#39;123456&#39;)")){ 
echo "insert success"; 
echo $pdo -> lastinsertid(); 
} 
?>
<?php 
$pdo = new PDO("mysql:host=localhost;dbname=mydb","root",""); 
$rs = $pdo -> query("select * from table"); 
$rs->setFetchMode(PDO::FETCH_ASSOC); //关联数组形式
//$rs->setFetchMode(PDO::FETCH_NUM); //数字索引数组形式
while($row = $rs -> fetch()){ 
    print_r($row); 
} 
?>

データの行数をカウントします:

<?php
foreach( $db->query( "SELECT * FROM table" ) as $row )
{
    print_r( $row );
}
?>

prepare メソッド:パラメータ化されたクエリ:

<?php
$sql="select count(*) from table";
$num = $dbh->query($sql)->fetchColumn();
?>

PDO の使用 MySQL データベースにアクセスする場合、デフォルトでは実際のプリペアド ステートメントは使用されません。この問題を解決するには、準備されたステートメントのエミュレーション効果を無効にする必要があります。 PDO を使用してリンクを作成する例を次に示します:

<?php
$dbh = new PDO(&#39;mysql:dbname=mydb;host=127.0.0.1;charset=utf8&#39;, &#39;root&#39;, &#39;pass&#39;);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
?>

setAttribute()这一行是强制性的,它会告诉 PDO 禁用模拟预处理语句,并使用 real parepared statements 。这可以确保SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)。

虽然你可以配置文件中设置字符集的属性(charset=utf8),但是需要格外注意的是,老版本的 PHP( < 5.3.6)在DSN中是忽略字符参数的。

完整的代码使用实例:

<?php
$dbh = new PDO("mysql:host=localhost; dbname=mydb", "root", "pass");
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果
$dbh->exec("set names &#39;utf8&#39;"); 
$sql="select * from table where username = ? and password = ?";
$query = $dbh->prepare($sql); 
$exeres = $query->execute(array($username, $pass)); 
if ($exeres) { 
    while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
        print_r($row);
    }
}
$dbh = null;
?>

上面这段代码就可以防范sql注入。为什么呢?

当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,它们是分开传送的,两者独立的,SQL攻击者没有一点机会。

但是我们需要注意的是以下几种情况,PDO并不能帮助你防范SQL注入。

不能让占位符 ? 代替一组值,这样只会获取到这组数据的第一个值,如:

select * from table where userid in ( ? );

如果要用in來查找,可以改用find_in_set()实现

$ids = &#39;1,2,3,4,5,6&#39;;
select * from table where find_in_set(userid, ?);

不能让占位符代替数据表名或列名,如:

select * from table order by ?;

不能让占位符 ? 代替任何其他SQL语法,如:

select extract( ? from addtime) as mytime from table;

本篇文章如何使用PDO查询mysql避免SQL注入的方法,更多相关内容请关注php中文网。

相关推荐:

关于php 双向队列类的讲解

php heredoc 与 nowdoc之间的区别与特点

关于HTML5 localStorage and sessionStorage 之间的区别

以上がSQL インジェクションを回避するために PDO を使用して mysql にクエリを実行する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。