Ⅰ 什麼是sql注入
SQL是操作資料庫數據的結構化查詢語言,網頁的應用數據和後台資料庫中的數據進行交互時會採用SQL。而SQL注入是將Web頁面的原URL、表單域或數據包輸入的參數,修改拼接成SQL語句,傳遞給Web伺服器,進而傳給資料庫伺服器以執行資料庫命令。如Web應用程序的開發人員對用戶所輸入的數據或cookie等內容不進行過濾或驗證(即存在注入點)就直接傳輸給資料庫,就可能導致拼接的SQL被執行,獲取對資料庫的信息以及提權,發生SQL注入攻擊。
Ⅱ 什麼是SQL注入
引 言
隨著B/S模式應用開發的發展,使用這種模式編寫應用程序的程序員也越來越多。但是由於這個行業的入門門檻不高,程序員的水平及經驗也參差不齊,相當大一部分程序員在編寫代碼的時候,沒有對用戶輸入數據的合法性進行判斷,使應用程序存在安全隱患。用戶可以提交一段資料庫查詢代碼,根據程序返回的結果,獲得某些他想得知的數據,這就是所謂的SQL Injection,即SQL注入。
SQL注入是從正常的WWW埠訪問,而且表面看起來跟一般的Web頁面訪問沒什麼區別,所以目前市面的防火牆都不會對SQL注入發出警報,如果管理員沒查看IIS日誌的習慣,可能被入侵很長時間都不會發覺。
但是,SQL注入的手法相當靈活,在注入的時候會碰到很多意外的情況。能不能根據具體情況進行分析,構造巧妙的SQL語句,從而成功獲取想要的數據,是高手與「菜鳥」的根本區別。
根據國情,國內的網站用ASP+Access或SQLServer的佔70%以上,PHP+MySQ佔L20%,其他的不足10%。在本文,我們從分入門、進階至高級講解一下ASP注入的方法及技巧,PHP注入的文章由NB聯盟的另一位朋友zwell撰寫,希望對安全工作者和程序員都有用處。了解ASP注入的朋友也請不要跳過入門篇,因為部分人對注入的基本判斷方法還存在誤區。大家准備好了嗎?Let's Go...
入 門 篇
如果你以前沒試過SQL注入的話,那麼第一步先把IE菜單=>工具=>Internet選項=>高級=>顯示友好 HTTP 錯誤信息前面的勾去掉。否則,不論伺服器返回什麼錯誤,IE都只顯示為HTTP 500伺服器錯誤,不能獲得更多的提示信息。
第一節、SQL注入原理
以下我們從一個網站www.19cn.com開始(註:本文發表前已徵得該站站長同意,大部分都是真實數據)。
在網站首頁上,有名為「IE不能打開新窗口的多種解決方法」的鏈接,地址為:http://www.19cn.com/showdetail.asp?id=49,我們在這個地址後面加上單引號』,伺服器會返回下面的錯誤提示:
Microsoft JET Database Engine 錯誤 '80040e14'
字元串的語法錯誤 在查詢表達式 'ID=49'' 中。
/showdetail.asp,行8
從這個錯誤提示我們能看出下面幾點:
1.網站使用的是Access資料庫,通過JET引擎連接資料庫,而不是通過ODBC。
2.程序沒有判斷客戶端提交的數據是否符合程序要求。
3.該SQL語句所查詢的表中有一名為ID的欄位。
從上面的例子我們可以知道,SQL注入的原理,就是從客戶端提交特殊的代碼,從而收集程序及伺服器的信息,從而獲取你想到得到的資料。
第二節、判斷能否進行SQL注入
看完第一節,有一些人會覺得:我也是經常這樣測試能否注入的,這不是很簡單嗎?
其實,這並不是最好的方法,為什麼呢?
首先,不一定每台伺服器的IIS都返回具體錯誤提示給客戶端,如果程序中加了cint(參數)之類語句的話,SQL注入是不會成功的,但伺服器同樣會報錯,具體提示信息為處理 URL 時伺服器上出錯。請和系統管理員聯絡。
其次,部分對SQL注入有一點了解的程序員,認為只要把單引號過濾掉就安全了,這種情況不為少數,如果你用單引號測試,是測不到注入點的
那麼,什麼樣的測試方法才是比較准確呢?答案如下:
① http://www.19cn.com/showdetail.asp?id=49
② http://www.19cn.com/showdetail.asp?id=49 and 1=1
③ http://www.19cn.com/showdetail.asp?id=49 and 1=2
這就是經典的1=1、1=2測試法了,怎麼判斷呢?看看上面三個網址返回的結果就知道了:
可以注入的表現:
① 正常顯示(這是必然的,不然就是程序有錯誤了)
② 正常顯示,內容基本與①相同
③ 提示BOF或EOF(程序沒做任何判斷時)、或提示找不到記錄(判斷了rs.eof時)、或顯示內容為空(程序加了on error resume next)
不可以注入就比較容易判斷了,①同樣正常顯示,②和③一般都會有程序定義的錯誤提示,或提示類型轉換時出錯。
當然,這只是傳入參數是數字型的時候用的判斷方法,實際應用的時候會有字元型和搜索型參數,我將在中級篇的「SQL注入一般步驟」再做分析。
第三節、判斷資料庫類型及注入方法
不同的資料庫的函數、注入方法都是有差異的,所以在注入之前,我們還要判斷一下資料庫的類型。一般ASP最常搭配的資料庫是Access和SQLServer,網上超過99%的網站都是其中之一。
怎麼讓程序告訴你它使用的什麼資料庫呢?來看看:
SQLServer有一些系統變數,如果伺服器IIS提示沒關閉,並且SQLServer返回錯誤提示的話,那可以直接從出錯信息獲取,方法如下:
http://www.19cn.com/showdetail.asp?id=49 and user>0
這句語句很簡單,但卻包含了SQLServer特有注入方法的精髓,我自己也是在一次無意的測試中發現這種效率極高的猜解方法。讓我看來看看它的含義:首先,前面的語句是正常的,重點在and user>0,我們知道,user是SQLServer的一個內置變數,它的值是當前連接的用戶名,類型為nvarchar。拿一個nvarchar的值跟int的數0比較,系統會先試圖將nvarchar的值轉成int型,當然,轉的過程中肯定會出錯,SQLServer的出錯提示是:將nvarchar值 」abc」 轉換數據類型為 int 的列時發生語法錯誤,呵呵,abc正是變數user的值,這樣,不廢吹灰之力就拿到了資料庫的用戶名。在以後的篇幅里,大家會看到很多用這種方法的語句。
順便說幾句,眾所周知,SQLServer的用戶sa是個等同Adminstrators許可權的角色,拿到了sa許可權,幾乎肯定可以拿到主機的Administrator了。上面的方法可以很方便的測試出是否是用sa登錄,要注意的是:如果是sa登錄,提示是將」dbo」轉換成int的列發生錯誤,而不是」sa」。
如果伺服器IIS不允許返回錯誤提示,那怎麼判斷資料庫類型呢?我們可以從Access和SQLServer和區別入手,Access和SQLServer都有自己的系統表,比如存放資料庫中所有對象的表,Access是在系統表[msysobjects]中,但在Web環境下讀該表會提示「沒有許可權」,SQLServer是在表[sysobjects]中,在Web環境下可正常讀取。
在確認可以注入的情況下,使用下面的語句:
http://www.19cn.com/showdetail.asp?id=49 and (select count(*) from sysobjects)>0
http://www.19cn.com/showdetail.asp?id=49 and (select count(*) from msysobjects)>0
如果資料庫是SQLServer,那麼第一個網址的頁面與原頁面http://www.19cn.com/showdetail.asp?id=49是大致相同的;而第二個網址,由於找不到表msysobjects,會提示出錯,就算程序有容錯處理,頁面也與原頁面完全不同。
如果資料庫用的是Access,那麼情況就有所不同,第一個網址的頁面與原頁面完全不同;第二個網址,則視乎資料庫設置是否允許讀該系統表,一般來說是不允許的,所以與原網址也是完全不同。大多數情況下,用第一個網址就可以得知系統所用的資料庫類型,第二個網址只作為開啟IIS錯誤提示時的驗證
Ⅲ c# 傳參的方式能完全防止sql注入嗎
結論:如果不能夠重用執行計劃,那麼就有SQL注入的風險,因為SQL的語意有可能會變化,所表達的查詢就可能變化。
首先,什麼是注入漏洞攻擊呢?所謂SQL注入,就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字元串,最終達到欺騙伺服器執行惡意的SQL命令。通常的解決方案有過濾敏感字元,比如說過濾掉or, and , select sql等關鍵字,通過參數化查詢解決sql注入漏洞的實例。
所謂的參數化查詢(Parameterized Query 或 Parameterized Statement)是指在設計與資料庫鏈接並訪問數據時,在需要填入數值或數據的地方,使用參數 (Parameter) 來給值,這個方法目前已被視為最有效可預防SQL注入攻擊 (SQL Injection) 的攻擊手法的防禦方式。Microsoft SQL Server 的參數格式是以 "@" 字元加上參數名稱而成.
SQL 引擎的處理流程,大致為:收到指令 -> 編譯SQL生成執行計劃 ->選擇執行計劃 ->執行執行計劃。
參數化查詢主要做了這些事情:
1:參數過濾,對傳入值進行了處理,按字元語義來處理。
2:執行計劃重用
為參數化查詢可以重用執行計劃,並且如果重用執行計劃的話,SQL所要表達的語義就不會變化,所以就可以防止SQL注入,如果不能重用執行計劃,就有可能出現SQL注入,存儲過程也是一樣的道理,因為可以重用執行計劃。
Ⅳ mybatis在傳參時,為什麼#能夠有效的防止sql注入
因為在mybatis中,」${xxx}」這樣格式的參數會直接參與sql編譯,從而不能避免注入攻擊。但涉及到動態表名和列名時,只能使用「${xxx}」這樣的參數格式,所以,這樣的參數需要程序開發者在代碼中手工進行處理來防止注入。
#xxx# 代表xxx是屬性值,map裡面的key或者是你的pojo對象裡面的屬性, ibatis會自動在它的外面加上引號,表現在sql語句是這樣的 where xxx = 'xxx' ;
$xxx$ 則是把xxx作為字元串拼接到sql語句中, 比如 order by topicId , 語句這樣寫 ... order by #xxx# ibatis 就會翻譯成order by 'topicId' (這樣就會報錯) 語句這樣寫 ... order by $xxx$ ibatis 就會翻譯成 order by topicId
#將傳入的數據都當成一個字元串,會對自動傳入的數據加一個雙引號。如:order by #user_id#,如果傳入的值是111,那麼解析成sql時的值為order by "111", 如果傳入的值是id,則解析成的sql為order by "id".
2. $將傳入的數據直接顯示生成在sql中。如:order by $user_id$,如果傳入的值是111,那麼解析成sql時的值為order by user_id, 如果傳入的值是id,則解析成的sql為order by id
所以說#方式能夠很大程度防止sql注入。
Ⅳ 試解釋 SQL 注入攻擊的原理,以及對資料庫可能產生的不利影響。
SQL注入就是攻擊者通過正常的WEB頁面,把自己SQL代碼傳入到應用程序中,從而通過執行非程序員預期的SQL代碼,達到竊取數據或破壞的目的。
當應用程序使用輸入內容來構造動態SQL語句以訪問資料庫時,會發生SQL注入攻擊。如果代碼使用存儲過程,而這些存儲過程作為包含未篩選的用戶輸入的字元串來傳遞,也會發生SQL注入。SQL注入可能導致攻擊者使用應用程序登陸在資料庫中執行命令。如果應用程序使用特權過高的帳戶連接到資料庫,這種問題會變得很嚴重。在某些表單中,用戶輸入的內容直接用來構造(或者影響)動態SQL命令,或者作為存儲過程的輸入參數,這些表單特別容易受到SQL注入的攻擊。而許多網站程序在編寫時,沒有對用戶輸入的合法性進行判斷或者程序中本身的變數處理不當,使應用程序存在安全隱患。這樣,用戶就可以提交一段資料庫查詢的代碼,根據程序返回的結果,獲得一些敏感的信息或者控制整個伺服器,於是SQL注入就發生了。
一般SQL注入
在Web 應用程序的登錄驗證程序中,一般有用戶名(username) 和密碼(password) 兩個參數,程序會通過用戶所提交輸入的用戶名和密碼來執行授權操作。我們有很多人喜歡將SQL語句拼接起來。例如:
Select * from users where username =』 txtusername.Text 』 and password =』 txtpassword.Text 』
其原理是通過查找users 表中的用戶名(username) 和密碼(password) 的結果來進行授權訪問, 在txtusername.Text為mysql,txtpassword.Text為mary,那麼SQL查詢語句就為:
Select * from users where username =』 mysql 』 and password =』 mary 』
如果分別給txtusername.Text 和txtpassword.Text賦值』 or 『1』 = 『1』 --和abc。那麼,SQL 腳本解釋器中的上述語句就會變為:
Select * from users where username =』』or 『1』 = 『1』 -- and password =』abc』
該語句中進行了兩個條件判斷,只要一個條件成立,就會執行成功。而'1'='1'在邏輯判斷上是恆成立的,後面的"--" 表示注釋,即後面所有的語句為注釋語句這樣我們就成功登錄。即SQL注入成功.
如果我們給txtusername.Text賦值為:』;drop table users--即:
Select * from users where username =』』;drop table users-- and password =』abc』
整個用戶表就沒有了,當然這里要猜出數據表名稱。想想是多麼可怕的事情。
好我想大家在這里已經大致明白了一般SQL注入了,試想下您的登錄程序會不會出現我上述的情況。
防範SQL注入
那麼現在大家都在思考怎麼防範SQL注入了這里給出一點個人的建議
1.限制錯誤信息的輸出
這個方法不能阻止SQL注入,但是會加大SQL注入的難度,不會讓注入者輕易得到一些信息,讓他們任意破壞資料庫。SQL Server有一些系統變數,如果我們沒有限制錯誤信息的輸出,那麼注入著可以直接從出錯信息獲取,例如(假定這里用的string即字元類型並可以發生SQL注入):http://www.xxx.com/showdetail.aspx?id=49 and user>0 這句語句很簡單,但卻包含了SQL Server特有注入方法的精髓,。首先看看它的含義:首先,前面的語句是正常的,重點在and user>0,我們知道,user是SQL Server的一個內置變數,它的值是當前連接的用戶名,類型為nvarchar。拿一個nvarchar的值跟int的數0比較,系統會先試圖將nvarchar的值轉成int型,當然,轉的過程中肯定會出錯,SQL Server的出錯提示是:將nvarchar值 」abc」 轉換數據類型為 int 的列時發生語法錯誤,呵呵,abc正是變數user的值,這樣,注入著就拿到了資料庫的用戶名。
眾所周知,SQL Server的用戶sa是個等同Adminstrators許可權的角色,拿到了sa許可權,幾乎肯定可以拿到主機的Administrator了。上面的方法可以很方便的測試出是否是用sa登錄,要注意的是:如果是sa登錄,提示是將」dbo」轉換成int的列發生錯誤,而不是」sa」。
當然注入者還可以輸入不同的信息來得到他們想要的信息 ,上面只是其中一個例子,所以我們要限制錯誤信息的輸出,從而保護我們的資料庫數據,這里我給出.NET限制錯誤信息的方法:
在Web.Config文件中設置
<customErrors mode="On" defaultRedirect="error.aspx">
</customErrors>
這樣當發生錯誤時候就不會講信息泄露給外人。
2.限制訪問資料庫帳號的許可權
對於資料庫的任何操作都是以某種特定身份和相應許可權來完成的,SQL語句執行前,在資料庫伺服器端都有一個用戶許可權驗證的過程,只有具備相應許可權的帳號才可能執行相應許可權內的SQL語句。因此,限制資料庫帳號許可權,實際上就阻斷了某些SQL語句執行的可能。不過,這種方法並不能根本解決SQL注入問題,因為連接資料庫的帳號幾乎總是比其他單個用戶帳號擁有更多的許可權。通過限制貼帳號許可權,可以防止刪除表的攻擊,但不能阻止攻擊者偷看別人的信息。
3.參數化使用命令
參數化命令是在SQL文本中使用佔位符的命令。佔位符表示需要動態替換的數據,它們通過Command對象Parameters集合來傳送。能導致攻擊的SQL代碼可以寫成:
Select * from employee where userID=@userID;
如果用戶輸入: 09105022』OR 『1』=』1,將得不到何記錄,因為沒有一個用戶ID與文本框中輸入的』 09105022』OR 『1』=』1』相等。參數化命令的語法隨提供程序的不同略有差異。對於SQL SERVER提供程序,參數化命令使用命名的佔位符(具有唯一的名字),而對於OLE DB提供程序,每個硬編碼的值被問號代替。使用OLE DB提供程序時,需要保證參數的順序和它們出現在SQL字元串中的位置一致。SQL SERVER提供程序沒有這樣的需求,因為它們用名字和佔位符匹配。
4.調用存儲過程
存儲過程是存儲在資料庫伺服器上的一系列SQL代碼,存儲過程與函數相似,有良好的邏輯封裝結構,可以接收和返回數據。使用存儲過程可以使代碼更易於維護,因為對存儲過程的更改不會導致應用程序的重新編譯,使用存儲過程還可以節省帶寬,提高應用程序性能。因為存儲過程是存儲在資料庫服務端的獨立的封裝體,調用存儲過程可以保證應用程序只執行存儲過程中的固定代碼,從而杜絕SQL語句注入的可能。結合上述所講的參數化命令,可以實現SQL代碼可以實現的任何功能,並進一步提高應用程序的安全等級。
5.限制輸入長度
如果在Web頁面上使用文本框收集用戶輸入的數據,使用文本框的MaxLength屬性來限制用戶輸入過長的字元也是一個很好的方法,因為用戶的輸入不夠長,也就減少了貼入大量腳本的可能性。程序員可以針對需要收集的數據類型作出一個相應的限制策略。
6.URL重寫技術
我們利用URL重寫技術過濾一些SQL注入字元,從而達到防禦SQL注入。因為許多SQL注入是從URL輸入發生的。
7.傳遞參數盡量不是字元
假設我們顯示一篇新聞的頁面,從URL傳遞參數中獲得newid我們可能會隨手寫下下面的代碼:
string newsid = Request.QueryString["newsid"];
string newssql = "select * from news where newsid=" + newsid;
如果傳遞過來的參數是數字字元就沒有問題。但是如果傳遞過來的newsid是「1 delete from table 」的話,那麼sql的值就變成了「select * from table where newsid=1 delete from news」。發生注入成功。但是這里改為
int newsid=int.Parse(Request.QueryString["newsid"].ToString());
string newssql = "select * from news where newsid=" + newsid.Tostring();
這里如果還是上面"1 delete from table "會發生錯誤,因為在轉換時候出現了錯誤
從上面的一個小例子,我們得出在傳遞參數時候盡量不要用字元,免得被注入。
最後是我想擴展下利用URL重寫技術來過濾一些SQL注入字元,首先這里有一篇關於URL重寫的文章,我的基本思想是可以利用它,屏蔽一些危險的SQL注入字元串,這些字元串我們可以人為的設定,畢竟我們還是根據特定的環境設定我們防禦措施。首先我們在MoleRewriter類中的Rewrite函數得到絕對的URL判斷其中是否有危險字元,如果有我們就將它鏈接到一個提示用戶您輸入危險的URL地址。如果不是我們繼續判斷是否觸發了其他的URL重寫的規則,觸發了就重寫。這樣就大致上能在URL上防禦危險字元。
代碼
<configSections>
<section name="RewriterConfig" type="URLRewriter.Config., URLRewriter" />
</configSections>
<RewriterConfig>
<Rules>
<RewriterRule>
<LookFor>~/d(\d+)\.aspx</LookFor>
<SendTo>~/Default_sql_error.aspx</SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>~/d(\d+)\.aspx</LookFor>
<SendTo>~/Default2.aspx</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
<httpMoles>
<add type="URLRewriter.MoleRewriter, URLRewriter" name="MoleRewriter" />
</httpMoles>
上面是要在web.config配置文件加上的內容,這里我加上了兩個重寫規則,第一個規則是專門針對滿足這個正則表達式的頁面URL查看是否有危險字元,有危險字元就會發送到Default_sql_error.aspx頁面,來示警。這里我假定會發生危險字元注入的頁面時以"d"字元開頭並加上數字的頁面(這里我們可以根據實際情況自己定義,看哪些頁面URL容易發生我們就制定這些頁面的正則表達式),第二個是一般URL重寫。因為這里我採用的是HTTP模塊執行URL重寫,所以加上<httpMoles></httpMoles>這一塊。
第二步就是要在重寫Rewrite函數了
代碼
protected override void Rewrite(string requestedPath, System.Web.HttpApplication app)
{
// 獲得配置規則
RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules;
//獲得絕對的URL
Uri url = app.Request.Url;
// 判斷url 中是否含有SQL 注入攻擊敏感的字元或字元串,如果存在,sqlatFlag = 1 ;
string urlstr = url.AbsoluteUri;
int sqlatFlag = 0;
//這里我們根據實際情況隨便編寫,我這里這是隨便列舉了幾個
string words = "exec ,xp ,sp ,declare ,cmd ,Union ,--";
string[] split = words.Split(',');
foreach (string s in split)
{
if (urlstr.IndexOf(s.ToUpper()) > 0)
{
sqlatFlag = 1;
break;
}
}
if (sqlatFlag == 1)
{
// 創建regex
Regex re = new Regex(rules[0].SendTo, RegexOptions.IgnoreCase);
// 找到匹配的規則,進行必要的替換
string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.ToString());
// 重寫URL
RewriterUtils.RewriteUrl(app.Context, sendToUrl);
}
else
{
// 遍歷除rules[0 ]以外的其他URL 重寫規則
for (int i = 1; i < rules.Count; i++)
{
// 獲得要查找的模式,並且解析URL (轉換為相應的目錄)
string lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "$";
// 創建regex
Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
// 查看是否找到了匹配的規則
if (re.IsMatch(requestedPath))
{
// 找到了匹配的規則, 進行必要的替換
string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));
// 重寫URL
RewriterUtils.RewriteUrl(app.Context, sendToUrl);
break;
// 退出For 循環
}
}
}
}
那麼下一步就是檢驗例子了
首先我們輸入http://localhost:4563/web/Default.aspx?id=1;--
這樣http://localhost:4563/web/Default.aspx?id=1;-- 沒有改變,就會顯示Default_sql_error.aspx里內容「您輸入了危險字元」。
再輸入http://localhost:4563/web/D11.aspx就會顯示 Default2.aspx內容,因為這里觸發了第二個重寫規則
Ⅵ 針對sql注入攻擊,有哪些防範措施
SQL注入攻擊的危害很大,而且防火牆很難對攻擊行為進行攔截,主要的SQL注入攻擊防範方法,具體有以下幾個方面。
1、分級管理
對用戶進行分級管理,嚴格控制用戶的許可權,對於普通用戶,禁止給予資料庫建立、刪除、修改等相關許可權,只有系統管理員才具有增、刪、改、查的許可權。
2、參數傳值
程序員在書寫SQL語言時,禁止將變數直接寫入到SQL語句,必須通過設置相應的參數來傳遞相關的變數。從而抑制SQL注入。數據輸入不能直接嵌入到查詢語句中。同時要過濾輸入的內容,過濾掉不安全的輸入數據。或者採用參數傳值的方式傳遞輸入變數,這樣可以最大程度防範SQL注入攻擊。
3、基礎過濾與二次過濾
SQL注入攻擊前,入侵者通過修改參數提交and等特殊字元,判斷是否存在漏洞,然後通過select、update等各種字元編寫SQL注入語句。因此防範SQL注入要對用戶輸入進行檢查,確保數據輸入的安全性,在具體檢查輸入或提交的變數時,對於單引號、雙引號、冒號等字元進行轉換或者過濾,從而有效防止SQL注入。
當然危險字元有很多,在獲取用戶輸入提交參數時,首先要進行基礎過濾,然後根據程序的功能及用戶輸入的可能性進行二次過濾,以確保系統的安全性。
4、使用安全參數
SQL資料庫為了有效抑制SQL注入攻擊的影響。在進行SQLServer資料庫設計時設置了專門的SQL安全參數。在程序編寫時應盡量使用安全參數來杜絕注入式攻擊,從而確保系統的安全性。
5、漏洞掃描
為了更有效地防範SQL注入攻擊,作為系統管理除了設置有效的防範措施,更應該及時發現系統存在SQL攻擊安全漏洞。系統管理員可以采購一些SQL漏洞掃描工具,通過專業的掃描工具,可以及時的掃描到系統存在的相應漏洞。
6、多層驗證
現在的網站系統功能越來越龐大復雜。為確保系統的安全,訪問者的數據輸入必須經過嚴格的驗證才能進入系統,驗證沒通過的輸入直接被拒絕訪問資料庫,並且向上層系統發出錯誤提示信息。同時在客戶端訪問程序中驗證訪問者的相關輸入信息,從而更有效的防止簡單的SQL注入。但是如果多層驗證中的下層如果驗證數據通過,那麼繞過客戶端的攻擊者就能夠隨意訪問系統。因此在進行多層驗證時,要每個層次相互配合,只有在客戶端和系統端都進行有效的驗證防護,才能更好地防範SQL注入攻擊。
7、資料庫信息加密
傳統的加解密方法大致分為三種:對稱加密、非對稱加密、不可逆加密。
Ⅶ 參數化之後還是有sql注入,求教
首先:我們要了解SQL收到一個指令後所做的事情:
具體細節可以查看文章:Sql Server 編譯、重編譯與執行計劃重用原理
在這里,我簡單的表示為: 收到指令 -> 編譯SQL生成執行計劃 ->選擇執行計劃 ->執行執行計劃。
具體可能有點不一樣,但大致的步驟如上所示。
接著我們來分析為什麼拼接SQL 字元串會導致SQL注入的風險呢?
首先創建一張表Users:
CREATE TABLE [dbo].[Users](
[Id] [uniqueidentifier] NOT NULL,
[UserId] [int] NOT NULL,
[UserName] [varchar](50) NULL,
[Password] [varchar](50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
插入一些數據:
INSERT INTO [Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES (NEWID(),1,'name1','pwd1');
INSERT INTO [Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES (NEWID(),2,'name2','pwd2');
INSERT INTO [Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES (NEWID(),3,'name3','pwd3');
INSERT INTO [Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES (NEWID(),4,'name4','pwd4');
INSERT INTO [Test].[dbo].[Users]([Id],[UserId],[UserName],[Password])VALUES (NEWID(),5,'name5','pwd5');
假設我們有個用戶登錄的頁面,代碼如下:
驗證用戶登錄的sql 如下:
select COUNT(*) from Users where Password = 'a' and UserName = 'b'
這段代碼返回Password 和UserName都匹配的用戶數量,如果大於1的話,那麼就代表用戶存在。
本文不討論SQL 中的密碼策略,也不討論代碼規范,主要是講為什麼能夠防止SQL注入,請一些同學不要糾結與某些代碼,或者和SQL注入無關的主題。
可以看到執行結果:
這個是SQL profile 跟蹤的SQL 語句。
注入的代碼如下:
select COUNT(*) from Users where Password = 'a' and UserName = 'b' or 1=1—'
這里有人將UserName設置為了 「b' or 1=1 –」.
實際執行的SQL就變成了如下:
可以很明顯的看到SQL注入成功了。
很多人都知道參數化查詢可以避免上面出現的注入問題,比如下面的代碼:
class Program
{
private static string connectionString = "Data Source=.;Initial Catalog=Test;Integrated Security=True";
static void Main(string[] args)
{
Login("b", "a");
Login("b' or 1=1--", "a");
}
private static void Login(string userName, string password)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
//為每一條數據添加一個參數
comm.CommandText = "select COUNT(*) from Users where Password = @Password and UserName = @UserName";
comm.Parameters.AddRange(
new SqlParameter[]{
new SqlParameter("@Password", SqlDbType.VarChar) { Value = password},
new SqlParameter("@UserName", SqlDbType.VarChar) { Value = userName},
});
comm.ExecuteNonQuery();
}
}
}
實際執行的SQL 如下所示:
exec sp_executesql N'select COUNT(*) from Users where Password = @Password and UserName = @UserName',N'@Password varchar(1),@UserName varchar(1)',@Password='a',@UserName='b'
exec sp_executesql N'select COUNT(*) from Users where Password = @Password and UserName = @UserName',N'@Password varchar(1),@UserName varchar(11)',@Password='a',@UserName='b'' or 1=1—'
可以看到參數化查詢主要做了這些事情:
1:參數過濾,可以看到 @UserName='b'' or 1=1—'
2:執行計劃重用
因為執行計劃被重用,所以可以防止SQL注入。
首先分析SQL注入的本質,
用戶寫了一段SQL 用來表示查找密碼是a的,用戶名是b的所有用戶的數量。
通過注入SQL,這段SQL現在表示的含義是查找(密碼是a的,並且用戶名是b的,) 或者1=1 的所有用戶的數量。
可以看到SQL的語意發生了改變,為什麼發生了改變呢?,因為沒有重用以前的執行計劃,因為對注入後的SQL語句重新進行了編譯,因為重新執行了語法解析。所以要保證SQL語義不變,即我想要表達SQL就是我想表達的意思,不是別的注入後的意思,就應該重用執行計劃。
如果不能夠重用執行計劃,那麼就有SQL注入的風險,因為SQL的語意有可能會變化,所表達的查詢就可能變化。
在SQL Server 中查詢執行計劃可以使用下面的腳本:
DBCC FreeProccache
select total_elapsed_time / execution_count 平均時間,total_logical_reads/execution_count 邏輯讀,
usecounts 重用次數,SUBSTRING(d.text, (statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(text)
ELSE statement_end_offset END
- statement_start_offset)/2) + 1) 語句執行 from sys.dm_exec_cached_plans a
cross apply sys.dm_exec_query_plan(a.plan_handle) c
,sys.dm_exec_query_stats b
cross apply sys.dm_exec_sql_text(b.sql_handle) d
--where a.plan_handle=b.plan_handle and total_logical_reads/execution_count>4000
ORDER BY total_elapsed_time / execution_count DESC;
Ⅷ 關於SQL注入。
我還沒進公司時,網站平均15天被注入一次,我進公司以後,大力整改,至今3個月,未見被注入。
我告訴你我的方法。
總結起來就是:關鍵詞屏蔽或替換 + 參數法sql。
1.封裝一個類,用來將傳入的參數進行關鍵詞的屏蔽和替換(像ID之類的參數,可以屏蔽關鍵詞的就完全屏蔽,像textarea這樣不能完全屏蔽的,就把關鍵詞替換,如將半形的'替換成全形』。還要限制參數的字數(很重要)
2.將所有需要和資料庫打交道的地方全部進行參數化sql。
如將sql="select * from table where id='"+value+"'"
改sql="select * from table where id=@id"
寫一個類,裡面專門存放參數法sql的各種方法,雖然會麻煩一些,但是非常非常有效,可以杜絕絕大多數sql注入。
這樣,雙管其下,基本可以防止sql注入了