如何防 SQL 注入?
一、什麼是 SQL 注入?
SQL 注入(英語:SQL injection),也稱 SQL 注入或 SQL 注碼,是發生於應用程序與數據庫層的安全漏洞。簡而言之,是在輸入的字符串之中注入 SQL 指令,在設計不良的程序當中忽略了字符檢查,那麼這些注入進去的惡意指令就會被數據庫服務器誤認爲是正常的 SQL 指令而執行,因此遭到破壞或是入侵。
有部分人認爲 SQL 注入是隻針對 Microsoft SQL Server,但只要是支持處理 SQL 指令的數據庫服務器,都有可能受到此種手法的攻擊。
二、應用程序注入的高風險情況有哪些?
-
- 在應用程序中使用字符串聯結方式或聯合查詢方式組合 SQL 指令。
-
- 在應用程序鏈接數據庫時使用權限過大的賬戶(例如很多開發人員都喜歡用最高權限的系統管理員賬戶(如常見的 root,sa 等)連接數據庫)。
-
- 在數據庫中開放了不必要但權力過大的功能。
-
- 太過於信任用戶所輸入的資料,未限制輸入的特殊字符,以及未對用戶輸入的資料做潛在指令的檢查。
三、SQL 注入的作用原理是什麼?
-
1.SQL 命令可查詢、插入、更新、刪除等,命令的串接。而以分號字符爲不同命令的區別。(原本的作用是用於 SubQuery 或作爲查詢、插入、更新、刪除…… 等的條件式)。
-
2.SQL 命令對於傳入的字符串參數是用單引號字符所包起來。(但連續 2 個單引號字符,在 SQL 數據庫中,則視爲字符串中的一個單引號字符)
-
3.SQL 命令中,可以注入註解(連續 2 個減號字符 – 後的文字爲註解,或 “/” 與 “/” 所包起來的文字爲註解)。
-
- 因此,如果在組合 SQL 的命令字符串時,未針對單引號字符作轉義處理的話,將導致該字符變量在填入命令字符串時,被惡意竄改原本的 SQL 語法的作用。
四、SQL 注入可能造成哪些傷害?
-
- 資料表中的資料外泄,例如企業及個人機密資料,賬戶資料,密碼等。
-
- 數據結構被黑客探知,得以做進一步攻擊(例如 SELECT * FROM sys.tables)。
-
- 數據庫服務器被攻擊,系統管理員賬戶被竄改(例如 ALTER LOGIN sa WITH PASSWORD=’xxxxxx’)。
-
- 獲取系統較高權限後,有可能得以在網頁加入惡意鏈接、惡意代碼以及 Phishing 等。
-
- 經由數據庫服務器提供的操作系統支持,讓黑客得以修改或控制操作系統。
-
- 攻擊者利用數據庫提供的各種功能操縱文件系統,寫入 Webshell,最終導致攻擊者攻陷系統。
-
- 破壞硬盤資料,癱瘓全系統。
-
- 獲取系統最高權限後,可針對企業內部的任一管理系統做大規模破壞,甚至讓其企業倒閉。
-
- 網站主頁被竄改,導致聲譽受到損害。
五、在 Java 開發中如何避免 SQL 注入?
-
- 在使用 MyBatis 的時候,通常使用 #{parm} 作爲傳參能很大程度避免 SQL 注入。
-
- 針對 Controller 相關參數做嚴格校驗與過濾也能很大程度避免 SQL 注入。
Java 防 SQL 注入代碼如下:
public class SqlUtil {
/**
* 定義常用的 sql關鍵字
*/
public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
/**
* 僅支持字母、數字、下劃線、空格、逗號、小數點(支持多個字段排序)
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 檢查字符,防止注入繞過
*/
public static String escapeOrderBySql(String value) {
if (StringUtil.isNotEmpty(value) && !isValidOrderBySql(value)) {
throw new UtilException("參數不符合規範,不能進行查詢");
}
return value;
}
/**
* 驗證 order by 語法是否符合規範
*/
public static boolean isValidOrderBySql(String value) {
return value.matches(SQL_PATTERN);
}
/**
* SQL關鍵字檢查
*/
public static void filterKeyword(String value) {
if (StringUtil.isEmpty(value)) {
return;
}
String[] sqlKeywords = StringUtil.split(SQL_REGEX, "\\|");
for (String sqlKeyword : sqlKeywords) {
if (StringUtil.indexOfIgnoreCase(value, sqlKeyword) > -1) {
throw new UtilException("參數存在SQL注入風險");
}
}
}
}
完整源代碼:
https://github.com/developers-youcong/yc-framework/blob/main/yc-common/yc-common-core/src/main/java/com/yc/common/core/base/utils/sql/SqlUtil.java
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/0iUObj6aAYJ69xlGETBITA