Wednesday, October 29, 2008

Don't Set Your Sharepoint App To Full Trust

I Know You've Done It

It happens all the time, SharePoint web applications are put in Full Trust simply because the developer can't be bothered to learn about his options, nevermind exercise them.

Don't feel bad if this sounds familiar, I've done it too. In fact we're both just two of many, a growing army of developers that simply "fix" the problem by setting the <trust level="Full" originUrl="" /> in the web.config. We move on with our lives and gleefully watch runtime exceptions disappear thinking we're doing the world a favor. Unfortunately we're also exposing our applications to unnecessary security risks and when the SharePoint content database gets mangled because some developer decided to let all code run in full trust...you're going to wish you'd read to the end of this post.

CAS For Dummies

Code Access Security (CAS) is all about protecting a bunch of code in a runtime environment (as in the .NET runtime) from other code. It's meant to provide hooks for you the developer, so that you can decide what kinds of code can call your libraries. You can demand that the calling code at least has a minimum set of privileges before you let them call your members/classes/assemblies. This is pretty handy, especially if you're planning on providing some dangerous functionality in the form of an API.

Let's pretend that you're writing an API that lets users write to a sensitive disk area. Well what happens if some sketchy code wants to use your library to do it's dirty work!? Even if the user who's running the code has access to the disk, the user doesn't necessarily know what the application is doing, they could have gotten this off of Astalavista.com...they only really know what the UI is telling them.

We're trying to stop some sketchy application from using your API to perform dangerous operations on disk.

Shields Up

Enter code access security. Leveraging CAS you can put special attributes on your code that ensures that the calling code at least have certain privileges. If they don't, the runtime throws a security exception.

In the block below, the AccessSecretArea() method only runs if the calling code already has access to "c:\windows\system32\secretplace". We can be assured that this method isn't going to elevate the privileges of untrustworthy code downloaded off the Internet and run unwittingly by some callous user. Remember that this has nothing to do with the rights of the user, it has to do with the trustworthiness of the calling code.

[FileIOPermissionAttribute(SecurityAction.LinkDemand,
Read="C:\\windows\system32\secretplace")]
public string AccessSecretArea()
{
//Go get content from a sensitive area on the computer...
}

In the code below we ensure that the calling code at least has rights to access the SharePoint object model. Otherwise the .NET runtime tells the calling code to hit the road.

[SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true)]
public SPSite OpenWeb(string url)
{
//Go get some Sharepoint API object.
}

How Permissions Are Set

So how does your code get permissions assigned to it?

It can happen in a couple of ways:

  • Code Access Security Policy on the computer (held in Administrative Tools->.NET Configuration). This normally sets trust levels for non web application code from different zones (Local, Intranet, Internet, Trusted Sites, Untrusted Sites)
  • Trust level explicitly set in web.config or bubbled down from the web.config held in c:\windows\microsoft.net\Framework\[version]\Config\web.config. Web Applications can dictate the trust level they want to run at with the <trust level="Full"> tag. The options for ASP.NET are Full, High, Medium, Low, Minimal. Out of the box, ASP.NET web applications run in full trust. Good idea?...who knows.
  • Permissions explicitly set in custom policy files. These files let you give certain assemblies in an application more trust than others. SharePoint creates two such custom policy files WSS_Minimal (default) and WSS_Medium. You can set them like so: <trust level="WSS_Medium" />

What Permissions Come With Which Trust Level?

Glad you asked. The table looks like below. It reads like so; when your app is running at trust level [column name], it gets [contents of cell] privileges for the [row name] permission group. Lets have a look.




Trust Level
PermissionFullHighWSS_MediumMediumLowWSS_MinimalMinimal
Environment**Read: TEMP, TMP, OS, USERNAME, COMPUTERNAMERead: TEMP, TMP, OS, USERNAME, COMPUTERNAME---
FileIO**Read, Write, Append, PathDiscovery:Application DirectoryRead, Write, Append, PathDiscovery:Application DirectoryRead, Path Discovery: Application Directory--
IsolatedStorage**AssemblyIsolationByUser, Unrestricted UserQuotraAssemblyIsolationByUser, Unrestricted UserQuotra1 MB quota AssemblyIsolationByUser--
Reflection*ReflectionEmit-----
Registry*------
Security*Execution, Assertion, ControlPrincipal, ControlThread, RemoteingConfigurationExecution, Assertion, ControlPrincipal, ControlThread, RemotingConfigurationExecution, Assertion, ControlPrincipal, ControlThread, RemotingConfigurationExecutionExecutionExecution
Socket**-----
WebPermission**Connect to origin host (if configured)Connect to origin host (if configured)---
DNS****---
Printing*Default PrintingDefault PrintingDefault Printing---
OleDBPermission*------
SqlClientPermission*SqlClientAllowBlankPassword=falseAllowBlankPassword=false---
EventLog*------
Message Queue*------
Service Controller*------
Performance Counters*------
Directory Service*------
SharePointPermission*-Object Model----
WebPartPermission*-Connections--Connections-

* = All Privileges for that permission group
- = No Privileges for that permission group

This speaks to why people often get the following exception when running code in SharePoint that tries to access to object model. Notice in the table above that WSS_Minimal (which is the default trust level that WSS ships with) doesn't have CAS rights to get at the object model. Hence the exception.

Request for the permission of type 'Microsoft.SharePoint.Security.
SharePointPermission, Microsoft.SharePoint.Security,Version=12.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c' failed.

When these kinds of exceptions happen (CAS exceptions that is, you have three options). You can either:

  1. Raise the trust level of the application so you get the permissions you need.
  2. GAC your assemblies (so that they run in full trust and get the permissions needed).
  3. Leave your assemblies in the Bin folder and author a custom policy file.

The pros/cons are detailed below. They were taken from here.


Option Pros Cons
Increase the trust level for the entire application. (ie. change trust level in web.config) Easy to implement.In a development environment, increasing the trust level allows you to test an assembly with increased permissions while allowing you to recompile assemblies directly into the BIN directory without resetting IIS. This option is least secure.This option affects all assemblies used by the virtual server.There is no guarantee the destination server has the required trust level. Therefore, Web Parts may not work once installed on the destination server.
Create a custom policy file for your assemblies. Recommended approach.This option is most secure.An assembly can operate with a unique policy that meets the minimum permission requirements for the assembly.By creating a custom security policy, you can ensure the destination server can run your Web Parts. Requires the most configuration of all three options.
Install your assemblies in the GAC. Easy to implement.This grants Full trust to your assembly without affecting the trust level of assemblies installed in the BIN directory. This option is less secure.Assemblies installed in the GAC are available to all virtual servers and applications on a server running Windows SharePoint Services. This could represent a potential security risk as it potentially grants a higher level of permission to your assembly across a larger scope than necessaryIn a development environment, you must reset IIS every time you recompile assemblies.Licensing issues may arise due to the global availability of your assembly.

Customizing A Policy File

A great alternative to raising the trust level for the entire application, or GAC'ing your assemblies is to simply create a custom policy file that gives the assembly in question the trust level or permissions you have in mind.

Because this post is already getting long, I'm going to point to do a set of instructions in a future post.

Epilogue

The moral of the story is that by blindly cranking the trust level of your application you're allowing ANY code in that web application to run with additional CAS privileges you just handed out (see table above).

While this might have been cool when you were an ASP.NET developer and there were a finite amount of web parts/features running around, remember that SharePoint is a platform where other developers, administrators and even worse...information workers are actively installing prototyping web parts from god knows where. If you value your SharePoint instance, you really don't want to trust all that code. In fact, you should consider living in a bomb shelter and trusting no one...

X Files - Trust no one.

Best,
Tyler

9 comments:

Anonymous said...

This is a realy great post.
Thank you.

spgeeks said...

Brilliant!!

Please add a "Do Not Delete" sticker on this post... :-) This had great value to me.

Christian said...

Great article! However, I have put my assembly in to the GAC and still I am getting a security exception when calling System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteID();

Anonymous said...
This comment has been removed by a blog administrator.
Serhiy said...

Thank you!!! It's great!

Joss said...

Making a custom CAS policy seems like the best way, but in reality it's incredibally hard to actually get working. I've been trying for days, and have followed many examples, but nothing seems to work. If no other developers are making web parts on your farm surely setting the trust to full isn't going to be that bad?

Why do Sharepoint webparts have to be so fiddly and difficult to deploy. You spend three times longer on deploying and security stuff than on the actual writing code!!!

Anonymous said...

Awesome!!! I agree with spgeeks!!! Please "DO NOT DELETE"

Moutasem al-awa said...

I have read about CAS 100 times but this is the first time i understand it in a nutshell.. It is simple but the headache in configuring the stuff. Any way security is a must and to respect it you should do some additional work.

Great one thanks,

Anonymous said...

Good article!!.This information was very useful.