(整篇文章廢話很多,但其實是為了新手能更好的了解這個sql注入是什么,需要學習的是文章最后關於如何預防sql注入)
(整篇文章廢話很多,但其實是為了新手能更好的了解這個sql注入是什么,需要學習的是文章最后關於如何預防sql注入)
(整篇文章廢話很多,但其實是為了新手能更好的了解這個sql注入是什么,需要學習的是文章最后關於如何預防sql注入)
重要的事情說三遍 ^-^
一.什么是SQL注入
- 如何理解sql注入?
sql注入是一種將sql代碼添加到輸入參數中,傳遞到sql服務器解析並執行的一種攻擊手法
示例:
本地一段代碼為get獲取id值,輸出實際執行sql以及查詢id對應內容。
當id值傳為1時,執行結果如下:
這是正常請求情況,而當我們往id傳的參數中注入sql代碼時,便可以根據自己需求查詢自己想要獲取的內容,例如:
id值傳參數為 -1 OR 1=1 ,此時執行代碼中id值帶入了我們傳參數的sql代碼, 1=1 為真,OR 1=1便會查出表中所有的內容。 達到攻擊目的。
所以sql注入攻擊就是輸入參數未經過濾,直接拼接到sql語句中,解析執行,達到預想之外的行為。
- sql注入是如何產生的?
1.web開發人員無法保證所有的輸入都已經過濾
2.攻擊者利用發送給sql服務器的輸入數據構造可執行代碼
3.數據庫未作相應的安全配置(對web應用設置特定的數據庫賬號,而不使用root或管理員賬號,特定數據庫賬號給予一些簡單操作的權限,回收一些類似drop的操作權限)
二.如何尋找SQL注入漏洞
- 如何尋找sql注入漏洞?
(借助邏輯推理)
1.識別web應用中所有輸入點
web應用中的輸入包含三點:get,post,http頭信息
2.了解哪些類型請求會觸發異常
<1>比如get信息請求,獲取文章id返回文章內容,當在get傳遞的id參數值后加“"”雙引號,請求結果就會出現數據庫異常錯誤.
<2>post請求示例,提交文章標題和文章內容,添加入庫,正常情況是:
提交入庫的sql如下:
但是當我們把標題輸入為 標題" ,提交后便會觸發sql異常:
3.檢測服務器響應中的異常
三.如何進行SQL注入攻擊
(這里介紹兩種主要的sql注入攻擊)
- 數字注入
sql中where條件的參數值為數字的語句進行修改攻擊。
也就是上面提到的 id = -1 OR 1=1
- 字符串注入
以一個用戶登陸為例:
<1.>以sql中的注釋符號‘#’來實現攻擊:
我們只需要知道數據庫中的某一個用戶的用戶名,比如peter,在表單輸入時,在用戶名列輸入 “peter'#”,密碼隨意輸入,點擊登陸后便會顯示登陸成功,輸出的sql語句為:
如上,用戶名拼接“ ‘# ”說明:( ’ 單引號用來閉合用戶名的輸入,#井號用來注釋掉后面的查詢條件)
<2.>以注釋符號‘ -- ’來實現攻擊:
還是一樣只需要知道數據庫中的某一個用戶的用戶名,比如peter,在表單輸入時,在用戶名列輸入 “peter'-- ” (雙中橫線后還有空格),密碼隨意輸入,點擊登陸后便會顯示登陸成功,輸出的sql語句為:
跟上面的#號攻擊一樣,sql語句執行都會跳過密碼驗證,在不需要知道密碼的情況下就可以實現登陸。
四.如何預防SQL注入(分三種方法講解)
- 嚴格檢查輸入變量的類型和格式
1.對數字類型的參數id的強校驗(empty()為空驗證和is_numeric()進行數字驗證)
2.對字符串類型的參數的校驗 (正則校驗)
例如上面提到的登陸系統的用戶名的校驗,比如校驗規則為 六位數字以上的字母或者數字,可以用preg_match("/^[a-zA-Z0-9]{6,}$/")
- 過濾和轉義特殊字符
一. 用php函數addslashes()進行轉義(addslashes函數使用方法詳解點這里):
一般是對這些特殊字符進行轉義:
1.單引號(') 2.雙引號(") 3.反斜杠(\) 4. NULL
二. 用mysqli的php擴展中的函數 mysqli_real_escape_string()
注:這兩種方法只做簡單介紹用,但其實現在的黑客已經可以輕而易舉的繞過這些函數,包括一些字符串替換 str_replace() 等,表着急,繼續往下看,下面介紹的第三種防sql注入的方法還是比較實在,如果需要還是直接用下面的方法吧~
- 利用預編譯機制(mysqli 和 pdo)
一. DML語句預編譯(mysqli示例和pdo示例)
mysqli預編譯示例
<?php $mysqli = new mysqli("localhost","root","root","dbname"); $mysqli->query("set names utf8"); $sql = 'insert into user(id,name,age,email) values (?,?,?,?)'; $mysqli_stmt = $mysqli->prepare($sql); $id = 2; $name = 'kung'; $age = 28; $email = 'ohdas@163.com'; $mysqli_stmt->bind_param('isis',$id,$name,$age,$email); $res = $mysqli_stmt->execute(); if(!$res){ echo 'error'.$mysqli_stmt->error; exit; }else{ echo 'ok'; } $id = 3; $name = 'xiaoyu'; $age = 28; $email = 'kung-yu@163.com'; $mysqli_stmt->bind_param('isis',$id,$name,$age,$email); $res = $mysqli_stmt->execute(); if(!$res){ echo 'error'.$mysqli_stmt->error; exit; }else{ echo 'ok'; } ?>
PDO預編譯示例
<?php $dns = 'mysql:dbname=dbname;host=127.0.0.1'; $user = 'root'; $password = 'root'; try{ $pdo = new PDO($dns,$user,$password); } catch(PDOException $e){ echo $e->getMessage(); } $pdo->query("set names utf8"); $sql = 'inser into user values(:id,:name,:age,:email)'; $pdo_stmt = $pdo->prepare($sql); $id = 2; $name = 'kung'; $age = 27; $email = 'ohdas@163.com'; $pdo_stmt->bindParam(':id',$id); $pdo_stmt->bindParam(':name',$name); $pdo_stmt->bindParam(':age',$age); $pdo_stmt->bindParam(':email',$email); $pdo_stmt->execute(); ?>
二. DQL語句預編譯(mysqli示例)
<?php $mysqli = new mysqli("localhost","root","root","dbname"); $mysqli->query("set names utf8"); $sql = " select id,name from user where id > ?"; $mysqli_stmt = $mysqli->prepare($sql); $id = 1; $mysqli_stmt->bind_param('i',$id); $mysqli_stmt->bind_result($id,$name); $mysqli_stmt->execute(); while($mysqli_stmt->fetch()){ echo $id.'--'.$name; } $mysqli_stmt->close(); $mysqli->close(); ?>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
整篇文章內容是看慕課網視頻寫的筆記: 鏈接戳我
最后預編譯的代碼示例摘自: https://blog.csdn.net/kissxia/article/details/46623097
作者:戈丫汝
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!