天天看點

PHP代碼審計 SQL注入專題

常見防禦方法

防禦原理:輸入(解決數字型注入–>即加is_numeric這些去判斷)-------轉義處理(解決字元型注入)-------輸出(解決資料庫報錯)

1.禁止資料庫爆錯資訊洩露件 php.ini檔案中display_errors = Of

2.php内部轉義處理函數

mysql_real_escape_string-->能将特殊字元進行轉義
mysql_escape_string()
magic_quote_gpc()
addslashes->這個函數會加上轉義符
對立函數stripcslashes-->這個函數為删除字元串中存在的\
           

3.預處理技術進行查詢

利用 m y s q l i − > p r e p a r e 和 mysqli->prepare和 mysqli−>prepare和mysqli_stmt->bind_param函數進行去預處理

<?php
$sql = "select id,username,password from users where id=?";建立一個預定義的對象 ?占位
$mysqli_stmt = $mysqli->prepare($sql);
$id=$_REQUEST['id'];
$mysqli_stmt->bind_param("i",$id);綁定參數
$mysqli_stmt->bind_result($id,$username,$password);綁定結果集
$mysqli_stmt->execute();//執行
while($mysqli_stmt->fetch()){ //取出綁定的結果集
echo $id." ".$username ." ". $password;
}
?>
           

代碼分析

== 防禦成功的利用這兩個函數即可==

<?php     
 
 if (isset($_GET['Submit'])) { 
 
     // Retrieve data 
 
     $id = $_GET['id']; 
     $id = stripslashes($id); 
     $id = mysql_real_escape_string($id); 
 
     if (is_numeric($id)){ 
 
         $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'"; 
         $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' ); 
 
         $num = mysql_numrows($result); 
 
         $i=0; 
 
         while ($i < $num) { 
 
             $first = mysql_result($result,$i,"first_name"); 
             $last = mysql_result($result,$i,"last_name"); 
              
             echo '<pre>'; 
             echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last; 
             echo '</pre>'; 
 
             $i++; 
         } 
     } 
 } 
 ?>

           

如果沒有兩個過濾函數

利用方法 http://127.0.0.1/?id=1

特殊案例

1.寬位元組注入思路

1.1 正常寬位元組注入

核心:mysql查詢的時候采用寬位元組方式查詢導緻

<?php 

$con = mysql_connect("localhost","root","root");
mysql_query("SET NAMES 'gbk'");
mysql_select_db("test", $con);
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$query = "SELECT * FROM users WHERE id ='{$id}' ";
?>

是以可以利用
id=%df%27進行去繞


修複方法:
1.将character_set_client設定為binary(二進制)
全部指定為二進制傳輸
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",
$conn);
2.指定php連接配接mysql的字元集
mysql_set_charset('gbk',$conn);
id=mysql_real_escape_string(_GET['id']);
           

1.2php編碼轉換導緻的寬位元組注入

導緻原理:在字元輸入後進行了編碼轉換進而導緻逃逸單引号

<?php
$con = mysql_connect("localhost","root","root");
mysql_query("SET NAMES 'gbk'");
mysql_select_db("test", $con);
mysql_query("SET character_set_connection=gbk,
character_set_results=gbk,character_set_client=binary", $con);
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$id=iconv('utf-8','gbk',$id);//和上面相比 添加了這個代碼
$query = "SELECT * FROM users WHERE id ='{$id}' ";
$result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');
while($row = mysql_fetch_array($result))
{
echo $row['0'] . " " . $row['1'];
echo "<br />";
}
echo "<br/>";
echo $query;
mysql_close($con);
?>

#繞過語句--> 錦',因為utf-8編碼和gbk編碼的不同性質,進而導緻逃逸,溢出導緻sql注入。

           

2.編碼解碼導緻sql注入

原理:

字元在拼接到sql注入之前進行了解碼

例子

<?php
$con = mysql_connect("localhost","root","root");
mysql_select_db("test", $con);
$id = addslashes($_REQUEST['id']);
$id = urldecode($id);//$id = base64_decode($id);#核心導緻的原因
$query = "SELECT * FROM users WHERE id = '{$id}'";
$result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');


#繞過方法
id=1%2527union select 1,2,3,4%23
           

3.二次注入

導緻原理:

1.資料入庫後轉義符号會無

2.而且在次調用了我們插入的内容去查詢

如2018 網鼎杯