最近工作上因為資安問題,修補程式修到頭破血流了
但也學到了不少防堵方法,有些入侵的手法還真的是有些讓人傻眼
一般的新手程式設計師,或是專門寫內部系統的工程師大概也很容易犯類似的錯誤
所以以下就列出一些在開發中必須要注意的事項或建議寫法,還有可能入侵的手法
有些是程式開發的常識,但有些是用本人的血淚堆積成的.......orz
如果以下有寫到程式碼的話,就用 C# 來舉例
1.使用 SQL Parameters
這個非常重要,要防止 SQL Injection 的方法只有這個了
千萬不要自己去做一個關鍵字集合去 Replace SQL命令
因為你沒法確定是不是會有新的攻擊命令或關鍵字敘述
所以操作資料庫的SQL命令一定要使用SQL Parameter
如下 :
string sql = "select * from City where Zip = @Zip";
SqlCommand cmd = new SqlCommand();
cmd.Parameters.Add("@Zip", SqlDbType.VarChar,10).Value = Zip;
cmd.CommandText = sql;
2.Cookies 內容加密
網站登入資料(ex:帳號) 不要寫在Cookies中,尤其是Client 端Cookies
因為瀏覽器只要按F12就可以看到值了,用Fiddler也可以很容易就錄到
沒加密的話知道Cookies 是幹嘛的之後就很好try了
如果要在Cookies中儲存登入資訊 (因為可能有"記住我"之類的功能)
比較好的做法 :
使用ASP.Net內建的 FormsAuthentication
ex :
//登入
FormsAuthentication.SetAuthCookie("使用者帳號", true);
//判斷是否登入
if (User.Identity.IsAuthenticated) {
Response.Write("已登入");
}
//取得使用者帳號方式
User.Identity.Name;
//登出
FormsAuthentication.SignOut();
之後打開瀏覽器F12,Cookies 就被加密了
但在使用這功能前要先改web.config
<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="~/default.aspx" defaultUrl="default.aspx" protection="All" timeout="600" path="/" requireSSL="false" slidingExpiration="true" cookieless="UseDeviceProfile" domain=".suncolor.com.tw" enableCrossAppRedirects="false">
<credentials passwordFormat="SHA1" />
</forms>
</authentication>
更詳細的使用方式請參考保哥這篇
http://blog.miniasp.com/post/2008/02/21/Explain-Forms-Authentication-in-ASPNET-20.aspx
裡面的這篇很詳細
http://msdn.microsoft.com/en-us/library/aa480476.aspx
3.千萬不要相信Client傳來的內容
這個內容包含的實在很廣.....
因為Client傳到Server的任何資訊都是可以被竄改的,尤其位置不是存在於SSL之下
舉例來說一般在會員註冊時,會要求使用者填寫住家地址,選擇縣市地區
相信大部份70%都是用AJAX處理 (因為對使用者體驗比較好)
選擇縣市後觸發change去更改地區值填回select option or DropDownList
而 Server 端就直接接收下拉的數值了
ex :
//如果是 Server Control
string City = this.City.SelectedValue;
//如果是一般HTML
string City = Request.Form("City");
...............
然後你可能就直接存取資料庫了
string sql = "Insert into Order (.....) values (......,@City)";
SqlCommand cmd = new SqlCommand();
cmd.Parameters.Add("@City", SqlDbType.VarChar,10).Value = City;
cmd.CommandText = sql;
如果此時你寫入的City值沒有再去驗證的話,你可能很容易就中了XSS
因為你接收到的數值可能已經被竄改
比較好的做法 :
下拉選單的數值盡量為數字,傳到Server端之後就可以驗證參數值是否為數字型態
以上面的例子而言 City 有城市編號,再利用城市編號 AJAX 去找回 ZipCode
如果要取回使用者所在城市就用ZipCode去資料庫去反查
ex :
//記得Zip 要先判斷是否為數值型態,或是在getCityInfo中處理
//傳入getCityInfo後取得 CityInfo 物件
CityInfo city = getCityInfo(Zip);
//用此方式取得城市與地區
city.Area;
city.City;
如果是一般無法用數字表示的下拉值,就要檢查長度
例如 : 台灣城市地區可能最長也就"海南諸島"四個字
超過四個字當然就很有問題
4.有牽扯到敏感資訊的內容頁面,要放在SSL之下
這是Fiddler 在 Http 下錄到的結果
這是Fiddler 在 Https 下錄到的結果
看到圖應該就不用解釋了吧!
5. Server 端接收的所有參數使用AntiXSS過濾
這元件就是用來防止XSS攻擊,可以到下方下載 dll
http://www.microsoft.com/en-us/download/details.aspx?id=43126
或是在Nuget上搜尋 AntiXSS
用法 :
先引用 dll or Nuget 下載安裝
using Microsoft.Security.Application;
string Str = AntiXss.GetSafeHtmlFragment("要過濾的文字");
ps : framework 4.5有內建AntiXss了,但用法跟使用 dll 不同使用時要注意一下
System.Web.Security.AntiXss 命名空間
所有傳遞到 Server 端的參數都最好加上XSS的過濾,尤其是會寫入到資料庫的值
如部落格類型的網站,就必須要檢查 or 過濾編輯器 ex:ckeditor 內的輸入是否有惡意符號,過濾後才能進資料庫
如SQL Parameters一般,防止XSS最好的辦法就這個了
6. 圖片上傳後要檢查副檔名,與內容是否真的為圖片
檢查副檔名這個雖然是常識,但是我有因為邏輯沒寫好而沒檢查到 @@
所以這個很重要,一定要再三確認邏輯是否正確,而且也建議要檢查內容是否真的是圖檔
因為如果只判斷附檔名,把 .txt、.js、.aspx....之類的改成.jpg 也是可以上傳
萬一不小心有其他洞可以rename就好玩了,更不用講有些真的是圖片裡面也有程式碼
網路上看到這個解決方式可以參考一下
請教判斷是否為真的圖檔的方法 <------ 這篇判斷前幾個byte 的方式
但我最後的做法是利用縮圖元件,再把上傳上來的圖再縮一次圖
測試過就算把.txt 改為 .jpg 拿去縮圖,也會被轉成真正的圖片
7.禁止使用者發表文章時寫入 iframe or frame 標籤
這其實也算XSS,如果沒有禁止iframe,就等於開了個洞讓人植入惡意程式
可以在iframe 的src 把瀏覽到此頁user的 document.cookie 送回指定網址
對方取得cookies 後再模擬登入你網站就好了,如果你連加密都沒有的話就更慘
請看此篇 : XSS Attack Using Frames
或是直接就在 iframe的onload 事件run 惡意js 了
8. Web.config 加上 Http Header 的相關安全設定
除了寫程式要注意,相關的設定檔也可以幫很大的忙
貼一下主管給我的這一篇給大家參考 :
https://www.imququ.com/post/web-security-and-response-header.html
web.config 加上以下標籤
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN"/>
<add name="X-XSS-Protection" value="1; mode=block"/>
</customHeaders>
</httpProtocol>
X-Frame-Options 設定後可以啟動瀏覽器避免非網站的Frame夾在頁面取得資料。
X-XSS-Protection 設定後可以啟動瀏覽器的XSS攻擊。
還有其他詳細設定請看上面那個連結
9.重新檢查網站金流服務的串接方式
網站金流都要在SSL下進行才對,但有可能會連出去的就是信用卡刷卡的服務 or 711
因為要連到銀行端頁面進行授權,雖然還是在SSL之下,但轉頁就可能會有可趁之機
在此講一下遇到的狀況......
我們使用的技術文件上寫了要以iframe方式箝入對方的信用卡輸入頁面
但因為iframe 的 src 網址上參數有什麼都一目了然,包含訂單編號、要授權的金額...等
而我們之前的外包寫得更糟是直接以網址連到銀行端,參數就直接在網址列改了
雖然改了參數之後還是有被銀行端拒絕交易,但不知道對方用何種方法....
讓銀行接受了$10元的授權金額,但是$300多元的商品金額,且接收到銀行回傳的交易金額也是$300多
意思就是說,就算你要拿訂單金額跟銀行回傳的金額比對也沒用
因為你已經被截斷了,送出去跟拿回來都是假的
就算完全遵照串接的文件使用iframe來做也是一樣
最後的解決方式是.....跟對方要新版本的串接文件,改用元件的方式
因為如果你們家的信用卡金流是以iframe or URL導頁方式執行的話
要記得抽空問一下對方文件有沒有更新版啊!
10.使用Web Application的方式來建置網站
不要使用Web Site 建立新網站的方式來開發,萬一網站被侵入了程式碼也會被看光光
看光光就算了,對方還可以直接改你的 .cs or .vb
使用建立Web Application 建立專案的方式開發,就算主機被侵入了也看不到程式碼
萬一現在的網站類型是 Web Site 的話,可以用下面的方式轉換成 Web Application
但轉換之前必須要先讓原本的Web Site 可以被建置成功 (連結裡面有提到)
11.AJAX的安全性問題
如果你的 AJAX 裡面有牽扯到訂單查詢 or 會員資料查詢修改的話,就必須要再檢查使用者權限
尤其是有關 Insert、Update、Delete
例如有個AJAX裡面的 SQL 如下 :
string sql = @"
update member
set nickname=@nickname,cname=@cname
where account = @account
";
SqlCommand cmd = new SqlCommand();
cmd.Parameters.Add("@nickname", SqlDbType.VarChar,50).Value = nickname;
cmd.Parameters.Add("@cname", SqlDbType.VarChar,50).Value = cname;
cmd.Parameters.Add("@account", SqlDbType.VarChar,50).Value = account;
如果全部參數值是從網頁上傳來的,然後又沒做任何限制擺明了就是個洞
因為直接改account 值就可以幫別人改資料了
此時應該是要檢查AJAX的使用者是否為登入的當事人
SqlCommand cmd = new SqlCommand();
cmd.Parameters.Add("@nickname", SqlDbType.VarChar,50).Value = nickname;
cmd.Parameters.Add("@cname", SqlDbType.VarChar,50).Value = cname;
cmd.Parameters.Add("@account", SqlDbType.VarChar,50).Value = User.Identity.Name;
12.盡量不要把重要資訊寫到頁面上的 Hidden
一般把值寫在 <input type="hidden " /> 大部分應該都是為了方便讓 js 去操作
但也造成了只要打開原始碼一看,大概就知道有哪些參數了
寧可多花點效能去SQL查回來,也不要一開始就全部查回來然後丟在網頁表單的 hidden 欄位
13.關閉圖檔資料夾的執行權限
依照網站類型,如果是社群或發表文章類的網站幾乎都會有上傳圖片的需求
有上傳就會有風險啊! 像之前 CKEditor 的檔案上傳問題就是
所以如果有那種不需要讀取執行 .aspx 程式的資料夾就把他執行的權限拿掉
不然如果被傳了惡意的檔案上來就很有可能會被執行起來
設定方式可以參考保哥的這篇
就會在圖檔或 JS、CSS....等不需要執行.aspx 的地方放一個 web.config 檔案
內容如下 :
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read" />
</system.webServer>
</configuration>
可以防止萬一真的被透過上傳介面上傳了惡意程式上來,也不會被執行
14.會員加入、登入記得加個驗證碼
............ 以防駭客太好 try
....................日後有遇到或看到或想到再來補充
留言列表