目錄
- 萬能密碼的SQL注入漏洞其PHP環境搭建及防御手段
- 一、環境搭建
- 二、session會話
- 三、環境搭建代碼
- 1、創建數據庫腳本
- 2、登錄界面html
- 3、查詢數據庫是否為正確的賬號密碼php代碼
- 4、連接數據庫php代碼:
- 5、注銷登錄代碼(即關閉session會話)
- 6、登錄成功歡迎界面
- 四、萬能密碼漏洞剖析
- 五、萬能密碼攻擊防護
- 1、使用正則表達式限制用戶輸入
- 2、使用PHP轉義函數
- 3、轉義函數的弊端
- 六、MySQLi 參數化查詢
萬能密碼的SQL注入漏洞其PHP環境搭建及防御手段
一、環境搭建
這個滲透環境的搭建有以下幾點:
- 基于session的會話
- 登錄界面
- 登錄成功界面
- 注銷界面
- 數據庫搭建
- 數據庫連接
二、session會話
- 服務器端利用session_start()函數發起一次session的會話
- 此時我們登錄成功后用戶的數據被保存在服務器端的Cookie: session= ,即sessionID
- 如果需要再次訪問
- 服務器端的
$_SESSION['...']
會獲取用戶session
- 然后與原本存在于服務器的sessionID進行比對,如果比對成功,則證明用戶正確
三、環境搭建代碼
1、創建數據庫腳本
在MySQL中使用source命令即可運行腳本:
drop database if exists lab;
create database lab;
use lab;
create table users
(
id int not null auto_increment,
username char(32) not null,
passcode char(32) not null,
primary key(id)
);
insert into users(username,passcode) values('admin','admin123');
insert into users(username,passcode) values('alice','alice456');
2、登錄界面html
html>
head>
meta charset="UTF-8">
title>Login/title>
style>
#a {
width: 500px;
text-align: center;
}
.b {
width: 200px;
height: 30px;
}
/style>
/head>
body>
div id=a>
h2>Login!/h2>
form name="form_login" method="POST" action="check_login.php">
Username:input type="text" class="b" name="username" />br> br>
Password:input type="password" class="b" name="password" />br>
input type="submit" name="Submit" value="Submit" />
input type="reset" name="reset" value="Reset" />
/form>
/div>
/body>
/html>
3、查詢數據庫是否為正確的賬號密碼php代碼
?php
include('con_database.php');
$username=isset($_POST['username'])?$_POST['username']:'';
$password=isset($_POST['password'])?$_POST['password']:'';
if($username=='' || $password==''){
echo "script>alert('請輸入賬號和密碼!')/script>";
exit;
}
$sql="select * from users where username='$username' and passcode='$password'";
$query=mysqli_query($con,$sql) or die('SQL語句執行失敗'.mysqli_error($con));
if ($row=mysqli_fetch_array($query)){
session_start();
$_SESSION['username']=$row[1];
echo "a href='welcome.php'>歡迎訪問/a>";
}else{
echo "script>alert('登錄失敗!');history.go(-1)/script>";
}
mysqli_close($con);
?>
4、連接數據庫php代碼:
?php
$con=mysqli_connect('127.0.0.1','root','root') or die("數據庫連接失敗!");
mysqli_select_db($con,'lab')or die("數據庫連接失敗");
?>
5、注銷登錄代碼(即關閉session會話)
?php
session_start();
session_unset();
session_destroy();
echo "注銷成功";
?>
6、登錄成功歡迎界面
?php
session_start();
if(isset($_SESSION['username'])){
echo "歡迎用戶".$_SESSION['username']."登錄";
echo "br>";
echo "a href=logout.php>退出登錄/a>";
}else{
echo "您沒有權限訪問";
}
?>
至此,我們的滲透環境就構建好了
四、萬能密碼漏洞剖析
- 用戶名輸
入' or 1=1 or'
,密碼隨意,發現可以登錄進去
- 密碼輸入
'or '1=1
也可以登錄進去
當然登錄方法不止一種:
原來查詢語句是這樣的:
$sql="select * from users where username='$username' and passcode='$password'";
經過注入之后,變成:
$sql="select * from users where username='' or 1=1 or ' and passcode='****'";
我們觀察到,where后面呃字句中的username被閉合,并且字句分成三個句子并用or連接。
在SQL語句中 and的優先級要大于or,所以1=1先判斷,為真,即where后面的語句為真,即整個SQL語句為真,即表示查詢正確
而形成的語句可以將整個users表查詢,后面的$row=mysqli_fetch_array($query)
選擇的是查詢的第一行值,這樣滿足了SQL語句并跳過了登錄驗證
由此可以引申出,只要where后面字句為真,即可跳過驗證,有如下衍生方法:
' or 1=1 #
' or 1=1 --
(后面有空格)
'or"="or'
五、萬能密碼攻擊防護
1、使用正則表達式限制用戶輸入
可以使用正則表達式限制用戶的用戶名輸入,比如:/^[a-z0-9A-Z_]{5,16}$/
這個限制了用戶5位以上16位以下的字母數字下劃線為用戶名的輸入
這個限制在check_login.php中添加
?php
include('con_database.php');
$username=isset($_POST['username'])?$_POST['username']:'';
$password=isset($_POST['password'])?$_POST['password']:'';
if (!preg_match("/^[a-Z0-9A-Z_]{5,16}$/",$username)){
echo "script>alert('用戶名格式錯誤')/script>";
exit;
if($username=='' || $password==''){
echo "script>alert('請輸入賬號和密碼!')/script>";
exit;
}
$sql="select * from users where username='$username' and passcode='$password'";
$query=mysqli_query($con,$sql) or die('SQL語句執行失敗'.mysqli_error($con));
if ($row=mysqli_fetch_array($query)){
session_start();
$_SESSION['username']=$row[1];
echo "a href='welcome.php'>歡迎訪問/a>";
}else{
echo "script>alert('登錄失敗!');history.go(-1)/script>";
}
mysqli_close($con);
}
?>
2、使用PHP轉義函數
- addslashes()函數:能夠將單引號、雙引號、反斜杠和null轉義
- mysql_escape_string()函數、mysql_real_escape_string()函數這個是轉義SQL語句中的符號,php7.x版本的都要變成mysqli
$username=isset($_POST['username'])?addslashes($_POST['username']):'';
$password=isset($_POST['password'])?mysqli_real_escape_string($con,$_POST['password']):'';
3、轉義函數的弊端
因為使用的是UTF-8編碼,不是寬字節編碼,形成的'會被變成%5c%27
Windows下默認的是寬字節的gbk編碼
如果在%5c前面加上一個字符形成一個復雜的漢字,那么單引號仍然會被輸出
六、MySQLi 參數化查詢
在使用參數化查詢的情況下,服務器不會將參數的內容是為SQL指令中的一部分
而是在數據庫完成SQL指令的編譯之后,再代入參數運行
此時就算參數里面有惡意數據
但是此時SQL語句以及編譯完成
就不會被數據庫運行
PHP提供了三種訪問mysql數據庫的拓展:
- MySQL (PHP5.5起,已經廢除)
- MySQLi
- PDO(PHP Data Object PHP數據對象)
PDO和MySQLi提供面向對象的api
MySQLi也存在面向過程的api,所以容易從MySQL轉換到MySQLi
下面是mysqli形式的check_login.php 寫法,新建check_login_mysqli.php
?php
include('con_database.php');
$username=isset($_POST['username'])?$_POST['username']:'';
$password=isset($_POST['password'])?$_POST['password']:'';
if($username==''||$password==''){
echo "script>alert('錯誤!');history.go(-1);/script>";
exit;
}
$sql="select * from users where username=? and passcode=? ;";//問號表示需要一個參數
$stmt=$con->prepare($sql);//預編譯SQL語句
if(!$stmt){
echo 'prepare 執行錯誤';
}
else{
$stmt->bind_param("ss",$username,$password); //為預編譯綁定SQL參數,ss表示兩個字符串
//i——int d——double s——string b——boolean
$stmt->execute();
$result=$stmt->get_result();
$row=$result->fetch_row();
if($row){
session_start();
$_SESSION['username']=$row[1];
echo $row[1]."a href='welcome.php'>歡迎訪問/a>";
}else{
echo "script>alert('登錄失敗!!');history.go(-1);/script>";
}
$stmt->close();
}
$con->close();
?>
一些內容已經標記在代碼的注釋里面
參數化的PHP代碼真的能夠很有效地防止SQL注入。
以上就是萬能密碼的SQL注入漏洞其PHP環境搭建及防御手段的詳細內容,更多關于萬能密碼的SQL注入 PHP環境搭建 防御手段的資料請關注腳本之家其它相關文章!
您可能感興趣的文章:- PHP基于pdo的數據庫操作類【可支持mysql、sqlserver及oracle】
- PHP基于PDO調用sqlserver存儲過程通用方法【基于Yii框架】
- PHP6連接SQLServer2005的三部曲
- PHP連接SQLServer2005的方法
- Win2003+apache+PHP+SqlServer2008 配置生產環境
- php使用pdo連接sqlserver示例分享
- PHP連接SQLServer2005方法及代碼
- Linux下php連接SQLServer 2000數據庫的配置方法
- php5.3中連接sqlserver2000的兩種方法(com與ODBC)
- php插入中文到sqlserver 2008里出現亂碼的解決辦法分享
- PHP連接SQLServer2005的實現方法(附ntwdblib.dll下載)
- PHP連接SQLSERVER 注意事項(附dll文件下載)
- PHP連接SQLServer2005 的問題解決方法