存取 MySQL 的客戶端應用程式應使用以下指南,以避免錯誤解譯外部資料或暴露敏感資訊。
存取 MySQL 的應用程式不應信任使用者輸入的任何資料,使用者可能會嘗試透過在 Web 表單、URL 或您建置的任何應用程式中輸入特殊或跳脫字元序列來欺騙您的程式碼。請務必在使用者嘗試透過輸入類似 ; DROP DATABASE mysql;
的內容到表單中來執行 SQL 注入時,您的應用程式仍保持安全。這是一個極端的範例,但如果您不為此做好準備,駭客使用類似的技術可能會導致重大的安全漏洞和資料遺失。
一個常見的錯誤是只保護字串資料值。請記住也要檢查數值資料。如果應用程式在使用者輸入值 234
時產生類似 SELECT * FROM table WHERE ID=234
的查詢,則使用者可以輸入值 234 OR 1=1
以導致應用程式產生查詢 SELECT * FROM table WHERE ID=234 OR 1=1
。結果,伺服器會檢索資料表中的每一列。這會暴露每一列並導致伺服器負載過高。防止此類攻擊的最簡單方法是在數值常數周圍使用單引號:SELECT * FROM table WHERE ID='234'
。如果使用者輸入額外資訊,則所有資訊都會成為字串的一部分。在數值內容中,MySQL 會自動將此字串轉換為數字,並從中去除任何尾隨的非數值字元。
有時人們認為,如果資料庫只包含公開可用的資料,則不需要保護。這是錯誤的。即使允許顯示資料庫中的任何列,您仍然應該防止阻斷服務攻擊(例如,基於前一段中導致伺服器浪費資源的技術)。否則,您的伺服器將對合法使用者沒有反應。
檢查清單
啟用嚴格 SQL 模式,以告知伺服器對其接受的資料值更加嚴格。請參閱第 7.1.11 節,「伺服器 SQL 模式」。
嘗試在所有 Web 表單中輸入單引號和雙引號 (
'
和"
)。如果您收到任何 MySQL 錯誤,請立即調查問題。嘗試透過將
%22
("
)、%23
(#
) 和%27
('
) 新增至動態 URL 來修改它們。嘗試使用先前範例中顯示的字元,將動態 URL 中的資料類型從數值修改為字元類型。您的應用程式應該安全地抵禦這些和類似的攻擊。
嘗試在數值欄位中輸入字元、空格和特殊符號,而不是數字。您的應用程式應該在將它們傳遞給 MySQL 之前移除它們,否則會產生錯誤。將未檢查的值傳遞給 MySQL 非常危險!
在將資料傳遞給 MySQL 之前,請檢查資料的大小。
讓您的應用程式使用與您用於管理目的的使用者名稱不同的使用者名稱連線到資料庫。不要給予您的應用程式它們不需要的任何存取權限。
許多應用程式介面 (API) 提供了在資料值中逸出特殊字元的方法。正確使用此方法可以防止應用程式使用者輸入導致應用程式產生與您預期效果不同的陳述式的值。
MySQL SQL 陳述式:使用 SQL 預備陳述式,且僅透過佔位符號接受資料值;請參閱第 15.5 節,「預備陳述式」。
MySQL C API:使用
mysql_real_escape_string_quote()
API 呼叫。或者,使用 C API 預備陳述式介面,且僅透過佔位符號接受資料值;請參閱C API 預備陳述式介面。MySQL++:對查詢串流使用
escape
和quote
修飾詞。PHP:使用
mysqli
或pdo_mysql
擴充功能,而不是較舊的ext/mysql
擴充功能。較佳的 API 支援改良的 MySQL 驗證通訊協定和密碼,以及具有佔位符號的預備陳述式。另請參閱MySQL 和 PHP。如果必須使用較舊的
ext/mysql
擴充功能,則對於逸出,請使用mysql_real_escape_string_quote()
函式,而不是mysql_escape_string()
或addslashes()
,因為只有mysql_real_escape_string_quote()
可以感知字元集;當使用(無效的)多位元組字元集時,其他函式可以被「略過」。Perl DBI:使用佔位符號或
quote()
方法。Java JDBC:使用
PreparedStatement
物件和佔位符號。
其他程式設計介面可能具有類似的功能。
應用程式有責任攔截執行帶有 MySQL 資料庫伺服器的 SQL 陳述式時發生的錯誤,並適當處理這些錯誤。
MySQL 錯誤中傳回的資訊並非無故,因為這些資訊是使用應用程式偵錯 MySQL 的關鍵。例如,若不提供有關哪些資料庫、表格及其他物件牽涉到問題的資訊,則幾乎不可能偵錯常見的 10 向聯結 SELECT
陳述式。因此,MySQL 錯誤有時必須包含對這些物件名稱的參照。
當應用程式從 MySQL 收到此類錯誤時,一種簡單但不安全的方法是攔截錯誤,並逐字顯示給用戶端。但是,洩露錯誤資訊是一種已知的應用程式漏洞類型 (CWE-209),應用程式開發人員必須確保應用程式沒有此漏洞。
例如,顯示如下訊息的應用程式會向用戶端暴露資料庫名稱和表格名稱,這些資訊可能是用戶端試圖利用的資訊
ERROR 1146 (42S02): Table 'mydb.mytable' doesn't exist
相反地,當應用程式從 MySQL 收到此類錯誤時,正確的行為是將包括錯誤資訊在內的適當資訊記錄到只有受信任人員才能存取的安全稽核位置。應用程式可以向使用者傳回更通用的資訊,例如 「內部錯誤」。