Printer Friendly Version      Send     
Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
Security
Security Guidance
Guidelines
 Security Guidelines: .NET Framework...
Security Guidelines: .NET Framework 2.0
 

Patterns and Practices home

patterns & practices Developer Center

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Chaitanya Bijwe

Microsoft Corporation

October 2005

Applies To

  • .NET Framework 2.0

Summary

This module presents a set of consolidated .NET Framework 2.0 security guidelines. The guidelines are organized into categories where mistakes are most often made, such as assembly design considerations, class design considerations, strong names, authentication and authorization, exception management, file I/O, and others. Each guideline explains what you should do and why you should do it, and then explains how you can implement the guideline. Where necessary, the guidelines refer you to companion How To modules, which provide detailed step-by-step instructions for more complex implementation procedures. This guideline module has a corresponding checklist that summarizes the security guidelines. For the checklist, see "Security Checklist: .NET Framework 2.0." It also includes an index of security guidelines for .NET Framework 2.0 applications.

Contents

Objectives
How To Use This Module
What's New in 2.0
Index of Guidelines
Assembly Design Considerations
Class Design Considerations
Strong Names
APTCA
Exception Management
File I/O
Registry
Communication Security
Event Log
Data Access
Unmanaged Code
Delegates
Serialization
Threading
Reflection
Obfuscation
Cryptography
Sensitive Data
Unmanaged Code
Companion Guidance
Additional Resources

Objectives

In this module, you will learn how to do the following:

  • Design assemblies with knowledge of your target trust environment.
  • Use appropriate class design to reduce attack surface area.
  • Determine when and how to use strong names.
  • Determine the risks introduced with AllowPartiallyTrustedCallersAttribute (APTCA).
  • Develop robust exception management.
  • Address canonicalization issues when your application accepts file names and paths.
  • Protect sensitive data in the registry.
  • Protect sensitive data passed over the network.
  • Avoid sensitive data in the event log.
  • Address data access security.
  • Minimize risk while calling delegates.
  • Avoid serializing sensitive data and do not trust serialized data.
  • Avoid threading vulnerabilities.
  • Minimize risk when your application calls unmanaged code.
  • Protect against reflection attacks.
  • Determine when to use obfuscation.
  • Use cryptographic services to protect sensitive data.

How to Use This Module

To get the most from this module, you should:

  • Use the index to browse the guidelines. Use the index to scan the guidelines and to quickly jump to a specific guideline.
  • Learn the guidelines. Browse the guidelines to learn what to do, why, and how.
  • Use the companion How To modules. Refer to the associated How To modules for more detailed step-by-step implementation details. They describe how to implement the more complex solution elements required to implement a guideline.
  • Use the companion checklist. Use the associated checklist as a quick reference to help you learn and implement the guidelines.

What's New in 2.0

.NET Framework version 2.0 introduces many new security features. The most notable enhancements are:

  • Full trust assemblies now satisfy any code access security demands. In .NET 2.0, any fully trusted assembly will satisfy any demand, including a link demand for an identity permission such as a System.Security.Permissions.StrongNameIdentityPermission that the assembly does not satisfy.
  • Enhanced security exception information. The System.Security.SecurityException object has been enhanced to provide more information in the case of a failed permission.
  • DPAPI managed wrapper. In the .NET Framework version 1.1 you had to use P/Invoke to access the Win32 Data Protection API (DPAPI) functions. In the .NET Framework version 2.0, you no longer need to use P/Invoke. Instead, you can use the new ProtectedData class. ProtectedData contains two static methods: Protect and Unprotect. To use DPAPI to encrypt data in memory, you can use the new ProtectedMemory class. Note that managed code requires the new DataProtectionPermission to be able to use DPAPI.
  • Secure string type. The System.Security.SecureString type uses DPAPI to ensure that secrets stored in string form are not exposed to memory or disk sniffing attacks.
  • XML encryption. The System.Security.Cryptography.Xml.EncryptedXML class can be used to secure sensitive data, such as database connection strings, that must be stored on disk.
  • Programming of ACLs and ACEs. You can now program access control lists (ACLs) and access control entities (ACEs) directly from managed code by using the System.Security.AccessControl namespace.
  • Programmatic Active Directory management. You can now perform management tasks for Microsoft Active Directory® directory service by using the System.DirectoryServices.ActiveDirectory namespace. Data in the directory can be accessed with the System.DirectoryServices namespace
  • Security context for secure asynchronous code. It is now easier to write secure asynchronous code. The System.Security.SecurityContext class allows you to capture the security context of a thread, including code access security markers such as permit and deny and the thread impersonation token, and restore the context on another thread.
  • Secure communication between hosts. .NET Framework version 2.0 provides a set of managed classes in the System.Net.Security namespace to enable secure communication between hosts. This allows you to implement both client and server-side secure channels by using SSPI or SSL. These classes support mutual authentication, data encryption, and data signing.
  • Remoting TCP channel. The System.Runtime.Remoting.Channels.Tcp.TcpChannel class now uses SSPI to support both encryption and authentication. This makes it easier to develop secure remoting without the need for custom code.
  • Remoting IPC channel. The new System.Runtime.Remoting.Channels.Ipc.IpcChannel class is ideal for communication between components on the same physical computer. The underlying implementation uses named pipes that can be secured with ACLs.
  • Simple sandboxing. In .NET Framework version 1.x, to set up a sandboxed application domain (for example, to host untrusted code), you had to create an application domain policy level, create a series of code groups, and define the permission sets that would be granted to each one. In .NET Framework version 2.0, you can use a new overload of the static AppDomain.CreateDomain method to perform all of this work.
  • Global assembly cache means full trust. Assemblies in the global assembly cache are always granted full trust, regardless of the local computer's security policy.
  • Full trust means full trust. Full trust assemblies are never granted any code access security protection.
  • Security transparency. You can now mark assemblies with the System.Security.SecurityTransparentAttribute to let the common language runtime (CLR) know that your code will not perform security-sensitive code access security operations, such as asserting permissions or using stack walk modifiers to escalate privileges. If your code or any code you call attempts such operations, a security exception is generated. This is particularly useful if your code loads third-party plug-ins.
  • Loading code for inspection only. The new Assembly.ReflectionOnlyLoadFrom method allows you to load code purely to examine its members. The loaded code is not allowed to run.
  • OleDB provider supports partial trust. The System.Data.OleDb managed provider no longer requires full trust. Code just requires the OleDbPermission. This allows partial trust developers to access non-SQL databases. For ASP.NET applications, this permission is not granted by medium trust policy, although you can create custom ASP.NET policy files to allow partial trust ASP.NET applications to use OLE DB data sources.
  • SMTP code access security permission. The new System.Net.Mail.SmtpPermission is used to determine which code can send e-mail.

Index of Guidelines

Assembly Design Considerations

Class Design Considerations

Strong Names

APTCA

Exception Management

File I/O

Registry

Communication Security

Event Log

Data Access

Delegates

Serialization

Threading

Reflection

Obfuscation

Cryptography

Sensitive Data

Unmanaged Code

Assembly Design Considerations

One of the most significant issues to consider at design time is the trust level of your assembly's target environment. This trust level affects the code access security permissions granted to your code and to the code that calls your code. The trust level is determined by code access security policy defined by the administrator, and it affects the types of resources that your code is allowed to access, as well as the other privileged operations it can perform.

When designing your assembly, you should:

  • Identify your target trust environment.
  • Explicitly design your public interface.

Identify Your Target Trust Environment

If you develop partial trust code, you should identify the permissions that will be available to your code, and you should understand which APIs require additional permissions. This is important because partial trust code is unable to access all methods and resources that code running with full trust can access. Typical partial trust scenarios include:

  • An ASP.NET application that runs with medium trust. Examine the Web_MediumTrust.config file in the %windir%\Microsoft.NET\Framework\{version}\CONFIG directory to see the permissions granted to your code.
  • An application downloaded from the Internet. Use the Microsoft .NET Framework Configuration tool or Caspol.exe to see the permissions granted to code running in the Internet zone.
  • An application that runs from a file share. Use the Microsoft .NET Framework Configuration tool or Caspol.exe to see the permissions granted to code running in the intranet zone.

Explicitly Design Your Public Interface

Think carefully about the types and members that form part of your assembly's public interface. Design your interfaces at the beginning of your project, and use a well-designed, minimal public interface. Use friend assemblies to allow other assemblies to access internal and protected members. This is important because it limits your assembly's attack surface by minimizing the number of entry points.

Class Design Considerations

In addition to using a well-defined and minimal public interface, you can further reduce your assembly's attack surface by designing secure classes. Secure classes conform to solid object-oriented design principles, prevent inheritance where it is not required, limit who can call them, and limit which code can call them. The following recommendations can help you to design secure classes:

  • Restrict class and member visibility.
  • Consider using the sealed keyword.
  • Restrict access to your code.
  • Do not trust input.
  • Use properties to expose fields.
  • Use read-only fields appropriately.
  • Use private default constructors to prevent unwanted object instantiation.
  • Make static constructors private.

Restrict Class and Member Visibility

Class and member access modifiers allow you to restrict the callers of your code. The fewer entry points (public interfaces) you have in your code, the smaller your attack surface is and the easier it is to protect.

Use the most restrictive access modifier possible for your code. Use the private access modifier wherever possible. Use the protected access modifier only if the member should be accessible to derived classes. Use the internal access modifier only if the member should be accessible to other classes in the same assembly.

Note   Access modifiers are enforced at compile time only. When malicious code runs in a full trust environment, it could use reflection or unmanaged pointers to bypass these visibility restrictions.

Consider Using the Sealed Keyword

You can use the sealed keyword at the class and method level. In Visual Basic .NET, you can use the NotInheritable keyword at the class level or NotOverridable at the method level. If you do not want anyone to extend your base classes, you should mark them with the sealed keyword.

Before you use the sealed keyword at the class level, you should carefully evaluate your extensibility requirements. It is especially important to seal a class in the following situations:

  • The class contains security secrets, such as passwords, that are accessible through protected APIs.
  • The class contains many virtual members that cannot be sealed, and the type is not designed for third-party extensibility.

You can also seal individual methods and properties within a class. For example, if you derive from a base class that has virtual members and you do not want anyone to extend the functionality of the derived class, you can consider sealing the virtual members in the derived class. Sealing the virtual methods has performance benefits because it makes them candidates for inlining and other compiler optimizations.

Consider the following example.

public class MyClass{ 
  protected virtual void SomeMethod() { ... } 
}
  

You can override and seal the method in a derived class, as follows.

public class DerivedClass : MyClass { 
  protected override sealed void SomeMethod () { ... } 
}
  

This code ends the chain of virtual overrides and makes DerivedClass.SomeMethod a candidate for inlining.

Note   Class sealing is enforced at compile time only. When malicious code runs in a full trust environment, it could use reflection or unmanaged pointers to bypass this restriction.

Restrict Access to Your Code

Not all methods in a class are meant to be accessed by all code. In some cases, you might need to restrict methods that are are not intended for general public use, but must still be marked as public. For example, you might expose public methods that need to be accessed by specific assemblies developed by your organization, but are not intended to be accessed by others. Consider the following approaches to restricting access to your code:

  • Strong name your assembly, so that partially trusted callers cannot call into it.
  • Restrict callers of your code by demanding specific or custom code access security permissions.

Do Not Trust Input

Do not trust any input to your application. Validate and constrain input by checking it for type, length, format, and range.

An attacker who passes malicious input can attempt SQL injection, cross-site scripting, and other injection attacks that aim to exploit your application's vulnerabilities.

Check for known good data and constrain input by validating it for type, length, format, and range. Check all numeric fields for type and range. You can use regular expressions and the Regex class, and you can validate numeric ranges by converting the input value to an integer or double, and then performing a range check.

Use Properties to Expose Fields

Fields should not be exposed directly to calling code. Properties allow you to add additional constraints, such as input validation or permission demands.

Mark fields as private, and create read/write or read-only properties to access them.

Note   Private fields are enforced at compile time only. When malicious code runs in a full trust environment, it could use reflection or unmanaged pointers to bypass these visibility restrictions.

Use Read-only Properties Appropriately

Do not expose your fields to caller modification unless absolutely necessary. Mark properties read-only unless the caller needs to be able to make a modification. This prevents a caller from accidentally modifying a field.

Note   Read-only properties are enforced at compile time only. When malicious code runs in a full trust environment, it could use reflection or unmanaged pointers to bypass these visibility restrictions.

Use Private Default Constructors to Prevent Unwanted Object Instantiation

A class with a public constructor can be instantiated. Mark the class's constructor private if it is not designed to be instantiated. An example of a class that is not designed for instantiation is a one that contains only static methods and properties.

Note   Private constructors are enforced at compile time only. When malicious code runs in a full trust environment, it could use reflection or unmanaged pointers to bypass these visibility restrictions.

Strong Names

Strong name signatures provide a unique identity for code, and they cannot be spoofed. The identity associated with the signature can be used to make security decisions. For example, you could set code access security policy to trust assemblies signed with your company's strong name when the assemblies come from a server you control. Consider the following guidelines for strong names:

  • Evaluate whether you need strong names.
  • Do not expect strong names to make your assembly tamper proof.
  • Use delay signing appropriately.
  • Use .pfx files to protect your private key if you do not use delay signing.
  • Do not depend on strong name identity permissions in full trust scenarios.

Evaluate Whether You Need Strong Names

From a security point of view, there are no reasons not to use strong names. However, they can make versioning more complicated. For example, if you fix a bug in a strong named assembly and increment its strong name version number, you have to either rebuild everything that depends on that assembly or deploy publisher policy with the assembly.

The following are the most common reasons to sign an assembly with a strong name:

  • You need to add your assembly to the global assembly cache. If you want your assembly to be shared among multiple applications, then you should add it to the global assembly cache. To add your assembly to the global assembly cache, you need to give it a strong name. Adding an assembly to the global assembly cache ensures that your assembly runs with full trust.
  • You want to prevent partial trust callers. The CLR prevents partially trusted code from calling a strong named assembly by adding a link demand for the Full Trust permission set. You can override this behavior by using AllowPartiallyTrustedCallersAttribute (APTCA), although you should do so only if you are fully aware of the issues and after careful code review. For more information, see the section, "APTCA," in this document.
  • You want cryptographically strong evidence for security policy evaluation. Strong names provide cryptographically strong evidence for code access security policy evaluation. This allows administrators to grant permissions to specific assemblies. For example, the public key component of a strong name is often used to represent a particular organization. You could create policy that only allows code from designated organizations to run on your computers.

Do Not Expect Strong Names to Make Your Assembly Tamper Proof

By adding a strong name to an assembly, you ensure that it cannot be modified and still retain your strong name signature. The strong name does not make your assembly tamper proof. It is still possible to remove a strong name, modify the IL code, and then reapply a different strong name.

However, an attacker cannot recreate a valid signature from your original publisher's key unless your publisher's private key has been compromised. Because the key is part of the strong name identity, if an attacker strips a strong name signature, signs the code, and then installs the code in the global assembly cache, the code will have a different identity. Any callers looking for the original assembly will not bind to an assembly signed with a different private key. Strong names prevent this type of substitution attack.

Note   Both Authenticode and strong name signing ensure that if the signed code is tampered with, the signature will be invalidated. However, neither technology prevents an attacker from stripping off the signature, modifying the IL, and signing the code with the attacker's key.

Use Delay Signing Where Appropriate

You should consider using delay signing when there are more than a few developers on your projects and/or you have a daily build process that allows you to easily sign assemblies generated from your daily build. Even if you do not meet either of these conditions, you should consider using delay signing if your private key is extremely sensitive; for example, because you have made trust decisions based on your private key across the thousands of desktops in your enterprise.

Delay signing places the public key in the assembly, which means that it is available as evidence to code access security policy, but the assembly is not signed. From a security perspective, delay signing has two main advantages:

  • The private key used to sign the assembly and create its digital signature is held securely in a central location. The key is accessible to only a few trusted individuals. As a result, the chance of the private key being compromised is significantly reduced.
  • A single public key, which can be used to represent the development organization or publisher of the software, is used by all members of the development team, instead of each developer using his or her own public, private key pair, typically generated by the sn -k command.

Creating a Public Key File for Delay Signing

When you use delay signing, distribute your public key in a .snk file that just contains the public key. Then, use the -keyfile compiler switch while you delay–sign the assemblies, or continue to use the AssemblyKeyFile attribute if you have existing .NET 1.x code that uses this attribute.

The signing authority performs the following procedure to create a public key file that developers can use to delay sign their assemblies.

To create a public key file for delay signing

  1. Create a key pair for your organization.

    sn.exe -k keypair.snk

  2. Extract the public key from the key pair file.

    sn -p keypair.snk publickey.snk

  3. Secure Keypair.snk, which contains both the private and public keys. For example, put it on a compact disc or other hardware device, such as a smart card, and physically secure it.
  4. Make Publickey.snk available to all developers. For example, put it on a network share.

Delay Signing an Assembly

This procedure is performed by developers.

To delay sign an assembly

  1. In Visual Studio .NET 2005, display the project properties.
  2. Click the Signing tab, and select the Sign the assembly and Delay sign only check boxes.
  3. In the Choose a strong name key file: drop-down box, select <Browse…>.
  4. In the file selection dialog box, browse to the public key (.snk) and click OK.
  5. Build your assembly. The complier will build a strong named assembly signed using the public key from the selected key pair (.snk) file.
    Note   A delay signed project will not run and cannot be debugged. You can, however, use the Strong Name tool (Sn.exe) with the -Vr option to skip verification during development.
  6. The delay signing process and the absence of an assembly signature means that the assembly will fail verification at load time. To work around this, use the following commands on development and test computers.
    • To disable verification for a specific assembly, use the following command.

      sn -Vr assembly.dll

    • To disable verification for all assemblies with a particular public key, use the following command.

      sn -Vr *,publickeytoken

    • To extract the public key and key token (a truncated hash of the public key), use the following command.

      sn -Tp assembly.dll

    Note   Use an uppercase -T switch.
  7. To fully complete the signing process and create a digital signature to make the assembly tamper proof, execute the following command. This requires the private key, and as a result the operation is normally performed as part of the formal build/release process. The following command uses key pair contained in the Keypair.snk file to re-sign an assembly called Assembly.dll with a strong name.

    sn -R assembly.dll keypair.snk

Use .pfx Files to Protect Your Private Key If You Do Not Use Delay Signing

If you do not use delay-signing, use password protected .pfx files to protect your private key. Visual Studio .NET 2005 adds support for .pfx files, which makes this very convenient. This approach is more appropriate for small to medium sized projects. If you previously passed around or had access to .snk files that included a private key, you should consider using .pfx files instead.

Do Not Depend on Strong Name Identity Permissions in Full Trust Scenarios

If you protect your code with a link demand for a StrongNameIdentityPermission to restrict the code that can call your code, be aware that this only works for partial trust callers. The link demand will always succeed for full trust callers, regardless of the strong name of the calling code.

In .NET Framework 2.0, any fully trusted assembly will satisfy any demand, including a link demand for an identity permission that the assembly does not satisfy. In .NET Framework 1.0, this did not happen automatically. However, a fully trusted assembly could simply call Assembly.Load, supplying as evidence the strong name it wants to satisfy, or, alternatively, it could turn code access security off.

The only protection against fully trusted code is to put it in a separate process and run that process with a restricted token so that its limits are enforced by the operating system. This applies whether code marks its interfaces as internal or private, or places link demands for StrongNameIdentityPermission on them.

The following code sample shows a method decorated with a link demand for a specific StrongNameIdentityPermission.

public sealed class Utility
{
  // Although SomeOperation() is a public method, the following 
  // permission demand means that it can only be called by partial trust 
  // assemblies with the specified public key OR by any fully trusted code. 
  [StrongNameIdentityPermission(SecurityAction.LinkDemand, 
                                PublicKey="00240000048...97e85d098615")]
  public static void SomeOperation() {}
}
  

APTCA

Strongly named, fully trusted assemblies are given an implicit link demand for Full Trust on every public and protected method of every publicly visible class. Any code in your assembly that external code could use as an entry point is protected with this link demand. The CLR enforces this link demand to help prevent luring attacks where untrusted code can lure fully trusted code into doing something dangerous on its behalf.

Note   APTCA removes the implicit link demands only. Any demands explicitly placed in your assembly will still be enforced.
  • Avoid using APTCA.
  • Consider using SecurityTransparent and SecurityCritical.

Avoid Using APTCA

You can override the link demand for full trust by adding the AllowPartiallyTrustedCallersAttribute (APTCA) to your assembly, as shown below, but you should do so only when it is absolutely necessary.

Use of APTCA increases the attack surface and exposes your code to partial trust callers.

Use APTCA only if both of the following conditions apply:

  • You specifically want partially trusted callers to use your strong named assembly. For example, you might need an application running on a file share to access your assembly located in the global assembly cache. However, do not open up an attack surface with APTCA if you only want fully trusted callers to use your code.
  • You have performed a thorough security code review, and your code has been rigorously audited for security vulnerabilities. Examine the resource access and other privileged operations performed by your assembly, and consider authorizing access to these operations by using other code access security demands.

The APTCA attribute is shown below.

 [assembly: AllowPartiallyTrustedCallersAttribute()]
  

Consider Using SecurityTransparent and SecurityCritical

If you know that your code will not attempt to elevate the permissions of the call stack—for example, by using assertions or stack walk modifiers—consider marking the code with the System.Security.SecurityTransparentAttribute. This is particularly useful if your code calls untrusted code such as a third-party plug-in. If the untrusted code attempts to manipulate the permissions of the call stack, a security exception is generated. Security transparent code and the code it calls give up the right to elevate the permissions of the call stack.

In addition to providing added protection when calling untrusted code, marking code explicitly with the SecurityTransparent and SecurityCritical attributes helps people who have to review your code. Typically, the majority of your code will not elevate code access security permissions, and can therefore be marked as SecurityTransparent. The small amount of your code that actually performs elevations of privilege should be marked as critical. This helps reviewers to focus on those areas of code marked as security critical.

Note   Because a transparent assembly cannot be used by partially trusted code to increase its effective permission set, any assemblies that are marked transparent do not require as thorough of a security audit as standard APTCA assemblies

Marking an assembly SecurityTransparent forces it to abide by the following rules:

  • It cannot assert permissions to stop a stack walk from continuing.
  • It cannot satisfy a link demand. Instead, any link demands on APIs called by the transparent assembly are automatically converted into full demands.
  • It cannot automatically use unverifiable code, even if it has SkipVerification permission. Instead, a full demand for UnmanagedCode occurs.
  • It cannot automatically make calls to P/Invoke methods, even if it has been decorated with the SuppressUnmanagedCodeAttribute. Instead, a full demand for UnmanagedCode occurs.
Note   By default, all assemblies compiled for .NET 1.x and .NET 2.0 are security critical and contain only critical code.

To make an entire assembly transparent, you can explicitly add SecurityTransparent to an assembly by using the following attribute:

 [assembly: SecurityTransparent]
  

This indicates that the assembly does not contain any critical code, and does not elevate the privileges of the call stack in any way.

If you need to mix critical and transparent code in the same assembly, start by marking the assembly with the System.Security.SecurityCriticalAttribute as shown here.

 [assembly: SecurityCritical]
  

By marking the assembly with the SecurityCriticalAttribute, you indicate that the assembly can contain critical code. However, unless explicitly marked as critical, all code within the assembly defaults to being transparent. If you want to perform security critical actions, you must explicitly mark the code that will perform the critical action with another SecurityCritical attribute, as shown in the following example.

 [assembly: SecurityCritical]
public class A
{
    [SecurityCritical]
    public void Critical()
    {
        // critical
    }

    public int SomeProp
    {
        get {/* transparent */ }
        set {/* transparent */ }
    }
}
public class B
{
    internal string SomeOtherProp
    {
        get { /* transparent */ }
        set { /* transparent */ }
    }
}
  

All of the code above is transparent (the default setting even with the assembly level SecurityCritical attribute), with the exception of the method Critical, which is explicitly marked as critical.

You can also mark all code within an entire class as critical. To do so, use the SecurityCritical attribute at the class level, and then pass SecurityCriticalScope.Everything, as shown in the following example.

 [assembly: SecurityCritical]

[SecurityCritical(SecurityCriticalScope.Everything)]
public class MyClass
{
  ...
}
  

Exception Management

Do not reveal implementation details about your application in exception messages returned to the client. This information can help malicious users plan attacks on your application. To provide proper exception management:

  • Use structured exception handling.
  • Do not log sensitive data.
  • Do not reveal system or sensitive application information.
  • Consider exception filter issues.
  • Consider an exception management system.
  • Fail early to avoid unnecessary processing that consumes resources.

Use Structured Exception Handling

Use structured exception handling instead of returning error codes from methods because it is easy to forget to check a return code, and, as a result, your code will fail to an insecure mode.

Microsoft Visual C# ® development tool and Microsoft Visual Basic® .NET development system provide structured exception handling constructs. C# provides the try / catch and finally construct. You can protect code by placing it inside try blocks, and implement catch blocks to log and process exceptions. Also, use the finally construct to ensure that critical system resources such as connections are closed, whether an exception condition occurs or not.

Do Not Log Sensitive Data

Avoid logging sensitive or private data such as user passwords. Also, make sure that exception details are not allowed to propagate beyond the application boundary to the client. The rich exception details included in Exception objects are valuable to developers and attackers alike. Log details by writing them in the event log to aid problem diagnosis.

Do Not Reveal System or Sensitive Application Information

Do not reveal too much information to the caller. Exception details can include operating system and .NET Framework version numbers, method names, computer names, SQL command statements, connection strings, and other details that are very useful to attackers. Write detailed error messages in the event log, and return generic error messages to the user.

Consider Exception Filter Issues

If your code fails to catch exceptions and your code uses impersonation, a malicious user could use exception filters to execute code that runs under the impersonated security context, even if you are reverting the impersonation in your finally block. This is particularly serious if your code impersonates a privileged account. If your code does not catch the exception, exception filters higher in the call stack can be executed before code in your finally block is executed.

If you use programmatic impersonation, use structured exception handling and put the impersonation code inside try blocks. Use a catch block to handle exceptions and to prevent exceptions propagating. Use a finally block to ensure that the impersonation is reverted, as shown in the following example.

using System.Security.Principal;
. . .
WindowsIdentity winIdentity = new WindowsIdentity("username@domainName");
WindowsImpersonationContext ctx = null;
try
{

  ctx = winIdentity.Impersonate();
  // Do work.
  ...
}
// Do not let the exception propagate. Catch it here.
catch(Exception ex)
{
  ...
}
finally
{
  // Stop impersonating.
  ctx.Undo();
}
  

By using a finally block, you make ensure that the impersonation token is removed from the current thread, even if an exception is generated. By preventing the exception from propagating from the catch block, you make sure that exception filter code higher in the call stack does not execute while the thread still has an impersonation token attatched to it.

Note   Exception filters are supported by Microsoft Intermediate Language (MSIL) and Visual Basic .NET.

Consider an Exception Management System

Consider using a formal exception management system for your application because this can help improve system supportability and maintainability and ensure that you detect, log, and process exceptions in a consistent manner.

For information about how to create an exception management framework and about best practices for exception management in .NET applications, see:

Fail Early to Avoid Unnecessary Processing that Consumes Resources

Check that your code fails early to avoid unnecessary processing that consumes resources. If your code does fail, check that the resulting error does not allow a user to bypass security checks to run privileged code.

File I/O

Canonicalization issues are a major concern for code that accesses the file system. If you have the choice, do not base security decisions on input file names because of the many ways that a single file name can be represented. If your code needs to access a file using a user-supplied file name, take steps to make sure that a malicious user cannot use your assembly to gain access to or overwrite sensitive data.

The following recommendations help you improve the security of your file I/O:

  • Avoid untrusted input for file names and file paths.
  • If you accept file names, validate them.
  • Use absolute file paths where you can.
  • Consider constraining file I/O within your application's context.

Avoid Untrusted Input for File Names and File Paths

Avoid writing code that accepts file or path input from the caller. Instead, use fixed file names and locations when your code reads and writes data. This ensures that your code cannot be coerced into accessing arbitrary files. Also avoid making security decisions based on user-supplied filenames.

If You Accept File Names, Validate Them

If you do need to receive input file names from the caller, make sure that the file names are strictly formed so that you can determine whether they are valid. There are two aspects to validating input file paths. You need to:

  • Check for valid file system names.
  • Check for a valid location as defined by your application's context. For example, are the file names within the directory hierarchy of your application?

To validate a path and file name, use the System.IO.Path.GetFullPath method as shown in the following code example. This method also canonicalizes the supplied file name.

using System.IO;
public static string ReadFile(string filename)
{
  // Obtain a canonicalized and valid filename
  string name = Path.GetFullPath(filename);
  // Now read the file and return the file content.
}
  

As part of the canonicalization process, GetFullPath performs the following checks:

  • It checks that the file name does not contain any invalid characters, as defined by Path.InvalidPathChars.
  • It checks that the file name represents a file and not another device type, such as a physical drive, a named pipe, a mail slot, or a DOS device such as LPT1, COM1, AUX, and other devices.
  • It checks that the combined path and file name is not too long.
  • It removes redundant characters such as trailing dots.
  • It rejects file names that use the //?/ format.

Use Absolute File Paths Where You Can

Try to use absolute file paths where you can. Do not trust an environment variable to construct a file path because you cannot guarantee the value of the environment variable.

Consider Constraining File I/O within your Application's Context

After you know that you have a valid file system file name, you might need to check that it is valid in your application's context. For example, you may need to check that it is within the directory hierarchy of your application and that your code cannot access arbitrary files on the file system.

You can use a restricted FileIOPermission to constrain an assembly's ability to perform file I/O; for example, by specifying allowed access rights (read, read/write, and so on) or limiting access to specific directories.

You can use declarative attributes together with SecurityAction.PermitOnly to constrain file I/O, as shown in the following example.

// Allow only this code to read files from c:\YourAppDir
[FileIOPermission(SecurityAction.PermitOnly, Read=@"c:\YourAppDir\")]
[FileIOPermission(SecurityAction.PermitOnly, PathDiscovery=@"c:\YourAppDir\")]
public static string ReadFile(string filename)
{
  // Use Path.GetFullPath() to canonicalize the file name
  // Use FileStream.OpenRead to open the file
  // Use FileStream.Read to access and return the data
}
  
Note   The second attribute that specifies PathDiscovery access is required by the Path.GetFullPath function that is used to canonicalize the input file name.

To avoid hard coding your application's directory hierarchy, you can use imperative security syntax, and then use the HttpContext.Current.Request.MapPath(".")to retrieve your Web application's directory at run time. You must refer to the System.Web assembly and add the corresponding using statement, as shown in the following example.

using System.Web;
using System.Security.Permissions;
...
public static string ReadFile(string filename)
{
  string appDir = HttpContext.Current.Request.MapPath(".");
  FileIOPermission f = new FileIOPermission(PermissionState.None);
  f.SetPathList(FileIOPermissionAccess.Read, appDir);
  f.SetPathList(FileIOPermissionAccess.PathDiscovery, appDir);
  f.PermitOnly();

  // Use Path.GetFullPath() to canonicalize the file name
  // Use FileStream.OpenRead to open the file
  // Use FileStream.Read to access and return the data
}
  

Partial trust ASP.NET Web applications that run with medium trust use code access security to restrict the directories that your application can access. Medium trust policy permits your application to access the directories beneath your application's virtual root directory. For more information about running ASP.NET applications at medium trust, see "How To: Use Medium Trust in ASP.NET 2.0" at http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGHT000020.asp.

Registry

In some scenarios, the registry can provide a suitable location for storing sensitive application configuration data. You can store configuration data under the single, local machine key (HKEY_LOCAL_MACHINE) or under the current user key (HKEY_CURRENT_USER). If you store sensitive data in the registry, consider restricting access to that data and consider encrypting it prior to storage.

Consider the following guidelines when using the registry.

  • Consider using ACLs to restrict access to data stored in HKLM.
  • Consider encrypting sensitive data in the registry.

Consider Using ACLs to Restrict Access to Data Stored in HKLM

If you store sensitive data in the HKEY_LOCAL_MACHINE section of the registry, consider applying an ACL to the registry key that restricts access to a specific account, such as the account under which your application runs. This is important because any process running on your computer has access to the HKEY_LOCAL_MACHINE section of the registry. By isolating your application and running it under a dedicated custom account, only your application can access the data from the ACL-protected key.

Note   Use of HKEY_LOCAL_MACHINE makes it easier to store configuration data at installation time and maintain it later on.

If your security requirements dictate an even less accessible storage solution, use a key under HKEY_CURRENT_USER. This approach means that you do not have to explicitly configure ACLs because access to the current user key is automatically restricted based on process identity.

Note   HKEY_CURRENT_USER allows more restrictive access because a process can access the current user key only if the user profile associated with the current thread or process token is loaded.

Consider Encrypting Sensitive Data in the Registry

If you need to store sensitive data in the registry, then consider encrypting it with DPAPI. You can use DPAPI with the machine key to encrypt the data, store the encrypted data beneath a registry key, and then use an ACL that restricts access to your specific application identity to restrict access to the registry key. Alternatively, you can use DPAPI with the user store. In this latter case, you need to load the user account's profile to access the key.

Consider using the machine store if your application is a server that runs on its own dedicated computer with no other applications, or if you have multiple applications on the same server and you need those applications to be able to share the sensitive registry data. If you only want specific service accounts to be able to access the DPAPI keys and their profiles are loaded, then use DPAPI with the user store.

The following code shows how to create a registry key protected with an ACL and how to use DPAPI with the machine store to store encrypted data in the restricted key.

using System.Security.Cryptography;
using System.Security.AccessControl;
using System.Text;
using Microsoft.Win32;
...

// Get the original data in a byte array
byte[] toEncrypt = UnicodeEncoding.ASCII.GetBytes(
                   "The secret data to be encrypted");

// Encrypt the data by using the ProtectedData class.
byte[] encryptedData = ProtectedData.Protect(toEncrypt, null,
                       DataProtectionScope.LocalMachine);

// Create a new key in the registry with a restricted ACL 
// and write stream of bytes to the registry key
string user = Environment.UserDomainName + "\\" + Environment.UserName;
RegistrySecurity security = new RegistrySecurity();
RegistryAccessRule rule = new RegistryAccessRule(user,
                RegistryRights.FullControl,
                InheritanceFlags.ContainerInherit,
                PropagationFlags.None,
                AccessControlType.Allow);
security.AddAccessRule(rule);

Registry.CurrentUser.CreateSubKey("TestEncryptedData",
                RegistryKeyPermissionCheck.ReadWriteSubTree,
                security);
Registry.SetValue(@"HKEY_CURRENT_USER\TestEncryptedData", "Encrypted",
                 encryptedData);
 
  

Use the following code to decrypt the data stored in the registry.

// Read the encrypted data from registry and decrypt the contents 
byte[] dataFromRegistry = Registry.GetValue(
@"HKEY_CURRENT_USER\TestEncryptedData",
                 "Encrypted", null) as byte[];
byte[] decryptedData = ProtectedData.Unprotect(dataFromRegistry, null,
                 DataProtectionScope.LocalMachine);
  

Communication Security

If your application passes sensitive data over networks, consider the threats of eavesdropping, tampering, and unauthorized callers accessing your end point. .NET Framework 2.0 provides a set of managed classes in the System.Net.Security namespace to enable secure communication between hosts when you are using remoting or raw-sockets based communication. This allows you to implement both client and server-side secure channels using SSPI or SSL. These classes support mutual authentication, data encryption, and data signing.

If you use remoting or sockets, consider the following guidelines:

  • Consider transport level encryption to protect secrets on the network.
  • If you are using the TCP channel with .NET remoting, consider System.Net.Security.NegotiateStream.

Consider Transport Level Encryption to Protect Secrets on the Network

If your servers are not inside a physically secure data center where the network eavesdropping threat is considered insignificant, you need to use an encrypted communication channel to protect data sent between servers. You can use SSL or IPSec to encrypt traffic and help protect communication between servers. Use SSL when you need granular channel protection for a particular application, instead of protection for all applications and services running on a computer. Use IPSec to help protect the communication channel between two servers and to restrict the computers that can communicate with each other. For example, you can help protect a database server by establishing a policy that permits requests only from a trusted client computer, such as an application or Web server. You can also restrict communication to specific IP protocols and TCP/UDP ports.

If You Use the TCP Channel with .NET Remoting, Consider System.Net.Security.NegotiateStream

In .NET Framework 1.1, remoting applications that use the TCP channel do not by default perform authentication or encryption. In .NET Framework 2.0, the remoting framework uses the new System.Net.Security.NegotiateStream class to encrypt and sign the data transported over the channel and to authenticate callers. To use this feature, you can configure the <channel> element in the Machine.config file, the Web.config file, or the App.config file, depending on whether you want to apply the setting across all applications on your computer or to a specific application.

The following example shows how a server specifies that authentication is required and that the channel should be protected with encryption.

<channel ref="tcp" port="1234" 
         authenticationMode="IdentifyCallers" secure="true" />
  

To authenticate clients by using their domain credentials, you need to set the useDefaultCredentials attribute of the <channel> in the client configuration to true. The following example shows a sample client configuration.

<channel ref="tcp" useDefaultCredentials="true" secure="true" 
         impersonationLevel="Identify" />
  

To use Kerberos authentication, the client must specify a service principal name (SPN). This can be done programmatically or in the client's configuration file, as shown in the following example.

<channel ref="tcp" 
         useDefaultCredentials="true" 
         impersonationLevel="Identify" 
         spn="someService/somehost.com" />
  
Note   Use of .NET remoting is not encouraged for interprocess or server-to-server communication. .NET remoting is for cross-application domain communication within a process.

Event Log

When you write event logging code, consider the threats of tampering and information disclosure. For example, can an attacker retrieve sensitive data by accessing the event logs? Can an attacker cover tracks by deleting the logs or erasing particular records?

Windows security restricts direct access to the event logs using system administration tools, such as the Event Viewer. Your main concern should be to ensure that the event logging code you write cannot be used by a malicious user for unauthorized access to the event log.

Consider the following guidelines:

  • Do not log sensitive data.
  • Do not expose event log data to unauthorized users.

Do Not Log Sensitive Data

Do not log sensitive user information, such as credentials, credit card numbers, or user IDs. When the information has been sent to the log, it can be viewed by anyone with access to the event log. To prevent the disclosure of sensitive data, do not log it in the first place. The event log is a useful location to store application execution information and error information.

Do Not Expose Event Log Data to Unauthorized Users

Direct access to the event log through tools such as the Event Viewer is restricted to administrators. Do not expose event log data to less privileged users because the log may contain information about application or system internals that could be useful to an attacker.

Data Access

Two of the most important factors to consider when your code accesses a database are how to manage database connection strings securely and how to construct SQL statements and validate input to prevent SQL injection attacks. Also, when you write data access code, consider the permission requirements of your chosen ADO.NET data provider.

  • Do not hard code connection strings.
  • Consider encrypting connection strings.
  • Prevent SQL injection.

Do Not Hard Code Connection Strings

Do not hard code connection string in your assembly. An attacker with access to your application can extract this information directly from the assembly. An attacker can use a decompiler to reconstitute your code, and make discovery of this information even easier.

Store connection strings externally, for example in configuration files.

Consider Encrypting Connection Strings

Sensitive data items such as connection string stored in configuration files should be encrypted. Encrypting connection strings is particularly important if they contain user credentials; for example, connection strings used with SQL authentication.

In ASP.NET 2.0, store connection strings in the <connectionStrings> section of Web.config file, and use the Aspnet_regiis tool to encrypt this section. This tool uses one of the protected configuration providers that support DPAPI or RSA encryption.

For more information, see the following documents:

Prevent SQL Injection

To help prevent SQL injection, you should validate input and use parameterized stored procedures for data access. The use of parameters (for example, SqlParameterCollection) ensures that input values are checked for type and length and values outside the range throw an exception. Parameters are also treated as safe literal values and not as executable code within the database. The following code shows how to use SqlParameterCollection when calling a stored procedure.

using System.Data;
using System.Data.SqlClient;

using (SqlConnection connection = new SqlConnection(connectionString))
{
  DataSet userDataset = new DataSet();
  SqlDataAdapter myCommand = new SqlDataAdapter( 
             "LoginStoredProcedure", connection);
  myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
  myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
  myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;

  myCommand.Fill(userDataset);
}
  

Avoid stored procedures that accept a single parameter as an executable query. Instead, pass query parameters only.

Use structured exception handling to catch errors that occur during database access, and prevent them from being returned to the client. A detailed error message may reveal valuable information such as the connection string, SQL server name, or table and database naming conventions. Attackers can use this information to construct more precise attacks.

As an additional precaution, use a least privileged account to access the database, so that even if your application is compromised, the impact will be reduced.

For more information, see "How To: Protect From SQL Injection in ASP.NET" at http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGHT000002.asp.

Delegates

Delegates are the managed equivalent of type-safe function pointers. The .NET Framework uses them to support events. The delegate object maintains a reference to a method, which is called when the delegate is invoked. Events allow multiple methods to be registered as event handlers. When the event occurs, all event handlers are called.

  • Avoid accepting delegates from untrusted sources
  • Consider restricting permissions to the delegate.
  • Avoid asserting permissions before calling a delegate.

Avoid Accepting Delegates from Untrusted Sources

If your assembly exposes a delegate or an event, be aware that any code can associate a method with the delegate, and you have no advance knowledge of what the code will do. The safest policy is not to accept delegates from untrusted callers. If your assembly is strong named and does not include the AllowPartiallyTrustedCallersAttribute, only full trust callers can pass a delegate to your code.

Consider Restricting Permissions to the Delegate

If you allow partially trusted callers, you should consider restricting permissions to the delegate. You can either use an appropriate permission demand to authorize the external code when it passes the delegate to your code, or you can use a deny or permit-only stack modifier to restrict the delegate's permissions just prior to calling it. For example, the following code grants the delegate code only execution permission to constrain its capabilities.

using System.Security;
using System.Security.Permissions;
...

// Delegate definition
public delegate void SomeDelegate(string text);
    
public void ExecDelegateWithExcePerm()

{
        // Permit only execution, prior to calling the delegate. This prevents the
        // delegate code accessing resources or performing other privileged
        // operations
        new SecurityPermission(SecurityPermissionFlag.Execution).PermitOnly();

        // Now call the "constrained" delegate
        SomeDelegate del = new SomeDelegate(DisplayResults);

        // Revert the permit only stack modifier
        CodeAccessPermission.RevertPermitOnly();
}

private void DisplayResults(string result)
{
...
} 
  

Avoid Asserting Permissions Before Calling a Delegate

Asserting a permission before calling a delegate is dangerous because you have no knowledge about the nature or trust level of the code that will be executed when you invoke the delegate. The code that passes you the delegate is on the call stack and can therefore be checked with an appropriate security demand. However, there is no way of knowing the trust level or permissions granted to the delegate code itself.

Serialization

You may need to add serialization support to a class if you need to be able to marshal it by value across a .NET remoting boundary (that is, across application domains, processes, or computers) or if you want to be able to persist the object state to create a flat data stream, perhaps for storage on the file system.

By default, classes cannot be serialized. A class can be serialized if it is marked with the SerializableAttribute or if it derives from ISerializable. If you use serialization:

  • Do not serialize sensitive data.
  • Validate serialized data streams.

Do Not Serialize Sensitive Data

If you must serialize your class and it contains sensitive data, avoid serializing the fields that contain the sensitive data. Either implement ISerializable to control the serialization behavior or decorate fields that contain sensitive data with the [NonSerialized] attribute. By default, all private and public fields are serialized. This is important because serialization places the data in memory, often in preparation for sending it over a network, making it easier for an attacker to gain access to it.

The following example shows how to use the [NonSerialized] attribute to ensure that a specific field which contains sensitive data cannot be serialized.

 [Serializable]
public class Employee {
  // OK for name to be serialized
  private string name;
  // Prevent salary being serialized
  [NonSerialized] private double annualSalary;
  . . .
}
  

Alternatively, implement the ISerializable interface and explicitly control the serialization process. If you must serialize the sensitive item or items of data, consider encrypting the data first. The code that de-serializes your object must have access to the decryption key.

Validate Serialized Data Streams

Serialized data should not be considered trusted data. Subject it to the same level of scrutiny that you would subject any other untrusted file, network, or user input. To avoid potentially damaging data being injected into the object, validate each field as it is reconstituted as shown in the following example.

public void DeserializationMethod(SerializationInfo info, StreamingContext cntx)
{
  string someData = info.GetString("someName");
  // Use input validation techniques to validate this data.
}
  

Threading

Bugs caused by race conditions in multithreaded code can result in security vulnerabilities and generally unstable code that is subject to timing-related bugs. If you develop multithreaded assemblies, consider the following guidelines:

  • Do not cache the results of security checks.
  • Avoid losing impersonation tokens.
  • Synchronize static class constructors.
  • Synchronize Dispose methods.

Do Not Cache the Results of Security Checks

If your multithreaded code caches the results of a security check, perhaps in a static variable, the code is potentially vulnerable, as shown in the following example.

public void AccessSecureResource()
{
  callerOK = PerformSecurityDemand();
  OpenAndWorkWithResource();
  callerOK = false;
}
private void OpenAndWorkWithResource()
{
  if (callerOK)
    PerformTrustedOperation();
  else
  {
    PerformSecurityDemand();
    PerformTrustedOperation();
  }
}
  

If your code has other paths to OpenAndWorkWithResource, and a separate thread calls the method on the same object, it is possible for the second thread to omit the security demand because it encounters callerOK=true, set by another thread.

Avoid Losing Impersonation Tokens

In .NET Framework 1.1, impersonation tokens did not automatically flow to newly created threads. This situation could lead to security vulnerabilities because new threads assume the security context of the process. In .NET Framework 2.0, by default the impersonation token still does not flow across threads, but for ASP.NET applications you can change this default behavior by configuring the ASPNET.config file in the %Windir%Microsoft.NET\Framework\{Version} directory.

If you need to flow the impersonation token to new threads, set the enabled attribute to true on the alwaysFlowImpersonationPolicy element in the ASPNET.config file, as shown in the following example.

<configuration>
  <runtime>
    <alwaysFlowImpersonationPolicy enabled="true"/>
     </runtime>
</configuration>
  

If you need to prevent impersonation tokens from being passed to new threads programmatically, you can use the ExecutionContext.SuppressFlow method.

Synchronize Static Class Constructors

If you use static class constructors, make sure that they are not vulnerable to race conditions. If, for example, they manipulate static state, add thread synchronization to avoid potential vulnerabilities.

Synchronize Dispose Methods

If you develop non-synchronized Dispose implementations, the Dispose code could be called more than once on separate threads. The following code shows an example of this.

void Dispose()
{
  if (null != theObject)
  {
    ReleaseResources(theObject);
    theObject = null;
  }
}
  

In this example, it is possible for two threads to execute the code before the first thread has set theObject reference to null. Depending on the functionality provided by the ReleaseResources method, security vulnerabilities could occur.

Reflection

.NET reflection is a feature that allows running code to dynamically discover, load, and generate assemblies. With reflection, you can enumerate an assembly's types, methods, and properties—including those marked as private. By using Reflection.Emit, you can generate a new assembly dynamically at run time and invoke its members. Reflection is a powerful feature that has a number of security implications:

  • If your code has the ReflectionPermission, it can enumerate and invoke non-public members or types in other assemblies. If you do not use code access security permission demands to authorize calling code, an attacker could gain access to code that would otherwise be inaccessible.
  • By using reflection, you can dynamically load assemblies—for example, by using System.Reflection.Assembly.Load. If you allow untrusted code or data to influence which assembly is loaded, an attacker could trick your code into loading and executing malicious code.
  • By using reflection, you can dynamically invoke methods on assemblies—for example, by using System.Reflection.MethodInfo.Invoke. If you allow untrusted code or data to influence the method invocation, an attacker could trick your code into making unexpected and potentially malicious method calls.
  • With Reflection.Emit, your code can dynamically generate and execute code at run time. If you allow untrusted code or data to influence the code generation, an attacker could coerce your application into generating malicious code.

When you use reflection, consider the following guidelines:

  • Use full assembly names when you dynamically load assemblies.
  • Avoid letting untrusted code or data control run-time assembly load decisions.
  • Avoid letting untrusted code or data control Reflection.Emit.
  • Consider restricting the permissions of dynamically generated assemblies.
  • Only persist dynamically created assemblies if necessary.
  • Use ReflectionOnlyLoadFrom if you only need to inspect code.

Use Full Assembly Names When You Dynamically Load Assemblies

If your code supports the dynamic loading of assemblies and you load the assembly by calling Activator.CreateInstance, make sure to refer to the assembly by using its strong name. This prevents your application from accidentally loading a malicious assembly with the same name as a legitimate assembly. The strong name of an assembly contains the public-key token that the assembly was signed with, providing evidence of the author.

The following example shows how to find the strong name for an assembly.

public static StrongName GetStrongName(Assembly assembly)
{
    if(assembly == null)
        throw new ArgumentNullException("assembly");

    AssemblyName assemblyName = assembly.GetName();
        
    // get the public key blob
    byte[] publicKey = assemblyName.GetPublicKey();
    if(publicKey == null || publicKey.Length == 0)
        throw new InvalidOperationException(
            String.Format("{0} is not strongly named", 
            assembly));
    
    StrongNamePublicKeyBlob keyBlob = 
        new StrongNamePublicKeyBlob(publicKey);

    // create the StrongName
    return new StrongName(
        keyBlob, assemblyName.Name, assemblyName.Version);
}
  

Avoid Letting Untrusted Code or Data Control Run-time Assembly Load Decisions

Avoid letting the user or untrusted code directly control which assemblies or types your code loads. Avoid using user input to derive assembly or type names. These precautions prevent your application from loading a malicious assembly or blindly invoking a method that could be used for malicious purposes.

Avoid Letting Untrusted Code or Data Control Reflection.Emit

If your application dynamically generates code through the use of Reflection.Emit, do not allow untrusted code or data to influence the code generation. If an attacker can influence the code generation, the attacker could coerce your application into generating malicious code. This is particularly significant if your code uses user-supplied input to generate code dynamically.

There are some scenarios, such as script engine implementation, in which it is necessary to allow untrusted input to drive Reflection.Emit. If your assembly dynamically generates code to perform operations for a caller and the caller operates at a lower trust level, be especially vigilant for security vulnerabilities. Validate any input string used as a string literal in your generated code and escape quotation mark characters to make sure that the caller cannot break out of the literal and inject code. If there is a way that the caller can influence the code generation s