2005.3.22 歐岩亮
課程介紹
如何應用.NET Framework中的特性來保護代碼的安全
基礎內容
熟悉.NET開發
課程安排
身分識別驗證
授權
加密
強命名程式集
代碼訪問安全
中介層安全
如何避免SQL注入
身分識別驗證
使用Credential來唯一標明一個使用者
可以使用Microsoft Windows的整合身分識別驗證,使用使用者登入Windows時的使用者憑證
編寫自己的使用者身分識別驗證的程式,應用程式來系統管理使用者憑證
System.Security.IIdentity介面和System.Security.GenericIdentity類
System.Security.Principal.WindowsIdentity.GetCurrent().Name
示範一
Authentication
這裡的密碼是1234的MD5加密密文,NorthwindCredentials的建構函式傳入了使用者名稱以及使用者的三個角色。另一個使用者fred只有銷售許可權。
下面是NorthwindCredentials類
建構函式
Identity就是一個使用者的標識,roles是使用者的角色數組。
登入表單
如果是登入驗證成功,那麼將當前執行線程的CurrentPrincipal使用者憑證,置成了WebService返回的creds對象。
Authorization
使用基於角色的安全
可以通過編程實現基於角色的授權
角色可以代表商業流程中的工作職責,例如:秘書、經理、管理員、總監等
用角色的方式來系統管理使用者會更加簡便
如何使用基於角色的安全
PrincipalPermissionAttribute和SecurityAction.Demand
在類或者方法上加上PrincipalPermission就表示要訪問類或者方法需要通過身分識別驗證。Authenticated為true表示必須要通過身分識別驗證,Role表示使用者需要訪問所必須具有的角色。.NET在啟動並執行時候就會去查看當前運行線程的CurrentPrincipal,判斷使用者是不是有相應的許可權。
IPrincipal.isInRole()
判斷當前的使用者是不是有某一個角色。Context.User是Asp.net裡面來訪問當前使用應用程式使用者的Class。這個例子通過判斷目前使用者所具有的角色來賦予介面元素不同的屬性。
示範二
Authorization
SecurityAction.Demand表示需要具有某種東西,Role表示需要具有Manager的角色許可權。這裡Manager是個字串常量,
如果不具有相應許可權想訪問這個類,就會拋出異常。
這樣做還是會有一些弊端,如果我們想通過資料庫來規定使用者需要哪些角色能訪問,就不能通過這種標籤的方式。這種標籤加許可權限制訪問的方式只能夠用硬代碼規定角色的常量字串名稱。
所以.NET為我們提供了另外一種方式。
在建構函式中,我們可以執行個體化一個PrincipalPermission,將角色通過字串方式傳入,而不同在類上面加標籤。如果frmProducts類不使用,那麼就不會得到此類的任何方法;如果要使用,必須通過建構函式中的許可權驗證。
為了更好的使用者體驗,我們把介面元素的屬性也根據許可權來設定可見與不可見。
加密
加密將位元組打亂
對稱式加密與非對稱式加密
對稱式加密適用一個相同的密鑰進行加密/解密
非對稱式加密使用一個金鑰組進行加密/解密,加密與解密的密鑰是不同的(公開金鑰/私密金鑰對)
非對稱式加密演算法更加安全
對稱式加密演算法更加高效
System.Security.Cryptography名稱空間
如何進行密鑰管理
示範三
加密
加密位元組序列,我們使用了.NET內建的一種加密方法,DESCryptoServiceProvider。
解密方法
CryptoStream實際上是對MemoryStream的封裝,當我們對cs進行寫操作的時候,會把解密後的資料寫入MemoryStream。
這裡加密後的資料要進行一個Base64的轉換,因為網路上傳輸的時候不能直接傳輸二進位,而一般使用xml進行傳輸,xml裡面仍然不能寫入位元據,但我們可以通過把位元據轉換為Base64的編碼形式,而Base64的字串是可以儲存在xml檔案中的。當xml資料檔案傳輸到對方之後,對方再用逆向的方法把Base64的String轉換為二進位,再進行解密。
運行結果
我們的設定檔中可以把連接字串加密存入設定檔,然後使用的時候解密,這樣能提高程式的安全性。
在擷取連接字串時用同樣的密鑰"NorthwindKey"進行解密
但是我們也最好不要把密鑰和解密演算法放在程式中,因為可以通過反編譯看出加密規則。我們可以通過把密鑰放在註冊表中,或者通過加密狗等程式來提高安全性。
Code Access Security
最低許可權的策略
讓所有使用者具有最低許可權。
Code Group——按照邏輯分類的程式碼群組合
Code Group可以按照多種方式劃分URL,string name,zone,etc
Permission Sets——許可集,用來定義代碼能夠訪問的資源:檔案I/O,Isolated Storage隔離儲存區 (Isolated Storage),SQL用戶端,等等。
Link demands
示範四
代碼訪問安全
我們可以用這樣的代碼來保證我們的應用程式在啟動並執行時候一定要具有某些許可權才可以運行。應用程式本身可以檢測當前Windows作業系統上的.NET架構配置上面是否允許運行。例如,WebPermission表示要求電腦要能訪問Web。IsolatedStorage標籤表示需要有能夠訪問隔離儲存區 (Isolated Storage)的功能。
Refused set表示要拒絕的功能。
進入cmd,在當前工程的路徑,我們可以通過permview命令來觀看當前應用程式集需要什麼樣的許可權。
我們也可以在組態工具中的Code Group來劃分許可權,以及設定PermissionSet
強命名應用程式集
使用sn.exe工具來建立強命名公開金鑰/私密金鑰對,並儲存在檔案當中:
sn.exe –k Northwind.snk
sn是strong name的縮寫,我們可以用-k的方式,後面帶密鑰檔案名稱,產生一個公開金鑰/私密金鑰對。編譯器的簽名工具會利用私密金鑰對程式集加密,產生密碼編譯摘要,放在Manifest中,並在Manifest中存放公開金鑰,在運行程式集時,會拿到公開金鑰資訊,驗證簽名是否有效。
AssemblyKeyFileAttribute
可以在AssemblyInfo中的這個標籤來標記密鑰檔案的路徑
優勢
可以被裝在到GAC當中
Side-by-side部署,支援多個版本的應用程式集
在編譯時間,.NET的用戶端代碼使用了強命名應用程式集,在運行時能夠有效地防止裝入“木馬”應用程式集。其他人雖然可以反編譯或者修改我們的代碼,但是他們不具有我們的私密金鑰檔案,在使用dll的時候,程式會檢測dll是否具有強命名,如果不具有,程式是不會理會的。
Delayed Signing
私密金鑰保密性,確保Team Dev中的多個組建使用相同的強命名
如果我們的Team Dev很龐大,我們如果想讓團隊的人對項目進行強命名,我們就需要把密鑰檔案給他,這就相當於把私密金鑰給他了。這種方式是很危險的,我們不能保證每個開發人員都是效忠的。我們可以使用下面的方法。
只匯出公開金鑰
我們讓所有程式員在開發的時候,唯寫上只包含公開金鑰的snk地址,然後我們加入標籤AssemblyDelaySign(True),這樣在真正用私密金鑰加密之後的簽名不會在每一次產生都放到dll中。
Sn -Vr<assemblyname>:關閉對只擁有公開金鑰的強命名應用程式集進行驗證
Sn –R<assemblyname><keyfilename>:在發布之前對應用程式集進行緩簽名
在發布之前才對所有程式進行真正的簽名
Link Demands
串連請求發生在外部的代碼對本應用程式集進行調用的時候
System.Security.Permissions名稱空間
例如:StrongNameIdentityPermission屬性
從某個應用程式集中提取公開金鑰標示(一個十六進位的字元序列)
sn –Tp NorthwindModel.dll
例如:
這個標籤要求別的應用程式集在裝載我們程式集時,必須具有這種公開金鑰才可以,如果不是這種認證簽名的程式,將不會被允許串連到我們程式集內部。
例如如果我們想查看某個強命名的程式集公開金鑰的Token。
我們只要把這個標示填充到標籤中的PublicKey屬性即可。
Middle Tier安全
最現成的方法,COM+是最安全的解決方案——與Windows整合并支援配置
Web Service的安全可以通過HTTPS和IIS安全來控制
當不能使用IIS安全的時候,可以使用WS-Security(Web Service Enhancements的一部分)來保證平台之間的Web Service安全
Remoting安全
IIS宿主和TCP,使用IIS安全和HTTPS
其他宿主,需要實現定製的Channel或Sink
示範五
中介層安全
IIS安全,是預設的匿名的驗證,是Basic驗證
其中Cache添加的時候註明了是使用Basic驗證。這種驗證會將使用者名稱和密碼以明文的方式傳輸到IIS上面,所以我們在使用Basic驗證時應該最好使用Https來保證傳輸安全。
SQL注入
SQL注入這種威脅發生在動態產生SQL查詢語句的時候,動態產生的SQL語句可能會被篡改
例如:
如果在上面的SQL語句中加入'OR 1=1'這個條件,users表中的所有資料將作為結果返回
所有使用動態SQL查詢的應用程式都有可能受到這種威脅
為了防禦這種攻擊,去掉所有的動態SQL查詢:使用ADO.NET中的SqlParameters
示範六
防止SQL注入攻擊
上面是危險的方式,下面是安全的方式
注入攻擊
如果是第一種方式的代碼,那麼登入始終會成功,但如果是用第二種方式,登陸就會失敗。
安全設計目標
最小化攻擊範圍
分析具體的攻擊並阻止它們:
拒絕服務的攻擊
基於檔案或目錄的攻擊
SQL注入
引誘攻擊(Luring)
防患於未然,提早預知新的攻擊
使用經過驗證的安全技術:身分識別驗證,給予角色的授權,HTTPS,加密
總結
.NET包括了強大的內建的安全特性
具體問題具體分析,根據情況來選擇安全技術,編寫安全的基於Windows Forms的代碼
不需要絞盡腦汁去發明新的安全的程式碼
2010.10.20