用戶在搜索框輸入 ___、.__ 等包含下劃線的關鍵字時,返回了數據表中的所有記錄。
MySQL LIKE 模式匹配中,兩個通配符:
| 符號 | 含義 |
|---|---|
% | 匹配任意長度字符(含 0 個) |
_ | 匹配任意單個字符 |
___ 即匹配任意 3 個字符的字符串,.__ 匹配任意 3 個字符(第一個任意字符 + 兩個下劃線),導致幾乎所有記錄命中。
MySQL String Comparison Functions 明確定義 _ 為單字符通配符。
$keyword = $_POST['keyword'];
// 轉義 % 和 _
$keyword = str_replace(['%', '_'], ['\\%', '\\_'], $keyword);
$sql = "SELECT * FROM products WHERE name LIKE '%{$keyword}%'";
String keyword = request.getParameter("keyword");
keyword = keyword.replace("%", "\\%").replace("_", "\\_");
String sql = "SELECT * FROM products WHERE name LIKE ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "%" + keyword + "%");
SELECT * FROM products WHERE name LIKE '%\_\_\_%' ESCAPE '\\';
-- 指定反斜槓為轉義字符
經驗證,早期流行的 PHP 論壇程序 IPB、phpBB 均存在此漏洞;vBulletin 已內置過濾。建議所有使用 LIKE 的應用審查用戶輸入處理邏輯。
escapeLikeWildcards() 方法%、_ 的測試用例| 數據庫 | 單字符通配符 | 轉義語法 |
|---|---|---|
| MySQL | _ | \_ 或 ESCAPE '\' |
| PostgreSQL | _ | \_ 或 ESCAPE '\' |
| SQL Server | _ | [_] 或 ESCAPE '\' |
| Oracle | _ | ESCAPE '\' |
| SQLite | _ | ESCAPE '\' |
幾乎所有主流關係型數據庫均遵循 SQL 標準,_ 為單字符通配符,開發時務必注意。