>  기사  >  데이터 베이스  >  SQL 주입을 피하기 위해 PDO를 사용하여 mysql을 쿼리하는 방법

SQL 주입을 피하기 위해 PDO를 사용하여 mysql을 쿼리하는 방법

jacklove
jacklove원래의
2018-06-09 14:03:501735검색

기존의 mysql_connect 및 mysql_query 메소드를 사용하여 데이터베이스에 연결하고 쿼리할 때 필터링이 엄격하지 않으면 SQL 주입의 위험이 있습니다. mysql_real_escape_string() 함수를 사용하여 사용자가 제출한 값을 필터링할 수 있지만 여기에도 결함이 있습니다. PHP PDO 확장의 prepare 메소드를 사용하면 SQL 인젝션의 위험을 피할 수 있습니다.

PDO(PHP 데이터 개체)는 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에는 세 가지 오류 처리 방법이 있습니다.

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()는 주로 전처리 작업을 실행하기 위해 $rs->execute()를 사용해야 합니다. 전처리의 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();
?>

prepare 쿼리:

e7aacce4249b65e0c0c47d847f142e63prepare("select * from table");
if ($query->execute()) {
    while ($row = $query->fetch()) {
        print_r($row);
    }
}
?>

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.