devxlogo

Code Access Security in the .NET Framework

Code Access Security in the .NET Framework

n case you ask yourself how this security model can be useful, just consider if the Windows operating system could currently apply a CAS such that no code downloaded from the Internet as a mail attachment was allowed to run (no matter if who’s running Outlook Express is the computer administrator). Got the point? No mail virus would have ever appeared.
 

CAS Code Evidence
The first problem that arises when defining a security model on “block of codes” is to define the entity to apply security checks on, since code has nothing like a unique “user identity” (aka principal) as we can find in NTLM, Kerberos or any standard security model.

CAS identifies an assembly on its evidence, that is, a list of property name?property value pair that describes it. The CLR comes with a predefined set of “evidence categories” as listed in the following table
 

 

Evidence Description
Application directory The application’s installation directory
Hash Cryptographic hash such as SHA1
Publisher Software publisher signature; that is, the Authenticode signer of the code
Site Site of origin, such as http://www.microsoft.com
Strong name Cryptographically strong name of the assembly
URL URL of origin
Zone Zone of origin, such as Internet Zone

Here is a sample of the evidence list that makes an assembly identity.

Evidence Category Evidence Value
Strong name Public key: 01 34 67 9A CD
Simple name: TestApp
Version: 1.0.0.0
URL http://www.microsoft.com/test/application.exe
Site www.microsoft.com
Zone Internet
Publisher (no Authenticode signature)

 
Note that not all the assemblies have the same set of evidence since it depends on the host loading the assembly (for instance an assembly loaded from the file system will have no site evidence associated with it).

Know that some evidences are stronger then other, depending on how easy they can be tampered. For instance, the strong name evidence of an assembly is stronger then its site evidence (Websites and DNS can be hacked). It’s also possible to define custom application or system based evidence types. See the IEvidence interface on the .NET framework SDK for more info.
 

CAS Code Permissions
Now that we’ve assessed what we mean for an assembly identity we move on examining the kind of code permissions the CAS can deal with. We’ll then soon move to the next paragraph, where will examine how permissions are associated to code evidence.
In the table that follows you can see a list of the built in access permissions.

All the permissions in this list have a counterpart security class gathered in the System.Security.Permissions namespace. As you can see in the table, code access permissions are very grained, nevertheless, it’s possible to define your custom access permissions in the situation where built-in permissions cannot fulfill your needs. SeeCreating Your Own Code Access Permissions on the MSDN library for more info.
 

Code access permission Resource protected
DirectoryServicesPermission Directory services
DNS services
EnvironmentPermission Environment variables
EventLogPermission Event logs
FileDialogPermission File dialog boxes in the UI
FileIOPermission Files and folders on the file system
IsolatedStorgeFilePermission Isolated storage
MessageQueuePermission Message queues
OleDbPermission Databases accessed by the OLEDB data access provider
PerformanceCounterPermission Performance counters
PrintingPermission Printers
ReflectionPermission Type information at run time
RegistryPermission Registry
SecurityPermission Execute code, assert permissions, call unmanaged code, skip verification, and other rights
ServiceControllerPermission Running or stopping services
SocketPermission Connections to other computers via sockets
SqlClientPermission Databases accessed by the SQL Server data access provider
UIPermission Windows and other UI elements
WebPermission Connections to other computers via HTTP

Permissions Sets, Code Groups, and Code Access Policies
Code groups are the building blocks of security policies. A Code Group is made of an association between an evidence value, also known in this case as a membership condition, and a permission set (that gathers together a set of permissions).
For instance, a fictitious code group could be the WindowsUpdate code group defined as

URL=http://www.microsoft.com (evidence membership condition) / Everything (permission set).

A hierarchical structure of Code Groups defines a security policy. The .NET framework comes with three different security policies: Enterprise, Machine, User. Additionally an host can define application domain-level policy by calling the AppDomain.SetAppDomainPolicy method on the System.AppDomain class. The first three policies are typically set by administrator while the latter is eventually defined by developers.

The .NET framework comes with a number of built-in permission sets as shown below.

  • FullTrust
  • SkipVerification
  • Execution
  • Nothing
  • LocalIntranet
  • Internet
  • Everything

You can define additional custom permission sets if necessary gathering together the desired code access permissions listed in the previous paragraph. Note that you cannot assign directly a list of permission to a membership condition to define a Code Group.

Custom permission sets are defined in XML files and then loaded in the desired policy.

The code permissions an assembly is granted is made of the intersection of the permissions each policy assign to the assembly (unless the –Levelfinal attribute is specified). The order of policy level evaluation for the LevelFinal attribute is enterprise, machine, and then user. The application domain policy level, if present, is always intersected with other levels even if the LevelFinal attribute is in effect for one of those levels.

Now there is just thing left to explain: How a policy is applied to a given assembly, that is, how each policy, separately, builds up the list of permissions sets an assembly is granted. The procedure is as follows:
 

  1. CAS checks if the assembly can be granted membership to the root Code Group (this check always succeeds in a default configuration since the root Code Group is defined as membership: All Code Permission set: Nothing)
  2. CAS then evaluates if the assembly can be granted membership to the root’s child Code Groups (matching the assembly evidence with the Code Group membership condition). For any granted membership the corresponding permissions sets are added.
  3. CAS proceeds evaluating the membership of the assembly against the Code Groups that are child of a Code Group the assembly has been granted membership in the previous step. CAS ignores Code Groups sub-trees that are child of Code Groups that have not been granted membership in the previous step.
  4. Back to step 3 till all paths have been covered.
     

This logic is described graphically in the picture below, where green blocks represent granted membership; red blocks represent denied membership and yellow ones are code groups that are not evaluated.
 

Code groups, permission sets and policy structures can be queried and modified using the caspol.exe command line tool or using a much more friendly tool called the Microsoft .NET Framework Configuration Management Console snap-in.
Here I’ve included a snapshot of the CAS entities as shown by the snap-in
 

 

Code Access Permission Requests
CAS let’s you declare via a set of attributes at assembly level what permissions (or permissions sets) your code

  • needs at minimum
  • optionally needs
  • refuses

thus interacting/modifying the permissions assigned by the evidence vs. security policy mechanism described in the previous chapters.
In this code snippet a VB.NET assembly refuses the permissions associated with the FullTrust permission set and requires the File I/O permission.

When the CLR loads the assembly it evaluates the assembly permission requests against the permissions that have been assigned to it by CAS policies. If the assembly has not been granted the RequestMinimum permissions the assembly won’t load and an exception will be thrown, additionally the CLR will, eventually, remove permissions that have been granted to the assembly due its evidence but that have been explicitly refused by RequestRefuse declarations.

CAS Requests are not compulsory, still there are number of reason why you would won’t to evaluate to use them: the main reason is to avoid having to assembly loaded if the permissions restrictions would make its functionalities unacceptably limited.
Moreover, when declaring CAS requests your code is not required to gracefully handle any and all situations where not being granted some permission might prevent it from executing properly.
One last advantage is that putting permissions requests into the assembly metadata let administrators easily explore the assembly requirements with the Permission View tool (Permview.exe) to adjust, eventually, security policies.

Code Security Demands
What we’ve covered till at this point is just half of the story. You might have been asking yourself: what if an evil component calls into a trusted component and ask to perform some sensitive tasks on its behalf ? Enter Security Demands.

When placing Imperative or Declarative security demands on your code you enforce only assemblies that have been granted the demanded permissions (according to their evidence) to call into your code.

Security Demands have the CLR parse the whole call stack to check if all the assemblies involved in the call have the required permission.

Making Declarative Security Demands is done using the standard attribute based mechanism and it can be done at assembly, class and method level specifying SecurityAction.Demand.

Public Shared Function ReadData() As String ...End Function

In the following code snippet the same permission demand is executed imperatively

Public Shared Sub ReadData() Dim MyFileIOPermission As New FileIOPermission (PermissionState.Unrestricted) MyFileIOPermission.Demand()End Sub

There are actually other two Security demands type in addition to the one described above: Link demand and Inheritance demand.

The former works as standard demand, but stops the stack walk to the immediate caller of the assembly.

Placing Inheritance demand at class level you request specific permissions to classes that inherit from it. If you place an inheritance demand on the method level, the specified permission will be applied to all overridden methods in a derived class.

Overriding Demands Checks
There might be situations where you might want have your code perform (directly or calling into other assemblies) some actions that require permissions other assemblies in the upper call stack should not necessarily have.

For instance: assembly A is used as an entry point for assembly B downloaded from the internet. Among other things assembly A calls into assembly C that writes some info into a log file.
If assembly B makes a FileIO security request, this security request would fail since, walking up the call stack, the CLR would find that assembly A is not allowed to perform such action.

To have CAS stop walking the stack on a specific permission check request, the assert method come to rescue: assembly A will call

 _Public Sub MakeLog()

or, imperatively:

Dim MyFileIOPermission As New FileIOPermission (PermissionState.Unrestricted)MyFileIOPermission.Assert()

Of course, Assert is ignored when called against a permission not granted to the assembly trying to asserting it.

Calling RevertAssert or RevertAll removes an active Assert.

Calling SecurityAction.Deny on the permission class object has the opposite effect of calling Assert: it blocks a stack walk on the method that called deny, even if the assembly had enough rights to have the security check succeed.

Finally, calling SecurityAction.PermitOnly is similar to Deny: in both cause stack walks to fail when they would otherwise succeed.

The difference is that Deny specifies permissions that will cause the stack walk to fail, but PermitOnly specifies the only permissions that do not cause the stack walk to fail.

In the following picture the net effect on the permissions available after a call to Assert, Deny or Permitonly is shown graphically.


 

Conclusions
Literature on code access security is still rather scarce at present. Certainly this feature lets us tighten the security of our applications, covering security domains where identity based security is inadequate or inappropriate.
I bet all of you have thought of a couple of situations where CAS could have been helpful in your previous projects, the .NET programmer community will learn in the future the best effective way to take full advantage of this new feature.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist