--
PDO Statement
在執行 MySQL 的 SQL 語句時,除了語法正確外還要注意
- 關鍵字混用
- SQL injection
所以查驗使用者帳號、密碼的 SQL 語句可能會長這樣:
1 |
$sql = "SELECT * FROM `user` WHERE `username`='". $mysqli->real_escape_string($username) ."' AND `password`='". $mysqli->real_escape_string($password) ."'"; |
- password 是關鍵字,所以必須使用 ` 包住
- 傳遞變數皆須預防 ' 這類字元中斷正常的 SQL 語句執行,在此使用 MySQLi 的 real_escape_string 方法
如此就可以得到正確的執行結果,又不會因為疏忽產生資訊安全問題。
如果覺得這樣子處理「不酷」的話,那可以考慮預處理的方案,一樣的需求使用預處理的同一行 SQL 語句長這樣:
1 |
$sql = "SELECT * FROM user WHERE username=:username AND password=:password"; |
先讓資料庫得到「結構」,再將資料填入,如此資料庫只會「想辦法填入資料」而不會破壞語法結構,進而產生安全問題。
所以資料庫會比對欄位知道 password 是欄位,後續的 :username 和 :password 的資料會帶入,「不會更動 SQL 語句結構」
也就是以下的紅色部份不會減少也不能增加
SELECT * FROM user WHERE username=:username AND password=:password
因為一般的 SQL injection 就是使用「增加 SQL 語法」破壞了原本的架構來達到目的,例如
SELECT * FROM user WHERE username='root' or '1=1' AND password='xxx'
紅色為使用者填入資料,如此一來 SQL 的語句結構已經改變。
--
如何查驗 SQL 語法
使用預處理想要得到最後執行 SQL ,並不能簡單的使用 echo print 這類的 function ,當然 PDO 本身的函數也沒什麼卵用,例如: PDOStatement::debugDumpParams
唯一可以依靠的方法是直接查看 MySQL 資料庫實際執行的 SQL query
推薦的方式是打開 general_log 後,設定輸出在 mysql 資料庫,原因是雖然說是資料庫但是預設資料表型態是 CSV ,所以可以同時文字檔案和資料庫兩者的優點
1 2 |
SET GLOBAL log_output = 'TABLE'; SET GLOBAL general_log = 'ON'; |
使用 tail 來追蹤最後更新的資料
1 |
sudo tail -f /var/lib/mysq/mysql/general_log.CSV |
-
預處理的好處 mysql prepare statement(mysql预处理)
1 2 |
预处理的意思是先提交sql语句到mysql服务端,执行预编译,客户端执行sql语句时,只需上传输入参数即可。 从 5.1开始,mysql支持服务器端的Prepared Statements,他使用在client/server更有优势的binary protocol。(mysql的传统的协议中,在把数据通过网络传输前,需要把一切数据都转换成strings,这样就比原始数据大很多,最后,在服务器端,还必须把string转化成正确的数据格式而binary protocol去除了转换的开销,在被传输前,所有类型都转换成本地的binary类型,这样就减少了cpu转换的开销跟网络的使用) |
-
PHP 官網文件
PHP 的優點就是官網擁有最完整的說明和資訊,今天花了一點時間在 安全 這個項目上面,對一些安全議題有了更好的認識。
-
1,986 total views, 2 views today