Securing the MEF Directory Catalog

2010/01/01

one comment

Securing the MEF Directory Catalog

 

during my MEF lecture, on of the attendant (a fellow from check-point) ask the following question:

"How can we secure our catalog?"

 

this is a really good point, because without securing our catalog,

hackers can exploit our extensibility model for injecting malicious code.

 

so can we defend our MEF gates?

the short answer is yes.

and the long one is yes but…

 

Secure techniques

I will mention 3 techniques, each defend our code on different layer:

  • IT layer
  • CAS (code access security) layer
  • Catalog layer (which involving some changes to the Directory Catalog)
    (I’m currently speaking with the MEF team trying to convince them to add the 3rd technique into the MEF core).

you may use all the 3 techniques together, for getting a multi layer protection.

IT level protection

the IT layer protection is very simple and straight forward,

all you have to do is to restrict the access privilege to the plug-ins directory,

in order to prevent none authorized  plug-ins deployment.

 

CAS (code access security) protection

because MEF is contract based (means that MEF will only discover parts that match specific contract),

we can defend our contract by using CAS technique like demanding specific strong name (or any other evidence).

the secured contract may look like:

Code Snippet
  1. [StrongNameIdentityPermission(SecurityAction.Demand, PublicKey = "00240000048...")]
  2. public interface ILogger
  3. {
  4.     void Write(string message);
  5. }

as we can see in line 1, by restricting the access to our contract we can prevent
none authorized code from implementing it.

 

Adding predicate to the MEF Directory Catalog

Note: the secured version of the Directory Catalog is not currently in the box,

but i hope it will get in before the release time.

if you want to use it now you can download the modified MEF bits from my sky drive here.

thinking about the security risk I came to conclusion that the

mitigation should handle just before the assembly loading.

first it is more efficient and second we cannot handle the security after the instantiation

because it will be to late (constructor code can be malicious too).

 

Directory Catalog API modifications

the only change needed in terms of  the public API is to add new constructor

to the Directory Catalog, which will get lambda expressions (predicate)

that will authorize the assembly loading (just before the actual loading).

the new constructor definition is:

Code Snippet
  1. public DirectoryCatalog(string path, string searchPattern, Predicate<AssemblyName> isAuthorized)

all you have to do is give a predicate with AssemblyName parameter so you restrict the

assembly loading upon the AssemblyName information.

using it may look like:

Code Snippet
  1. var catalog = new DirectoryCatalog(path, "*.*",
  2.                     info => info.KeyPair.PublicKey == …);

 

Summary

the MEF release is getting close, but I’m hoping that

this minor yet very important API change will get into the release.

so we will have an elegant way to secure our extension points out of the box.

 

Point of Interest

the code for the modified MEF code can be download from here.

 

if you interesting is which modification was needed at the MEF core level

in order to have this new API, I will describe it in this section.

actually as you will shortly see, I was changing only a few lines of code.

the reason that I decided to change the core rather of creating new catalog type was:

1. it seem like a feature that should ship as part of the MEF core.

2. because some of the changes was needed on internal methods,
    building new catalog would result with coping half of the MEF core.

 

Changes made step by step:

Step 1:

Code Snippet
  1. private Predicate<AssemblyName> _isAuthorized = (name) => true;
  2.  
  3. public DirectoryCatalog(string path, string searchPattern, Predicate<AssemblyName> isAuthorized)
  4. {
  5.     Requires.NotNullOrEmpty(path, "path");
  6.     if (isAuthorized != null)
  7.         _isAuthorized = isAuthorized;
  8.  
  9.     this.Initialize(path, searchPattern);
  10. }

the above is the code of the new DirectoryCatalog constructor that include the authorization predicate.

as you can see in lines 6,7 I’m storing the predicate in private member (line 1)

 

Step 2:

the DirectoryCatalog class is having private method that responsible for creating AssemblyCatalog.

Code Snippet
  1. private AssemblyCatalog CreateAssemblyCatalogGuarded(string assemblyFilePath)
  2. {
  3.     Exception exception = null;
  4.  
  5.     try
  6.     {
  7.         return new AssemblyCatalog(assemblyFilePath, this, _isAuthorized);
  8.     }
  9.     catch (FileNotFoundException ex) {   // Files should always exists but don't blow up here if they don't
  10.         exception = ex;
  11.     }
  12.     catch (FileLoadException ex) {   // File was found but could not be loaded
  13.         exception = ex;
  14.     }
  15.     catch (BadImageFormatException ex) {   // Dlls that contain native code are not loaded, but do not invalidate the Directory
  16.         exception = ex;
  17.     }
  18.     catch (ReflectionTypeLoadException ex) {   // Dlls that have missing Managed dependencies are not loaded, but do not invalidate the Directory
  19.         exception = ex;
  20.     }
  21.     catch (Security.SecurityException ex) {
  22.         exception = ex;
  23.     }
  24.     CompositionTrace.AssemblyLoadFailed(this, assemblyFilePath, exception);
  25.     return null;
  26. }

I was making 2 changes in this class:

1. at line 7, I added the authentication predicate to the AssemblyCatalog creation.

2. at lines 21-23, I added catch for security exception (so none authorized assemblies will be traced while the application will not crash)

 

Step 3:

adding internal constructor to the AssemblyCatalog

Code Snippet
  1. internal AssemblyCatalog(string codeBase, ICompositionElement definitionOrigin,
  2.     Predicate<AssemblyName> isAuthorized)
  3.     : this(LoadAssembly(codeBase, isAuthorized), definitionOrigin)
  4. {
  5. }

at line 3 you can see that I forward the authentication predicate to the LoadAssembly method.

 

Step 4:

the last modification was at the assembly loading level

Code Snippet
  1. private static Assembly LoadAssembly (string codeBase, Predicate<AssemblyName> isAuthorized)
  2. {
  3.     Requires.NotNullOrEmpty(codeBase, "codeBase");
  4.  
  5.     AssemblyName assemblyName;
  6.  
  7.     try
  8.     {
  9.         assemblyName = AssemblyName.GetAssemblyName(codeBase);
  10.     }
  11.     catch (ArgumentException)
  12.     {
  13.         assemblyName = new AssemblyName();
  14.         assemblyName.CodeBase = codeBase;
  15.     }
  16.  
  17.     if (!isAuthorized(assemblyName))
  18.             throw new SecurityException(assemblyName.Name + " is not authorized");
  19.     return Assembly.Load(assemblyName);            
  20. }

1. at the method signature I added the authorization predicate

2. at lines 17,18 we use the authentication predicate to determine whether the assembly

is authorized (this happens before the actual loading of the assembly)

 

Conclusion

with a few minor steps we got match secured catalog,

once again i hope that i will manage to get into the release bits.


Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

one comment

  1. Glenn Block2010/01/01 ב 13:31

    Hi Bnaya

    Great to see you taking intiative on putting together this catalog.

    As far as why we don’t have such a facility in the product, I explained that in the codeplex thread here: http://mef.codeplex.com/Thread/View.aspx?ThreadId=79489

    Reply