用vs2005 + vsto 開發一個outlook的addin的時候,碰到了一個問題,在我機器上運行的好好的程序,用vs自己的打包安裝程序安裝到別的機器的時候總是顯示 not load, 加載程序的時候出錯。google了一下,遇到了一個新名詞, CAS: code access security. 找不到相關的中文文檔。在codeproject上看到了這篇文章。文章比較長,有codeproject的文風,講解的非常詳細,就是一點基礎都沒有的人都知道他說什么,但是要耐心看。 ^_^
Role Based Security (not being discussed in this article) 基于角色的安全驗證
Code Access Security 代碼訪問安全性
CLR 允許代碼做那些只被授權的行為,所以, CAS 是一種通過阻止未授權的訪問來保護資源和操作的一種安全系統。運用 CAS ,你可以做到:
指定你的代碼能夠做的
指定那些代碼可以代用你的代碼
唯一標識你的代碼
我們將在這篇文章討論這些問題,你應該熟悉一些術語。
?
術語
?
CAS 包含一下這些元素:
-
permissions
?
許可
-
permission sets
許可集
-
code groups
代碼組
-
evidence
物證
-
policy
策略
Permissions
Permissions 聲明對受保護的資源的訪問或者是執行受保護的操作的能力。 .Net Frameword 提供了一些 Permission 的類,像 FileIOPermission (對文件起作用), UIPermission (允許使用一些用戶接口), SecurityPermission (對于執行代碼甚至是繞過安全機制這是必須的)。我將不會列舉所有的 Permission 類在這里,他們列舉在下面。
Permission sets
一個
Permission Set
是一個
permission
的容器。你可以把
FileIOPermission
和
UIPermission
放到你的
Permission set
中,然后叫他“
My_PermissionSet
”。一個
Permission set
可以包含許多
permissions
。
FullTrust
,
LocalIntranet
,
Internet
,
Execution
和
Nothing
是
.net framework
內置的一些
permission sets
。
FullTrust
包含所有的
permissions
,而
Nothing
則表示什么都不包括,甚至連執行的權利都沒有。
Code groups
Code group
是一個特定條件下的代碼邏輯組。
http://www.somewebsite.com/
的代碼可以屬于一個代碼組,包含一個特定的強類型名字的代碼屬于另一組,特定裝配的代碼又屬于一個組。內置的代碼組像
My_Computer_Zone
,
LocalIntranet_Zone
,
Internet_Zone
等等。像
permission sets,
我們可以創建代碼組來滿足我們基于
evidence
的需求。
Site
,
Strong Name
,
Zone
,
URL
是一些
evidence
的類型。
Policy
Security policy
是可配置的規則的集合,當我們決定賦予代碼一定的許可。有
4
個機制的等級
Enterprise
,
Machine
,
User
和
Application Domain
,每種操作不互相依賴。每個等級有它自己的
code groups
和
permission sets
。他們的層次如下:
【圖一】
Ok
,理論說完了,讓我們把理論付諸實踐。
?
小例子
?
讓我們創建一個新的
windows
應用程序。添加
2
個
button
到存在的
form
上。我們將用到文件系統,所以添加
System.IO
命名空間。
using System.IO;
【圖二】
寫下如下代碼:
{????
StreamWriter?myFile? = ? new ?StreamWriter( " c:\\Security.txt " );???}
myFile.WriteLine( " Trust?No?One " );???
myFile.Close();
private ? void ?btnRead_click( object ?sender,?System.EventArgs?e)
{????
StreamReader?myFile? = ? new ?StreamReader( " c:\\Security.txt " );???}
MessageBox.Show(myFile.ReadLine()); ?
myFile.Close()
完整的版本號我們的例子才能夠工作。確定你設置了你的版本號為一個固定的值,否則它會隨著你的編譯次數自動增加。我們標記這個裝配用一個強名字,這將被用做 evidence 時標識代碼用。這就是為什么你需要設置你的版本號為一個固定的值。
[assembly: AssemblyVersion( "<chsdate isrocdate="False" islunardate="False" day="30" month="12" year="1899" w:st="on">1.0.0</chsdate>.0" )]
就這樣。。。沒有什么異常。它將會寫一個名字為 security.txt 的文件到 c:. 現在跑起來你的代碼,它將會創建一個文件并寫下一行,每件事看起來都 ok 。。。除非你沒有 c 盤?,F在我們要做的事把我們的裝備到一個 code group ,并且設置一些 permissions 。還不要刪除 security.txt 文件,我們晚點會需要它。
NET Configuration Tool
我們可以用兩種方式來做這個工作,從 .NET Configuration Tool 或者是用命令行調用 caspol.exe 。 首先我們用 .NET Configuration Tool 。從控制面板——》管理工具-》 Microsoft .NET Framework Configuration 。 你也可以用“ mscorcfg.msc ”在 .net 命令行。你可以做很 cool 的事情通過這個工具。。但是目前我們只是對設置代碼訪問權限感興趣。
【圖三】
Creating a new permission set 創建一個新的 permission set
展開
runtime security policy
節點。你可以看到安全機制級別
Enterprise
,
Machine
和
User
。我們將改變
Machine
機制的安全集合。首先我們創建我們自定義的
permission set
。右擊
permission sets
節點選擇
new
。因為我到別的易記住的名字,我命名它為
MyPermissionSet
.
【圖四】
我將在下一個屏幕添加 permissions 到 permission set 。在左邊的 panel ,我們可以看到 .NET Framework 支持的所有的 permissions ?,F在我們得到 File IOpermission 屬性。設置 File path 到 c:\ 然后只選上 read 。所以我們沒有賦予寫的權限。請注意那里還有另一個選項說“準許裝備自由的訪問文件系統”如果這個被選上,任何事情都可以做,沒有任何限制。
【圖五】
現在我們多添加
2
個
p’ermissions
Security
和
User
Interface
。
只需要添加記住添加“準許裝備自由的訪問文件系統”。我很快將會解釋這些屬性。沒有
Security
permission
。我們沒有權限去執行我們的代碼,沒有
User Interface p’ermission
,我們將不會看到
UI
。如果你添加了這
3
個
permissions
,你會看到有一個新的
permission set
被創建,命名為
MyPermissionSet
.
?
Creating a new code group 創建一個新的代碼組
現在我們創建一個
code group
然后設置一些條件,所以我們的裝配將會是這個
code group
的一員。注意在
code group
機電,
All_Code
是父節點。右擊
All_Code
節點選擇
new
。創建
code group
向導將呈現在你面前。我將命名它為
MyCodeGroup
.
【圖六】
下一個屏幕,你需要提供一個
condition
類型給
code group
。這些就是之前提到過的
evidence
。在這個例子中,我們用
strong name
類型。首先標識你的裝配用一個
strong name
然后編譯它?,F在我們按
import
(導入)按鈕選擇你的裝配。
Public key
,名字和版本將從裝配中萃取出來,我們不需要考慮它?,F在我們到下一個頁面。我們必須為我們的
code group
指定一個
permission set
。因為我們已經創建了一個
MyPermissionSet
,
,我們從
list box
中選他。
【圖七】
Exclusive and LevelFinal
如果你還沒有被。
NET configuration
默認的安全設置搞混淆,你的裝配已經屬于另一個內置的
code group
My_Computer_Zone
。當
permission
被計算,如果一個特別的裝配屬于多個
code group
在相同的機制級別,最后的
permissions
將是所有的
code group
的
permissions
的集合。我將晚點解釋怎么計算
permissions
,現在我們只需要跑我們的裝配用我們的
permission set
,就是用
MyPermissionSet
關聯的
MyCodeGroup
.
所以我們必須設置其他的屬性來達到這個目的。右擊新創建的
MyCodeGroup
節點選擇屬性。選擇
check box "
This policy level will only have the permissions from the permission set associated with this code group.
"
這個機制等級的
permission
只包含與這個
code group
關聯的
permission set
。這個叫
Exclusive
屬性。如果這個被選上了,運行時將不會允許除關聯到這個
code group
的
permissions
。另一個選項叫做
LevelFinal
.
這兩個屬性將在計算
permissions
的時候起作用,我們將詳細解釋它在下面。
【圖八】
我們已經設置了許多屬性,但是它將在最后講得通。 :-<
?
好了,現在我們來跑我們得代碼。我們現在做得就是把我們得代碼放到一個 code group 中,并且給她對 c 盤得只讀得權限,跑它并按那兩個按鈕, read 工作得很好,但是當你按 write 得時候,一個 exception 拋出了,因為我們沒有對 c 盤寫得權限。下面時出錯得信息。
【圖九】
所以多謝 code access security ,這種對資源得限制是可行的。通過 CAS 你可以做很多事情,我們講在余下得文章中討論。
Functions of Code Access Security
根據文檔, CAS 充當了一下這些功能:(直接從文檔上復制過來的)
-
Defines
permissions
and
permission sets
that represent the right to access various system resources.
-
Enables administrators to configure
security policy
by associating sets of permissions with groups of code (
code groups
).
-
Enables code to
request
the
permissions it requires in order to run
, as well as the
permissions that would be useful to have
, and specifies which
permissions the code must never have
.
-
Grants permissions
to each assembly that is loaded, based on the permissions requested by the code and on the operations permitted by security policy.
-
Enables code to
demand
that its callers have specific permissions. Enables code to demand that its callers possess a digital signature, thus allowing only callers from a particular organization or site to call the protected code.
-
Enforces restrictions
on code at run time by comparing the granted permissions of every caller on the call stack to the
permissions that callers must have.
我們已經做了最頂上的
2
個,那是管理的部分。有一個獨立的命名空間我們還沒有看過
System.Security
,這個是用來實現安全的。
?
Security Namespace
System.Security
命名空間下的
主要的類有:
Classes
|
Description
|
CodeAccessPermission
|
定義下面的結構所有的代碼訪問權限
|
PermissionSet
|
申明一個包含不同 permissions 的集合
|
SecurityException
|
當檢測到安全錯誤的時候拋出的異常
|
System.Security.Permissions 命名空間下的主要的類有 :
Classes
|
Description
|
EnvironmentPermission
|
控制對系統和用戶環境變量的訪問權限
|
FileDialogPermission
|
通過文件對話框控制對文件和文件夾的訪問權限
|
FileIOPermission
|
控制對文件和文件夾的訪問權限
|
IsolatedStorageFilePermission
|
指定對私有的虛擬文件系統的使用方式 .
|
IsolatedStoragePermission
|
指定對普通的獨立存儲的訪問權限
|
ReflectionPermission
|
控制對
metadata
訪問通過
|
RegistryPermission
|
控制對注冊表的訪問
|
SecurityPermission
|
描敘安全的 permissions 應用到 code 上
|
UIPermission
|
控制 UI 和鍵盤的權限
|
你能找到更多的
permission
類 在其他的命名空間,例如,
SocketPermission
和
WebPermission
在
System.Net
。
SqlClientPermission
在
System.Data.SqlClient
命名空間
,
PerformanceCounterPermission
在
System.Diagnostics
命名空間等等。
下一步,我們將看到怎么使用這些類。
Declarative vs. Imperative (聲明和命令)
你在寫代碼的時候可以用兩種不同的語法,聲明和命令。
Declarative syntax 聲明語法
生命語法用需要的安全信息屬性去標識方法,類或者是裝配。所以當編譯的時候,他們替換相應的元數據章節。
?2 ?
?3 ? public ?calss?MyClass
?5 ? {
?7 ? ???? public ?MyClass()?{

?9 ? ???? public ? void ?MyMethod_A()?{

11 ? ???? public ? void ?MyMethod_B()?{

13 ? }
命令語法
命令語法用運行時方法調用創建一個新的實例。
{
???? public ?MyClass()?{?}
???? public ? void ?Method_A()?
????{
???????? // ?Do?Something
????????FileIOPermission?myPerm? = ?
?????????? new ?FileIOPermission(PermissionState.Unrestricted);
????????myPerm.Demand();?
???????? // ?rest?of?the?code?won't?get?executed?if?this?failed
?
???????? // ?Do?Something
????}
???? // ?No?demands
???? public ? void ?Method_B()
????{
???????? // ?Do?Something
????}
}
他們 2 個的主要的不同是,聲明調用是在編譯的時候調用而命令調用是在運行時的時候。請 注意編譯的時候指的是在 jit 編譯的時候。
這里有一些行為可能與 permissions 沖突。
首先,我們看一下聲明的語法。用
UIPermission
來說,聲明語法意思使用屬性,所以我們實際使用
UIPermissionAttribute
,當你打開
msdn
你會看到這些屬性:
-
Action - SecurityAction
枚舉的一個值
-
Unrestricted –
自由訪問
-
Clipboard –
對鍵盤的訪問權限,
UIPermissionClipboard
枚舉的一個值
(UIPermission specific)
-
Window –
對窗體的訪問權限
UIPermissionWindow
的一個值。
Action
和
Unrestricted
屬性是通常類的
permission
。
Clipboard
和
Window
用來指明
UIPermission
。你必須提供
action
你使用其他屬性的你用到的
permission
類。所以在這種情況下,你可以像這樣寫:
Clipboard = UIPermissionClipboard.AllClipboard)]
或者添加
Clipboard
和
Window
兩個屬性:
????Clipboard = UIPermissionClipboard.AllClipboard,?
??????Window = UIPermissionWindow.AllWindows)]
如果你想要聲明一個 permission 用自由訪問,你可以這樣做:
當你使用命令語法,你可以使用構造函數來傳遞這些值,然后在屬性中調用它的
action
。我們用
RegistryPermission
。
??? new ?RegistryPermission(RegistryPermissionAccess.AllAccess,
??? " HKEY_LOCAL_MACHINE\\Software " );
myRegPerm.Demand();
如果你想自由訪問這些資源,你可是使用
PermissionState
枚舉用如下的方法:
RegistryPermission(PermissionState.Unrestricted);
myRegPerm.Demand();
這是你調用任何 permissions 類所需要知道的在 .NET Framework. 。現在,我們將詳細討論 actions
Security Demands
需求用來保證每一個調用你代碼的調用者(間接的或者是直接的),已經得到需要的
permission
。這個通過一個棧來完成。什么
...
一個老鼠道?不,那是你女朋友做的,我的意思是一個棧道。請求一個
permission
,運行時安全系統瀏覽棧,比較每個調用者準許的
permissions
和被請求的
permission
。如果任何一個調用棧不能找到請求的
permission
,然后
SecurityException
拋出。請看如下的圖:
圖十】
不同的裝配和不同的方法在相同的裝配通過棧道來檢查。
現在回到需求。這里有 3 種類型的需求。
-
Demand
-
Link Demand
-
Inheritance Demand
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
