Freigeben über


Whidbey's New SecurityException

One of the more difficult things to debug with .NET 1.0 and 1.1 is the security exception.  With these frameworks generally the only information that you got was the state of the failed permission.  Due to the complexity of debugging security problems, most people just gave up and required that their code run in a fully trusted environment.  With Whidbey we've done a lot of work to beef up the security exception, and make debugging security issues even easier, in the process making it easier for developers to figure out the minimum set of permissions that their application needs to run under.

Limitations of the Current Implementation

Currently, the SecurityException contains four security specific properties.

  • GrantedSet provides the set of permissions that are granted to the assembly that failed.  This property does not get filled out every time an exception is thrown however.
  • PermissionState has the permission or permission set that caused the exception to be thrown
  • PermissionType is also not always filled out, when it is, it should contain if PermissionState is a permission, permission set, or permission set collection
  • RefusedSet contains the set of permissions that were refused by by the assembly that caused the security exception to be thrown

Generally, PermissionState is the only property that can be depended upon to always have a value.  This does not provide for a good user experience.

The Whidbey SecurityException

The Whidbey SecurityException adds several more properties, which together allow developers to figure out what code was causing a security problem.  The new properties are:

Name Type Description
Action SecurityAction the SecurityAction that failed the security check
Demanded object the permission, permission set, or permission sets that were demanded and triggered the exception
DenySetInstance object if a Deny stack frame caused the security exception to fail, then this property will contain that set, otherwise it will be null.
FailedAssemblyInfo AssemblyName AssemblyName of the assembly that caused the security check to fail
FirstPermissionThatFailed IPermission the first permission in failing PermissionSet (or PermissionSetCollection) that did not pass the security check
Method MethodInfo the method that the failed assembly was in when it encountered the security check that triggered the exception.  If a PermitOnly or Deny stack frame failed, this will contain the method that put the PermitOnly or Deny frame on the stack.
PermitOnlySetInstance object if the stack frame that caused the security exception had a PermitOnly permission set, this property will contain it, otherwise it will be null 
Url string URL of the assembly that failed the security check
Zone SecurityZone Zone of the assembly that failed the security check

As you can see, there's a ton more data available about the cause of the security exception in Whidbey.  However, as I noted above, even the current SecurityException properties don't get filled out properly all the time.  As part of the SecurityException enhancement work, we've gone through all the places in the BCL that throw exceptions and ensured that they've filled out as much of the SecurityException data as possible. 

So What Does a New Security Exception Look Like?

All of these extra properties provide a lot of information for developers to work with if they catch the SecurityException in their code.  But what happens if the exception goes unhandled?  The default behavior of spewing exception information to the screen will still provide a lot more information than was provided before.  For instance, if I tried to run my ProtectedData sample off a network share, with default policy in place, I'd end up with a SecurityException.  The debug spew for that exception would look similar to the following.

First comes the standard stack trace and exception type that failed.

Unhandled Exception: System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.DataProtectionPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
at System.Security.CodeAccessSecurityEngine.Check(PermissionToken permToken,CodeAccessPermission demand, StackCrawlMark& stackMark, Int32 checkFrames, Int32 unrestrictedOverride)
at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
at System.Security.CodeAccessPermission.Demand()
at System.Security.Cryptography.ProtectedData.Protect(Byte[] userData, Byte[] optionalEntropy, DataProtectionScope scope)
at CPD.Main() in \\shawnfa-build\c$\blog\ManagedDPAPI\CryptProtectData.cs:line 12

This is followed up by the SecurityAction that failed, the first failed permission, and the details of the demanded permissions. (From now on, I'm going to abbreviate the full assembly names.)

The action that failed was:
Demand
The type of the first permission that failed was:
System.Security.Permissions.DataProtectionPermission
The first permission that failed was:
<IPermission class="System.Security.Permissions.DataProtectionPermission, mscorlib ... "
version="1"
Flags="ProtectData"/>

The demand was for:
<IPermission class="System.Security.Permissions.DataProtectionPermission, mscorlib ..."
version="1"
Flags="ProtectData"/>

Next is a list of all the permissions granted to the assembly that failed the demand:

The granted set of the failing assembly was:
<PermissionSet class="System.Security.PermissionSet"
version="1">
<IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib ..."
version="1"
Read="USERNAME"/>
<IPermission class="System.Security.Permissions.FileDialogPermission, mscorlib ..."
version="1"
Unrestricted="true"/>
<IPermission class="System.Security.Permissions.FileIOPermission, mscorlib ..."
version="1"
Read="\\SHAWNFA-BUILD\C$\blog\ManagedDPAPI\"
PathDiscovery="\\SHAWNFA-BUILD\C$\blog\ManagedDPAPI\"/>
<IPermission class="System.Security.Permissions.IsolatedStorageFilePermission, mscorlib ..."
version="1"
Allowed="AssemblyIsolationByUser"
UserQuota="9223372036854775807"
Expiry="9223372036854775807"
Permanent="True"/>
<IPermission class="System.Security.Permissions.ReflectionPermission, mscorlib ..."
version="1"
Flags="ReflectionEmit"/>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, ..."
version="1"
Flags="Assertion, Execution, BindingRedirects"/>
<IPermission class="System.Security.Permissions.UIPermission, mscorlib, ..."
version="1"
Unrestricted="true"/>
<IPermission class="System.Security.Permissions.UrlIdentityPermission, mscorlib, ..."
version="1"
Url="file://shawnfa-build/c$/blog/ManagedDPAPI/CryptProtectData.exe"/>
<IPermission class="System.Security.Permissions.ZoneIdentityPermission, mscorlib, ..."
version="1"
Zone="Intranet"/>
<IPermission class="System.Net.DnsPermission, System ..."
version="1"
Unrestricted="true"/>
<IPermission class="System.Windows.Forms.WebBrowserPermission, System ..."
version="1"
Level="Restricted"/>
<IPermission class="System.Drawing.Printing.PrintingPermission, System.Drawing ..."
version="1"
Level="DefaultPrinting"/>
</PermissionSet>

Finally, the assembly that failed the permission demand is listed along with the method that called into the demanding code, and the Zone and URL evidence for that assembly.

The assembly that failed was:
CryptProtectData, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
The method that caused the failure was:
Void Main()
The Zone of the assembly that failed was:
Intranet
The Url of the assembly that failed was:
file://shawnfa-build/c$/blog/ManagedDPAPI/CryptProtectData.exe

Visual Studio Gets In On The Action

In addition to all the work done in the CLR to make debugging security exceptions easier, Visual Studio 2005 has done quite a bit of work as well.  When an unhandled SecurityException is thrown under the VS debugger, Visual Studio will look at all of the extra properties that are populated on that exception, and provide you with context sensitive help to solve the problem.

Visual Studio 2005 Security Exception Handler

As you can see in the screen shot, VS will highlight the line that caused the SecurityException, and shows a pop up dialog that tells you the permission that failed and provides several possible solutions for the problem.  In this case, there's not a lot of ways to get around the DataProtectionPermission demand, so the options that VS presents include turning this into a ClickOnce application or installing locally.  This help is based around the failing permission, so if a FileIOPermission failed, VS might suggest using IsolatedStorage instead.

The View Details link will, oddly enough, open up the View Detail dialog where you can inspect each property of the Security Exception yourself, in order to help you further track down security issues.

Debug-In-Zone

All that's fine and good, but when you develop on your local machine, you end up with FullTrust by default.  Forcing developers to modify their security policy to debug is not a good user experience, so again Visual Studio steps up to the plate, this time with a feature called Debug In Zone.

Debug In Zone Settings

By going to your project properties, and accessing the security tab, you can specify the set of permissions that you'd like to debug your application with.  For instance, if your goal is to have your application run with Internet permissions, then just select Internet from the drop down list.  You can also create a custom permission set that reduces down to the exact set of permissions that your app needs; the Calculate Permissions button, which will interface with PermCalc will help you with this goal.

With the changes to the SecurityException class and enhancements to the Visual Studio debugger, figuring out the cause of those hard to diagnose SecurityExceptions.

Comments

  • Anonymous
    August 01, 2004
    Excellent information. I'm wondering about the status of PermCalc. Are you still tweaking the heuristics? I hope so, because in B1 I find it does a poor job of identifying the permissions required for an application with, for example, a toolstrip and Web browser control. You should be able to catch this in static analysis, right?
  • Anonymous
    August 02, 2004
    Hi Peter,

    Yes, PermCalc is still under active development. However, we'd be interested to see the specifics of the cases it doesn't solve. If you could file us a bug report over on the Ladybug site (http://lab.msdn.microsoft.com/productfeedback/), that'd be great. Filing the report there will enter it into our internal bug tracking system, and we'll see if we already know about the scenario you're encountering and if not, the best way for us to fix it. Thanks!

    -Shawn
  • Anonymous
    August 03, 2004
    I'm interested as to why most of the SecurityException fields in the View Detail dialog don't contain a value, but simply contain a rather unhelpful string ...
  • Anonymous
    August 05, 2004
    Hi Julian,

    This is still a beta release of Visual Studio, and there are still bugs to be worked out. Things should be much nicer when the final version ships.

    -Shawn
  • Anonymous
    August 27, 2004
    Hi,

    Is there a raison why GrantedSet ou RefusedSet a not always set? Performance problem maybe?

    I don't really understand PermissionState.
    For instance I need ControlEvidence permission to display it, but need nothing for PermissionType that basically display the same thing I guess.

    thank you

    Fred
  • Anonymous
    June 16, 2005
    These are notes I took at Joel Pobar’s “What’s New in .NET 2.0” breakout session.
    New Features

    GZip...
  • Anonymous
    August 24, 2005
    There's a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,...
  • Anonymous
    August 31, 2005
    There's a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,...
  • Anonymous
    November 09, 2005
    How come my app works on my location machine but not through network shares? All Zones are on full trust on the server and still no go. Anyone know of a tutorial for that?
  • Anonymous
    November 10, 2005
    You need to check out:
    http://blogs.msdn.com/shawnfa/archive/2003/06/20/57023.aspx

    -Shawn
  • Anonymous
    March 02, 2006
    On Wednesday March 1, 2006 I conducted part one of a five part series titled “Security on the Brain”.&amp;nbsp;...
  • Anonymous
    November 18, 2006
    The AllowPartiallyTrustedCallersAttribute (affectionately referred to as APTCA from here on out), is