存取 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 錯誤,請立即調查問題。嘗試透過在動態 URL 中新增
%22
("
)、%23
(#
) 和%27
('
) 來修改它們。嘗試使用先前範例中顯示的字元,將動態 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 收到此類錯誤時,適當的行為是將適當的資訊(包括錯誤資訊)記錄到只有受信任人員才能存取的安全稽核位置。應用程式可以向使用者傳回更通用的內容,例如「內部錯誤」。