How to provide extra trust for an Internet Explorer hosted assembly

A common scenario for developers is that they create an assembly that is to be hosted
by Internet Explorer, but requires more trust than would be given to it by default
by the Internet or LocalIntranet zone code groups. Often the first attempt at
fixing this involves signing the assembly with a strong name or an X509 certificate
and then creating a code group that gives that signature full trust. Developers
are often surprised when they continue to see security exceptions thrown even after
they do this.

The reasoning behind the security exception is AppDomains. Before IE can load
your assembly, it must create an AppDomain to load the assembly into. When it
creates this AppDomain, it assigns it all the evidence it knows without loading your
assembly, the URL and zone that it is loading from. Since the AppDomain itself
does not get any evidence about the signature that your assembly has (it can't since
the assembly is not loaded yet), it will not match the code group that you created
giving extra trust. Now when a security demand occurs, a stack walk begins.
When your assembly is checked for correct permissions, it passes, and the stack walk
continues until it gets to the AppDomain. Since the AppDomain doesn't have the
permissions that are required by this demand, it causes the SecurityException to be
thrown.

There are two ways to work around this problem. The first way is to create a
code group that matches the evidence that the AppDomain is getting, using a SiteMembershipCondition
or a ZoneMembershipCondition, and trust that. The other is to Assert() all the
permissions that your assembly needs at its entry points. This prevents the
stack walk from getting to the AppDomain level, therefore preventing the AppDomain
from causing a SecurityException to be thrown.

This depends on which version of the framework your embedded assembly is targeting. With v1.0 of the framework, this is not possible without having the client trust your code. However, with v1.1 and higher, all code run off the internet has same site web access back to where they are hosted from. You can use the System.Web.HttpWebRequest class to gain access back to this site.

This is the first explanation of the security in the .Net Framework that I’ve found that makes sense. I’ve been trying to create WinForm controls that use the PropertyGrid as a component and have been failing miserably in terms of getting all the functions to work properly.

I figured out the strongname/code group relationship that is required and am able to get the control to work partially. However, I can’t get all the functionality of the PropertyGrid to work in IE. What I’ve been stuck on is how one would get expandable object types and custom UItypeeditors to work in the control while in IE. I’ve coded the control and when it runs in an executable, the expandable properties work and I can use the ellipsis buttton to call my custom UItypeeditor. The problem is that hosted in IE, the expandable property doesn’t expand and the ellipsis button is not available.

From what you’re saying is that IE hosts the control in an AppDomain that doesn’t have enough permissions to use expandable types or custom UItypeeditors. So, I have to assert the permissions for my public classes and methods? Would this apply to all classes and methods (including those for the expandable types and UItypeeditors)?

How do you assert the permissions? Is that when you prefix the class with :

Asserting permissions is different from creating a LinkDemand. To assert permissions, at every entry point to your control (the control’s constructor as well as every method called from your HTML page or by IE), you need to create the permissions that the control needs to execute (i.e. new FileIOPermission(PermissionState.Unrestricted); ), and then call their assert method.

This is an interesting question, which I’ll write a blog post about this week. The quick answer is that using the default security objects you can’t. The best you can do is grant same-site web access, and communicate using HTTP or HTTPS. However, if you write a custom security object to create same-site socket permissions, this is achievable. I’ll post a link back here when I write the blog.

I need help. I am trying to load a usercontrol in IE. I know that the AppDomain has not enough security permissions. I don’t think that asserting permissons works for me. Everything works fine for me when I use the site condition with my machine name. When I try with the strong name condition it doesnt load at all. Can you provide a full source of a window control than can be load in IE using ONLY his strong name as a security condition? There is no documentation on this. Thank you for your time.

I see that you understand that the problem is with the permission set associated with the AppDomain, and not with the assembly itself. Now what you need to think about are what evidence is available to IE at the time the AppDomain is created (and its PermissionSet assigned). Since the AppDomain must be created before the assembly is loaded into it, nothing specific about the assembly is available (including the strong name, or authenticode signature). Instead, you have only the site, URL, and zone evidence to work with. In order to get your control to work, you’ll need to use a membership condition that matches one of these types of evidence to grant trust to your control. Since you say that you’ve gotten this to work already on your dev machine with the site membership condition, I see that you didn’t have a problem getting that far.

Is there a specific reason you need to move away from using the site membership condition?

Hi, I’m not very familiar with .NET security (or .NET for that matter), but I did develop a user control that is embedded in IE and am getting the problems that you described in the blog.

I’m not sure how to word this, but calling Assert() on a Permission will only work if my user control is allowed to be able to get access to whatever I’m asking permission for right? For example, I tried new WebPermission(PermissionState.Unrestricted).Assert() and got a SecurityException. I found that only when I add my dll to a code group in the client machine with some sort of trust would the Assert() method call work.

Am I completely off track here?

So is it even possible for the client machines (anywhere on the internet) to load my application (a dll embedded in a webpage) without making changes to their security policy on their machine?

You’re correct, Asserting a permission requires that you be granted the permission in the first place. This post is mostly about getting the control to not throw once it has already been granted permissions.

If you need to have the user’s machines trust your code, you have two options. The easiest would be to simply code with only those permissions that appear in the Internet code group. If that’s not a possibility, then another option is for you to modify the policy of your local machine so that your control is trusted (see my post here for information on that: http://blogs.msdn.com/shawnfa/archive/2003/06/20/57023.aspx … I recommend trusting based on strong name), and then creating an .MSI deployment file out of the policy, and placing that on your website. Have users install the custom policy before running your control, and then your Asserts should work fine.

I don’t think that the .MSI deployment file is a viable solution since we don’t want our users to have to deliberately download and install something.

The actual problem I’m having is that my windows control needs to access an .aspx page that is located on the same web server that the control .dll is from. If the user (who could be connecting from anywhere on the internet) who downloaded the .dll is not connected to the internet through a proxy server, everything works perfectly. But if the user is connected through a proxy server, I get a HTTP 407 Authorization Required error when my code does a httpwebrequest.GetResponse(). I realized that HttpWebRequest has a Proxy property, however whenever I try to access that property, I get a SecurityException stating that the request for type WebPermission has failed. I tried to Assert a WebPermission with PermissionState.Unrestricted as parameter, but that caused a SecurityException as well. I’m assuming this is because my application isn’t granted unrestricted WebPermission. Given this information, do you know if I need any kind of extra permissions that are not available just by adding the site that the control .dll is from to the Trusted Sites list in IE?

Thanks for this wonderful insight. I actually tried creating a limited permission appdomain with codegroup having only named permission "Execution". To provide full access to my own assemblies I added them as fulltrust assemblies. Also I created another fulltrust codegroup for these assemblies using UnionCodeGroup and added it as a child of root codegroup. However I still get the security exception. It would be nice If you could provide a code snippet based on strongnamemembershipcondition to clarify doubts of mortals like us. Thanks.

However, as soon as I override PreTranslateMessage in my class my control fails to load – I just get the red X. From the docs this just requires UIPermissionWindow.AllWindows. I really need these lower-level overrides for my control.

Issue #2. If I use the strong name method my control fails to load – red X again. Doesn’t matter what code I put in the class (ie. I don’t call any code that requires special permissions).

FYI, in answer to the "How can I give a SocketPermission to managed code in IE?" question, you can assert multiple stack walk modifiers / permission sets simultaneously to create a socket by doing something like this:

FYI, I recently ran into an issue where I create a CAG that fully trusted the strong name key through a Deployment Package, but when I loaded the page with the assembly it would throw SecurityExceptions or tell me in the IE Debug log that "that assembly does not allow partially trusted callers", when it certainly did trust them.

I was developing on Win 2000 with 1.1 (and this worked fine) and then tested on XP Pro SP2 with 1.1 and 2.0

The problem is that I was creating the CAG in the .Net 1.1 framework only and IE was using the .Net 2.0 Framework when it loads inside of its own app domain.

The fix was to create an identical CAG for the .Net 2.0 framework using mscorcfg or caspol.exe. I have to check for the newer framework version even though my app and installer only need 1.1.

This will be a maintenence issue, since IE uses the latest installed version of .Net for some reason, any ".Net Framework 2.1" upgrades will break this in the same way.

I have a Windows Forms app running in IE which needs to make use of a web service (.ASMX page) hosted at the same site as the DLL is downloaded from. It’s all built in .NET and I’m using the proxy class that Visual Studio builds to talk to the ASMX page.

However, even though it only tries to contact the same site, I get web permission exceptions when running in the Local Intranet zone, which according to the documentation ought to allow this by default. If I bump up the zone to full trust, everything works – but clients don’t like me asking them to do this!

Signing the assembly is not (yet) an option as it simply doesn’t run in that case.

You should be able to get details from the SecurityException about what you were actually granted and what demand failed — from there you can see the difference between the WebPermission you have and the one that you’re trying to use.

Hi. I am developing an ie based project which needs to have full-trust in internet zone for it to function well. I was just wondering what can i do if i want my specific sight (and only my sight) to have full trust in internet zone of clients viewing it? can i place my web address in their registry or sumthing then it will detect that this site has full trust in internet zone?

I created an asp application that creates a word object,fills in the necessary content and sends this mail as an attachment..teh application is working fine from the server which is my machine..but when acessed from a client machine it throws an object required error..Can someone plz help me on this as i am stuck up on this for 1 week..plz help

I want to display a UserControl on a web page using an tag. The
control has dependent assemblies that are quite large. These assemblies are
installed on the client (not in GAC), but I don’t see a way to use them. The dependent
assemblies are always download from the web server resulting in intolerable
performance. I have tried using an application configuration file to specify probing privatePath, but the
Fusion log reports that it won’t probe the specified client location because
that is outside the appbase.

In the old days of ActiveX, It was possible to download and install whatever was needed and simply activate it on the web page after that. This provided huge value in terms of good performance, ability to do things on the client not allowed/supported by the browser, and simplicity. I’m hoping there is a way to gain those benefits but with the much better security offered by code access control and UserControls.

No, it is not currently possible to elevate your permissions on the client side for a control. The closest option is ClickOnce which will allow you to prompt and elevate an application — although this application will not be hosed in the web page.

I’m not a web service authentication expert, so I’m not sure how to answer your question. I recommend checking out the MSDN forums, where someone will be able to help you with your authentication questions.

I’m annoyed at the fact that there is no viable solution for this at the enterprise level today. Orcas isn’t out yet. Clickonce has its issues. On a fundamental level, elevating the code trust for a site, url or zone in order to have a usercontrol run flies in the face of security. It is just as bad as running an ActiveX because a site, zone or url receives more permissions than it requires. Roll that out to the enterprise and it opens up a massive hole ripe for hacking. What do we do TODAY to make this work in a way that is safe for an enterprise? The *solutions* provided are bandaids that do not address the underlying issue. I’m not referring to this within the context of one or two desktops, i’m putting this in the context of a government or large instituion with hundreds of thousands of client machines. You can’t reasonably expect to raise the permissions of a site, zone or url to full trust? Or did i take a wrong turn somewhere?

I’m not sure I entirely understand your points. ClickOnce aside (it’s not really the same thing — it allows for installing applciations locally, whereas we’re talking about hosting a control in a web page here), let me look at your other points.

You don’t have to elevate a Zone, Site, or URL to get this scenario to work. I totally agree that elevating a zone is almost certainly the wrong way to go. You can use StrongName or Publisher evience to elevate your control, however that means the AppDomain itself will not be trusted. To solve this, you can place Asserts at the entry points of your control so that demands never hit the AppDomain boundary.

You can’t do this without modifying anything on the client machine. (Think of how much malware would love to be able to elevate on client machines!).

In Orcas there is a feature that allows controls to carry a manifest which states it needs to be trusted, and if that manifest is signed by a trusted publisher (you’ll have to push the trusted publisher down to client machines), then it will run with the requested permissions.

First of all Thank you for maintaing this blog. This is very usefull and informative. There is very little (if any) documentation available on this issue. Here is my situation. I have a user control which I am hosting in IE. This is signed using a strong name. I have created a new CodeGroup and the membership condition is the publik key part of the strong name. Everything works fine in both the Intranet and Internet zone in IE. Except, when a modal form pops up in the Internet Zone, it has a .NET security warning bubble associated with it, warning not to enter password and other stuff on the dialog. ( The form/dialog does not have any textboxes on it). This does not happen in Intranet zone. I am confused as to the behaviour. I will really appreciate your input/suggestions for resolving this issue.

I have a .NET control hosted in IE, which uses WSE2 (Microsoft.Web.Services2.dll) to connect back to the server and download files which are later loaded into MS Office applications (Excel, Word, Outlook).

WSE2 requires FullTrust and does not trust partially trusted callers.

My solution so far is to set a URL/Site based policy entry, which grants FullTrust.

The problem is – how to deploy this policy with minimum client involvement?

1. Provide the power users with a document, which describes for them how to do the change using .NET Framework Configuration tool.

Problem – too much user involvement and .NET 2.0 doesn’t even come with Configuration tool (you have to install the SDK to get it – that’s way too much to ask from the end user)

Problem – while this might be considered somewhat OK for well established enterprise-wide situations – it’s completely ridiculous each policy “update” to wipe out everything else at that level. On top of that it seems that the msi toggles between install and uninstall no matter how it’s called. Also with the generated msi, there’s no way to change the URL/Site which is different for every client we have.

3. To deal with the above situation, I wrote an ActiveX control, which again is launched from a page to set the required .NET CAS permissions. As long as the user has enough Windows permissions and ActiveX controls are allowed, it doesn’t need anything else to “update” the .NET security policy (for the highest CLR version it finds on the machine). This worked just fine in XP…Then Vista came along…and ActiveX basically lost that ability. It’s signed, marked safe for Scripting and Initialization, but I don’t know of any way for the ActiveX to request elevated Windows permissions to run caspol.exe in order to update the policy. In an exe, I can embed a manifest and require admin rights. Then at runtime Vista will prompt for rights elevation if the user can in fact obtain them.