PDF下載
安全性:URL查尋字串加密
作者:黃偉榮
開發工具:Visual Studio 2005
議題
URL的查尋字串是很容易作為被功擊的地方,而是很容易被程式設計師忽略而使資訊洩漏,本文將介紹常見的功擊和防範。
什麼是URL查尋字串
在 URL 中,查詢資訊與路徑資訊是以問號 (?) 分隔,而名稱/值組則是以等號 (=) 分隔。
如Http://localhost/index.aspx?ID=S01,其中Http://localhost/index.aspx代表的是路徑,有一個ID的資訊,在ASP.NET中讀取URL查尋字串的方法是Request.QuestString方法。
下列程式碼將範例Request.QuestString方法如何讀取URL的字串
public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string ID; int Count; string[] Keys; //使用索引鍵來取得或設定項目 ID = Request.QueryString["ID"]; //使用索引來取得或設定項目 ID = Request.QueryString[0]; //取得所有的索引鍵 Keys = Request.QueryString.AllKeys; //取得數目 Count = Request.QueryString.Count; } } |
資訊被非法取得
上圖是我模擬如何被非法取得資訊,請注意網址列的部分,URL有加上EmployeeID的查尋字串,EmployeeID=0代表了顯示EmployeeID為0的個人資料,只要將0修改成別的數字如1,就可以取得EmployeeID為1的個人資料,很多人都是這樣設計網站,包括很多書都是這樣寫,因為參數的傳遞非常的容易,很容易撰寫程式碼,請不要抱者僥倖的心態以為使用者不會注意這個小細節,而且這樣作法除了很容易被非法取得資訊外,也是常被SQL Injection[1]功擊的地方。
為查尋字串加一道鎖
原來使用URL來傳遞參數,這麼不安全,那是不是就不要使用了呢?以上一個例子EmployeeID=0從字面上就很容易猜出他的作用,那如果我把EmployeeID=0加以編碼變成EmployeeID=MAA1或 A=AHAAbABvAHkAZQBlAEkARAA9AD[2]是不是比較讓人無從猜起,而且因為還需經過解碼手序,就算被人亂輸入也不怕,唯一的缺點經過編碼查尋字串會增加好幾倍,URL的查尋總字數為4096Byte(約二千個字左右),如果字串多很容易就爆掉了,這點要多加注意。
編碼範例
<%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { //假設我的EmployeeID為0 int EmployyeeID = 0; //先將字串轉成位元組 byte[] StringByte = System.Text.UnicodeEncoding.Unicode.GetBytes(EmployyeeID); //將位元組編碼 String Encode = HttpServerUtility.UrlTokenEncode(StringByte); //設定連結控制項的連結Url MyInforHyperLink.NavigateUrl = "MyInfo.aspx?EmployeeID=" + Encode; } </script> <html> <head runat="server"> <title>EnCode</title> </head> <body> <form id="form1" runat="server"> <div> <asp:HyperLink ID="MyInforHyperLink" runat="server">My Information</asp:HyperLink> </div> </form> </body> </html> |
這個範例主要就這二行
byte[] StringByte = System.Text.UnicodeEncoding.Unicode.GetBytes(EmployyeeID); String Encode = HttpServerUtility.UrlTokenEncode(StringByte); |
首先先看第一行,這一行的做用是將字串轉成位元組,轉成位元組是因為在.Net中大部分的編碼都只支援編碼位元組,這裡是使用Unicode[3]轉成位元組(不要使用ASCII免得中文字無法還原)。
第二行的做用是將位元組編碼成字串如0就變成MAA1。
在.NET Framework中有很多的編碼的類別,這裡使用的是比較簡單且適合URL的編碼,也有更安全,更複雜的編碼方法,請自行研究。
解碼範例
<%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { //有沒有查尋字串 if (Request.QueryString["EmployeeID"] != null) { string EmployeeID = Request.QueryString["EmployeeID"]; //先將字串解碼成位元組 byte[] StringByte = HttpServerUtility.UrlTokenDecode(EmployeeID); //將位元組轉成字串 String Decode = System.Text.UnicodeEncoding.Unicode.GetString(StringByte); //下面是連資料庫 System.Data.DataTable MyInfo; System.Data.SqlClient.SqlDataAdapter SDA = new System.Data.SqlClient.SqlDataAdapter("Data Source=(local); Initial Catalog=DataBase;Integrated Security=True", "Select * From Employee Where EmployeeID=" & EmployeeID); SDA.Fill(MyInfo); DetailsView.DataSource = MyInfo; DetailsView.DataBind(); } } </script> <html> <head runat="server"> <title>Decode</title> </head> <body> <form id="form1" runat="server"> <h3> My Information</h3> <p> <asp:DetailsView ID="DetailsView" runat="server"> </asp:DetailsView> </p> </form> </body> </html> |
這個範例主要就這二行
byte[] StringByte = HttpServerUtility.UrlTokenDecode(EmployeeID); String Decode = System.Text.UnicodeEncoding.Unicode.GetString(StringByte); |
第一行的做用是將字串解碼成位元組就是沒碼解前的位元組,第一行的做用是將位元組還原成字串。
安全性是現在程式設計很注重的問題,就算程式寫的再好,卻沒有考慮到安全性,那就算失敗的程式了,小弟會慢慢的一些常見的問題與決解方法寫出來,供大家參考,請近請期待。
2006/7/12偉榮
[1] SQL Injection 是指利用應用程式開發人員不期待或沒有預料到的方法,將SQL程式碼傳入應用程式的程式。如何防止SQL Injection不在本文的範圍內。
[2]將查尋字串全部編碼如查尋字串type=25&NO=40編碼變成http://localhost/default.aspx?QueryString = AHAAbABvAHkAZQBlAEkARAA9AD,這個方法更安全,只是在取值的時會較複雜些。
[3] Unicode(統一碼、萬國碼、單一碼)是一種在電腦上使用的字元編碼。它為每種語言中的每個字元設定了統一併且唯一的二進位編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。1990年開始研發,1994年正式公佈。隨著電腦工作能力的增強,Unicode也在面世以來的十多年裡得到普及。