SQL注入就是攻擊者在前端的表單輸入中,或者 API 的傳參時,按照 SQL 的語法,人為地加入一段代碼,改變原有的SQL 邏輯,來跳過驗證,篡改或者刪除數據庫,達到攻擊者的目的的過程。
SQL注入攻擊會造成非常嚴重的后果,舉個例子:
select user_id,user_name from user_info where user_name = '$a' and passwd = '$pwd'
一般情況下,參數userName,pwd 都是從前端的界面中的文本框輸入的,但是:
如果攻擊者在 pwd 的文本框中輸入以下字符串:
xxx' or 1=1
那么到了后端,SQL 拼接的情況就成了:
select user_id,user_name from user_info where user_name = '$a' and passwd = 'xxx' or 1 =1
這樣就跳過了密碼驗證。
如果攻擊者在 pwd 的文本框中輸入以下字符串:
xxx' or 1=1 ; delete from user_info
那么到了后端,SQL 拼接的情況就成了:
select user_id,user_name from user_info where user_name = '$a' and passwd = 'xxx' or 1 =1 ; delete from user_info ;
一執行,不但跳過的驗證,還刪除了所有的用戶信息,可以想象下,如果是 drop database 呢,整個數據庫立即消失。
如何防止SQL注入?
方法一:仍使用字符串拼接的方法,但對SQL進行案例檢查。
檢查的方法包括:
- 限制單條 SQL 語句,對應SQL語句中不能有分號。
- 防止將 where 條件失效,對應SQL語句中不能出現SQL語法中的注釋符號,如 -- ,/**/ 等。
- 禁止出現危險操作,對應SQL語句中不能出現 delete、drop、create 等關鍵詞。
- 在不影響 SQL功能的前提下,禁止SQL語句中出現 or 這種可以改變邏輯規則的詞
以上檢查操作在 Python 中使用正則表達式一句話就可以搞定:
if re.findall(r';|--|/*|delete|drop|create|or|*/',sql.lower()): return False # False 說明SQL是不安全的
方法二:使用數據庫 API 的預編譯功能,參數單獨做為參數傳遞,以 ibm_db 為例:
import ibm_db conn = ibm_db.connect("database","username","password") sql = "SELECT EMPNO, LASTNAME FROM EMPLOYEE WHERE EMPNO > ? AND EMPNO < ?" stmt = ibm_db.prepare(conn, sql) max = 50 min = 0 # Explicitly bind parameters ibm_db.bind_param(stmt, 1, min) ibm_db.bind_param(stmt, 2, max) ibm_db.execute(stmt) # Process results # Invoke prepared statement again using dynamically bound parameters param = max, min, ibm_db.execute(stmt, param)
總結:
方法二僅適用于將 where 條件中的字段值做為參數傳遞的情況,假如表名是通過參數傳遞,或者 select 中的字段名也是通過參數傳遞的話,只能使用方法一,因此只要 SQL 語句中對防止注入的安全性檢查做的好,方法一更靈活,適用范圍更廣。