Prizes & Awards
My Profile
Active Members
TodayLast 7 Days
more...
|
New Feature: Community Sites:
Create your own .NET community website and start earning from Google AdSense !
It's Free !
|
Secure Coding Guidelines for the .NET Framework
|
Evidence-Based Security and Code Access Security Two separate technologies work together to protect managed code:
Evidence-based security determines what permissions to grant to code. Code access security checks that all code on the stack has the necessary permissions to do something. Permissions bind these technologies together: a permission is the right to perform a specific protected operation. For example, "to read c:\temp" is a file permission; "to connect to www.msn.com" is a network permission.
Evidence-based security determines the permissions granted to code. Evidence is the information known about any assembly (the unit of granting permission) that is used as input to the security policy mechanism. Given evidence as input, security policy set by the administrator is evaluated to determine what permissions can be given to the code. The code itself can use a permission request to influence the permissions that are granted. The permission request is expressed as assembly-level declarative security using custom attribute syntax. However, the code can never in any way cause more or fewer permissions to be granted to it than the policy system allows. Permission grants occur once and specify the rights of all code in the assembly. To view or edit your security policy, use the .NET Framework configuration tool (Mscorcfg.msc).
The following table shows some common types of evidence that the policy system uses to grant permissions to code. In addition to the standard types of evidence listed here, which are provided by the security system, it is also possible to extend the set of evidence with new types that customers may define.
Evidence Description Hash Hash of the assembly Publisher AuthentiCode® signer StrongName Public key+name+version Site Web site of code origin Url URL of code origin Zone Internet Explorer zone of code origin
Code access security handles the security checks that enforce granted permissions. The unique aspect of these security checks is that they check not only the code that is attempting to do a protected operation, but also all of its callers up the stack. All checked code must have the necessary permission (subject to overrides) for the check to succeed.
Security checks are beneficial because they prevent luring attacks, where unauthorized code calls your code and tricks it into doing something on behalf of the unauthorized code. Suppose you have an application that reads a file, and security policy grants your code permission to do this. Because all your application code has permission, code access security checks will pass. However, if malicious code, which does not have access to the file, calls any of your code in any way, the security check will fail because that less trusted code will be visible on the stack by virtue of calling your code.
It is important to note that all of this security is based on the enforcement of what code is allowed to do. Authorization of users based on logon information is a completely separate security feature of the underlying operating system. Think of these two security systems as a multi-layered defense: to access a file, for example, both code and user authorizations must be passed. Although user authorization is important in many applications that depend on user logon information or other credentials to control what certain users can and cannot do, this type of security is not a focus of this document.
Goals of Secure Coding It is assumed that security policy is correct, and that potentially malicious code will not have permissions that trusted code is granted that allow it to do more powerful things safely. (To assume otherwise makes one type of code indistinguishable from the other, making the problem impossible.) Using the .NET Framework-enforced permissions, and other enforcement in your code, you must erect barriers to prevent the malicious code from obtaining information that you do not want it to have or from performing undesirable actions. Additionally, a balance must be struck between security and usability of the code in all the intended scenarios by trusted code.
Evidence-based security policy and code access security provide very powerful, explicit mechanisms to implement security. Most application code simply needs to use the infrastructure implemented by the .NET Framework. In some cases, additional application-specific security is required, built either by extending the security system or by using new ad hoc methods.
Approaches to Secure Coding One advantage of these security technologies is that you can usually forget about them. If your code is granted the permissions it needs to do its job, things will just work (while you enjoy protection against potential onslaughts, such as the luring attack described previously). However, there are a few specific situations where you must explicitly address security. The sections that follow describe these approaches. Even if these sections do not apply directly to you, understanding these security issues might prove useful.
Security-Neutral Code Security-neutral code does nothing explicit with the security system. It runs with whatever permissions it receives. Although failing to catch security exceptions with protected operations (such as using files, networking, and so on) can result in an ugly user experience (an exception with many details that are totally obscure to most users), this approach takes advantage of the security technologies because even highly trusted code will not open holes in security protection. The worst that can happen is that callers will need many permissions or will be stopped by security.
A security-neutral library has special characteristics that you should understand. Suppose your library provides API elements that use files or call unmanaged code; if your code does not have the corresponding permission, it will not run as described. However, even if the code has the permission, any application code that calls it must have the same permission in order to work. If the calling code does not have the right permission, the security exception will appear as a result of the code access security stack walk. If it is acceptable to require your callers to have permissions for everything your library does, this is an easy and safe way to implement security because it does not involve a risky security override. However, if you want application code that calls your library to be shielded from the effects of permission demands and relieved from the need to have what could be very powerful permissions, you must look at the library model that works with protected resources, which is described in the Library Code that Exposes Protected Resources section of this document.
Application Code That Is Not a Reusable Component If your code is part of an application that will not be called by other code, security is simple and special coding might not be required. However, remember that malicious code can call your code. While code access security might stop malicious code from accessing resources, such code could still read values of your fields or properties that might contain sensitive information.
Additionally, if your code accepts user input from the Internet or other unreliable sources, you must be careful of malicious input.
For more information, see Securing State Data and User Input in this document.
Managed Wrapper to Native Code Implementation Typically in this scenario, some useful functionality is implemented in native code and you want to make it available to managed code without rewriting it as such. Managed wrappers are easy to write as either platform invokes or using COM interop. However, if you do this, callers of your wrappers must have unmanaged code rights to succeed. Under default policy, this means that intranet- and Internet-downloaded code will not work with the wrappers.
Rather than giving all applications that use these wrappers unmanaged code rights, it is better to give these rights only to the wrapper code. If the underlying functionality is safe (exposes no resources) and the implementation is safe, the wrapper only needs to assert its rights, which enables any code to call through it. When resources are involved, security coding should be the same as the library code case described in the next section. Because the wrapper is potentially exposing callers to these issues, careful verification of the safety of the native code is necessary and is the wrapper's responsibility.
For more information, see the Unmanaged Code and Assessing Permissions sections of this document.
Library Code That Exposes Protected Resources This is the most powerful and hence potentially dangerous (if done incorrectly) approach for security coding: your library serves as an interface for other code to access certain resources that are not otherwise available, just as the classes of the .NET Framework enforce permissions for the resources they use. Wherever you expose a resource, your code must first demand the permission appropriate to the resource (that is, do a security check) and then typically assert its rights to perform the actual operation.
For more information, see the Unmanaged Code and Assessing Permissions sections of this document.
Best Practices for Secure Coding Note Code samples are written in C# unless otherwise specified. Permission requests are a great way to make your code security aware. These requests allow you to do two things:
Request the minimum permissions your code must receive to run. Ensure that your code receives no more permissions than it actually needs. For example:
[assembly:FileIOPermissionAttribute (SecurityAction.RequestMinimum, Write="C:\\test.tmp")] [assembly:PermissionSet (SecurityAction.RequestOptional, Unrestricted=false)] …SecurityAction.RequestRefused… This example tells the system that the code should not be run unless it receives permission to write C:\test.tmp. If the code ever encounters security policy that does not grant this permission, a PolicyException will be raised and the code will not run. You can be sure that your code will be granted this permission and you do not have to worry about errors caused by having too few permissions.
This example also tells the system that no additional permissions are wanted. Absent this, your code will be granted whatever permissions policy chooses to give it. While extra permissions do not cause harm, if there is a security bug somewhere, having fewer permissions could well close the hole. Carrying permissions that your code does not need can lead to security problems.
Another way to limit the permissions your code receives to the fewest privileges is to list specific permissions you want to refuse. Permissions are typically refused when you ask that all permissions be optional and exclude specific permissions from that request.
Securing State Data Applications that handle sensitive data or make any kind of security decisions need to keep that data under their own control and cannot allow other potentially malicious code to access the data directly. The best way to keep data securely in memory is as private or internal (scope limited to the same assembly) variables. However, even this data is subject to access you should be aware of:
Under reflection, highly trusted code that has reference to your object can get and set private members. Using serialization, highly trusted code can effectively get and set private members if it can access the corresponding data in the serialized form of the object. Under debugging, this data can be read. Make sure none of your own methods or properties expose these values unintentionally.
In some cases, data can be secured as "protected," with access limited to the class and its derivatives. However, you should take the following additional precautions due to additional exposure:
Control what code is allowed to derive from your class by restricting it to the same assembly, or by using declarative security to require some identity or permissions in order to derive from your class (see the Securing Method Access section of this document). Ensure that all derived classes implement similar protection or are sealed. Boxed Value Types Boxed value types can sometimes be modified in cases where you think you have distributed a copy of the type that cannot modify the original. When you return a boxed value type, you are returning a reference to the value type, not a reference to a copy of the value type, thus allowing the code that called your code to modify the value of your variable.
The following C# code example shows how boxed value types can be modified using a reference.
using System; using System.Reflection; using System.Reflection.Emit; using System.Threading; using System.Collections; class bug { // Suppose you have an API element that exposes a // field through a property with only a get accessor. public object m_Property; public Object Property { get { return m_Property;} set {m_Property = value;} // (if applicable) } // You can modify the value of this by doing // the byref method with this signature. public static void m1( ref int j ) { j = Int32.MaxValue; } public static void m2( ref ArrayList j ) { j = new ArrayList(); } public static void Main(String[] args) { Console.WriteLine( "////// doing this with value type" ); { bug b = new bug(); b.m_Property = 4; Object[] objArr = new Object[]{b.Property}; Console.WriteLine( b.m_Property ); typeof(bug).GetMethod( "m1" ).Invoke( null, objArr ); // Note that the property changed. Console.WriteLine( b.m_Property ); Console.WriteLine( objArr[0] ); } Console.WriteLine( "////// doing this with a normal type" ); { bug b = new bug(); ArrayList al = new ArrayList(); al.Add("elem"); b.m_Property = al; Object[] objArr = new Object[]{b.Property}; Console.WriteLine( ((ArrayList)(b.m_Property)).Count ); typeof(bug).GetMethod( "m2" ).Invoke( null, objArr ); // Note that the property does not change. Console.WriteLine( ((ArrayList)(b.m_Property)).Count ); Console.WriteLine( ((ArrayList)(objArr[0])).Count ); } } }
Securing Method Access Some methods might not be suitable to allow arbitrary untrusted code to call. Such methods pose several risks: the method might provide some restricted information; it might believe any information passed to it; it might not do error checking on the parameters; or with the wrong parameters, it might malfunction or do something harmful. You should be aware of these cases and take suitable action to secure the method.
In some cases, you might need to restrict methods that are not intended for public use, but still must be public. For example, you might have an interface that needs to be called across your own DLLs, and hence must be public, but you do not want to expose it publicly to prevent customers from using it or to prevent malicious code from exploiting the entry point into your component. Another common reason to restrict a method not intended for public use (yet that must be public) is to avoid having to document and support what may be a very internal interface.
Managed code affords several ways to restrict method access:
Limit the scope of accessibility to the class, assembly, or derived classes, if they can be trusted. This is the simplest way to limit method access. Note that, in general, derived classes can be less trustworthy than the class they derive from, yet in some cases they share the superclass identity. In particular, do not infer trust from the keyword protected, which is not necessarily used in the security context. Limit the method access to callers of a specified identity (essentially, any particular evidence you choose). Limit the method access to callers having whatever permissions you select. Similarly, declarative security allows you to control inheritance of classes. You can use InheritanceDemand to do the following:
Require derived classes to have a specified identity or permission. Require derived classes that override specific methods to have a specified identity or permission. Example: Securing Access to a Class or Method The following example shows how to secure a public method for limited access.
The sn -k command creates a new private/public key pair. The private part is needed to sign the code with a strong name and is kept securely by the publisher of the code. (If revealed, anyone could impersonate your signature on their code, defeating the protection.) Securing a method by strong name identity
sn -k keypair.dat csc/r:App1.dll /a.keyfile:keypair.dat App1.cs sn -p keypair.dat public.dat sn -tp public.dat >publichex.txt
[StrongNameIdentityPermissionAttribute (SecurityAction.LinkDemand, PublicKey="…",hex…",Name="App1", Version="0.0.0.0")] public class Class1
The csc command compiles and signs App1, authorizing it to access the protected method. The next two sn commands extract the public key portion from the pair and format it in hexadecimal. The lower half of the example is a source code excerpt of the protected method. The custom attribute defines the strong name and specifies the public key of the key pair, with the hexadecimal format data from sn inserted for the PublicKey attribute. At run time, App1 has the required strong name signature and is allowed to use Class1. This sample uses a LinkDemand to protect an API element; see later sections of this document for important information about the limitations of using LinkDemand.
Excluding Classes and Methods from Use by Untrusted Code Use the following declarations to prevent classes and methods (including properties and events) from being used by partially trusted code. By applying these declarations to a class, the protection will be applied to all its methods, properties, and events; however, note that field access is not affected by declarative security. Note that link demands only protect against the immediate callers and might still be subject to luring attacks, described in the Evidence-Based Security and Code Access Security section of this document.
Strong-named assemblies will have declarative security applied to all publicly accessible methods, properties, and events therein to restrict their use to fully trusted callers, unless the assembly explicitly opts in by applying the AllowPartiallyTrustedCallers attribute. Thus, explicitly marking classes to exclude untrusted callers is only necessary for unsigned assemblies or assemblies with this attribute, for subset of types therein that are not intended for untrusted callers. For full details, see the Version 1 Security Changes for the Microsoft .NET Framework document.
For public non-sealed classes: [System.Security.Permissions.PermissionSetAttribute(System.Security. Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")] [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public class CanDeriveFromMe
For public sealed classes: [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public sealed class CannotDeriveFromMe
For public abstract classes: [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")] [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public abstract class CannotCreateInstanceOfMe_CanCastToMe
For public virtual functions: class Base { [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")] [System.Security.Permissions.PermissionSetAttribute( System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public override void CanOverrideOrCallMe() { ... }
For public abstract functions: class Base { [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")] [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public override void CanOverrideMe() { ... }
For public override functions where the base does not demand full trust: class Derived { [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")] public override void CanOverrideOrCallMe() { ... }
For public override functions where the base demands full trust: class Derived { [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public override void CanOverrideOrCallMe() { ... }
For public interfaces: [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")] [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public interface CanCastToMe
Demand Versus LinkDemand Declarative security offers two kinds of security checks that are similar but perform very different checks. It is worth your time to understand both forms because the wrong choice can result in weak security or performance loss. This section is not intended to be a thorough description of these features; see the product documentation for full details.
Declarative security offers the following security checks:
Demand specifies the code access security stack walk: all callers on the stack must have the permission or identity to pass. Demand occurs on every call because the stack might contain different callers. If you call a method repeatedly, this security check occurs each time. Demand is strong against luring attacks; unauthorized code trying to get through it will be caught. LinkDemand happens at just-in-time (JIT) compilation time (in the previous example, when App1 code that references Class1 is about to execute) and it checks only the immediate caller. This security check does not check the caller's caller. Once this check passes, there is no additional security overhead no matter how many times it might call. However, there is also no protection from luring attacks. With LinkDemand, your interface is safe but any code that passes the test and can reference your code can potentially break security by allowing malicious code to call using the authorized code. Therefore, do not use LinkDemand unless all the possible weaknesses can be thoroughly avoided. The extra precautions required when using LinkDemand must be "hand crafted" (the security system can help with enforcement). Any mistake opens a security weakness. All authorized code that uses your code must be responsible for implementing additional security by doing the following:
Restricting the calling code's access to the class or assembly. Placing the same security checks on that code and obligating its callers to do so. For example, if you write code that calls a method that is protected with a LinkDemand for the SecurityPermission.UnmanagedCode permission, your method should also make a LinkDemand (or Demand, which is stronger) for this permission. The exception is if your code uses the LinkDemand-protected method in a limited way that is always safe or that you decide is safe, given other security protection mechanisms (such as demands) in your code. This exceptional case is where the caller takes responsibility in weakening the security protection on the underlying code. Ensuring that its callers cannot trick it into calling the protected code on their behalf (that is, callers cannot force the authorized code to pass specific parameters to the protected code, or to get results back from it). Interfaces and LinkDemands If a virtual method, property, or event with LinkDemand overrides a base class method, the base class method must also have the same LinkDemand for the overridden method to be secure. It is possible for malicious code to cast back to the base type and call the base class method. Also note that LinkDemands can be added implicitly to assemblies that do not have the AllowPartiallyTrustedCallersAttribute assembly-level attribute.
It is a good practice to protect method implementations with LinkDemands when interface methods also have LinkDemands.
Note the following about using LinkDemands with interfaces:
The AllowPartiallyTrustedCallers attribute can affect interfaces. You can place LinkDemands on interfaces to selectively opt out certain interfaces from partially trusted code use, such as when using the AllowPartiallyTrustedCallers attribute. If you have an interface defined in an assembly that does not contain the AllowPartiallyTrustedCallers attribute, you can implement that interface on a partially trusted class. If you place a LinkDemand on a public method of a class that implements an interface method, the LinkDemand will not be enforced if you then cast to the interface and call the method. In this case, because you linked against the interface, only the LinkDemand on the interface is honored. The following items should be reviewed for security issues:
Explicit link demands on interface methods. Make sure these link demands offer the expected protection. Determine whether malicious code can use a cast to get around the link demands as described previously. Virtual methods with link demands. Types and the interfaces they implement should use LinkDemands consistently. Virtual Internal Overrides There is a nuance of the type system accessibility to be aware of when confirming that your code is unavailable to other assemblies. A method that is declared virtual and internal can override the super class vtable entry and can be used only from within the same assembly because it is internal. However, the accessibility for overriding is determined by the virtual keyword and this can be overridden from another assembly as long as that code has access to the class itself. If the possibility of an override presents a problem, use declarative security to fix it or remove the virtual keyword, if it is not strictly required.
Wrapper Code Wrapper code—especially where the wrapper has higher trust than code that uses it—can open a unique set of security weaknesses. Anything done on behalf of a caller, where the caller's limited permissions are not included in the appropriate security check, is a potential weakness to be exploited.
Never enable something through the wrapper that the caller could not do itself. This is a special danger when doing something that involves a limited security check (as opposed to a full stack walk demand). When single-level checks are involved, interposing the wrapper code between the real caller and the API element in question can easily cause the security check to succeed when it should not, thereby weakening security.
Delegates Whenever your code takes delegates from less trusted code that might call it, make sure that you are not enabling the less trusted code to escalate its permissions. If you take a delegate and use it later, the code that created the delegate is not on the call stack and its permissions will not be tested if code in or under the delegate attempts a protected operation. If your code and the delegate code have higher privileges than the caller, this provides a way for the caller to orchestrate the call path without being part of the call stack.
To address this issue, you can either limit your callers (for example, by requiring a permission) or restrict permissions under which the delegate can execute (for example, by using a Deny or PermitOnly stack override).
LinkDemands and Wrappers There is a special protection case with link demands that has been strengthened in the security infrastructure, yet is still a source of possible weakness in your code.
If fully trusted code calls a property, event, or method protected by a LinkDemand, the call will succeed if the LinkDemand permission check for the caller is satisfied. Additionally, if the fully trusted code exposes a class that takes the name of a property and calls its get accessor using reflection, that call to the get accessor will succeed even though the user code does not have the right to access this property. This is because the LinkDemand will check only the immediate caller, which is the fully trusted code. In essence, the fully trusted code is making a privileged call on behalf of user code without making sure that the user code has the right to make that call. If you are wrapping reflection functionality, see the Version 1 Security Changes for the Microsoft .NET Framework article for details.
To prevent inadvertent security holes such as those described above, the runtime extends the check into a full stack-walking demand on any use of invoke (instance creation, method invocation, property set or get) to a method, constructor, property, or event protected by a link demand. This protection incurs some performance costs (the one-level LinkDemand was faster) and changes the semantics of the security check—the full stack-walk demand might fail where the one-level check would have passed.
Assembly Loading Wrappers Several methods used to load managed code, including Assembly.Load(byte[]), load assemblies with the evidence of the caller. Specifically, if you wrap any of these methods, the security system could use your code's permission grant, instead of the permissions of the caller to your wrapper, to load the assemblies. Obviously, you do not want to allow less trusted code to have you load code on its behalf that is granted higher permissions than those of the caller to your wrapper.
Any code that has full trust or significantly higher trust than a potential caller (including an Internet-permissions-level caller) could be vulnerable to weakening security in this way. If your code has a public method that takes a byte array and passes it to Assembly.Load(byte[]), thereby creating an assembly on the caller's behalf, it might break security.
This issue applies to the following API elements:
System.AppDomain.DefineDynamicAssembly System.Reflection.Assembly.LoadFrom System.Reflection.Assembly.Load Exception Handling A filter expression further up the stack will run before any finally statement. The catch block associated with that filter runs after the finally statement. Consider the following pseudocode:
void Main() { try { Sub(); } except (Filter()) { Console.WriteLine("catch"); } } bool Filter () { Console.WriteLine("filter"); return true; } void Sub() { try { Console.WriteLine("throw"); throw new Exception(); } finally { Console.WriteLine("finally"); } }
This code prints the following:
Throw Filter Finally Catch
The filter runs before the finally statement, so security issues can be introduced by anything that makes a state change where execution of other code could take advantage. For example:
try { Alter_Security_State(); // This means changing anything (state variables, // switching unmanaged context, impersonation, and so on) // that could be exploitable if malicious code ran before state is restored. Do_some_work(); } finally { Restore_Security_State(); // This simply restores the state change above. }
This pseudo-code allows a filter back up the stack to run arbitrary code. Other examples of operations that would have similar effect are temporary impersonation of another identity, setting an internal flag that bypasses some security check, changing the culture associated with the thread, and so forth.
The recommended solution is to introduce an exception handler to isolate your code's changes to thread state from callers' filter blocks. However, it is important that the exception handler be properly introduced or this problem will not be fixed. The following Microsoft Visual Basic® example switches the UI culture, but any kind of thread state change could be similarly exposed.
YourObject.YourMethod() { CultureInfo saveCulture = Thread.CurrentThread.CurrentUICulture; try { Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE"); // Do something that throws an exception. } finally { Thread.CurrentThread.CurrentUICulture = saveCulture; } }
Public Class UserCode Public Shared Sub Main() Try Dim obj As YourObject = new YourObject obj.YourMethod() Catch e As Exception When FilterFunc Console.WriteLine("An error occurred: '{0}'", e) Console.WriteLine("Current Culture: {0}", Thread.CurrentThread.CurrentUICulture) End Try End Sub
Public Function FilterFunc As Boolean Console.WriteLine("Current Culture: {0}", Thread.CurrentThread.CurrentUICulture) Return True End Sub
End Class
The correct fix in this case is to wrap the existing try/finally block in a try/catch block. Simply introducing a catch-throw clause into the existing try/finally block will not fix the problem:
YourObject.YourMethod() { CultureInfo saveCulture = Thread.CurrentThread.CurrentUICulture;
try { Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE"); // Do something that throws an exception. } catch { throw; } finally { Thread.CurrentThread.CurrentUICulture = saveCulture; } }
This does not fix the problem because your finally statement has not run before the FilterFunc gets control.
The following code fixes the problem by ensuring that your finally clause has executed before offering an exception up the callers' exception filter blocks.
YourObject.YourMethod() { CultureInfo saveCulture = Thread.CurrentThread.CurrentUICulture; try { try { Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE"); // Do something that throws an exception. } finally { Thread.CurrentThread.CurrentUICulture = saveCulture; } } catch { throw; } }
Unmanaged Code Some library code will need to call into unmanaged code (for example, native code APIs, such as Win32). Because that means going outside the security perimeter for managed code, due caution is required. If your code is security neutral (see the Security-Neutral Code section of this document), both your code and any code that calls it must have unmanaged code permission (SecurityPermission.UnmanagedCode).
However, it will often be unreasonable to require your caller to have such powerful permissions. In such cases, your trusted code can be the go-between, similar to the managed wrapper or library code described previously. If the underlying unmanaged code functionality is totally safe, it can be directly exposed; otherwise, a suitable permission check (demand) is required first.
When your code calls into unmanaged code but you do not want your callers to have that permission, you must assert your right. An assertion blocks the stack walk at your frame. You must be scrupulously careful that you do not create a security hole in this process. Usually this means that you must demand a suitable permission of your callers and then use only unmanaged code to perform what that permission allows and no more. In some cases (for example, get time of day), unmanaged code can be directly exposed to callers without any security checks. In any case, any code that asserts must take responsibility for security.
Because any managed code that affords a code path into native code is a potential target for malicious code, determining which unmanaged code can be safely used and how it must be used requires extreme care. Generally, no unmanaged code should ever be directly exposed to partially trusted callers (see the following section). There are two primary considerations in evaluating the safety of unmanaged code use in libraries that are callable by partially trusted code:
Functionality. Does the unmanaged API provide safe functionality that does not allow potentially dangerous operations to be performed by calling it? Code access security uses permissions to enforce access to resources, so consider whether the API uses files, user interface, threading, or exposes protected information. If it does, the managed code wrapping it must demand the necessary permissions before allowing it to be entered. Additionally, while not protected by a permission, security requires that memory access be confined to strict type safety. Parameter checking. A common attack passes unexpected parameters to exposed unmanaged code API methods in an attempt to cause them to operate out of specification. Buffer overruns are one common example of this type of attack (using out of range index or offset values), or any parameters that might exploit a bug in the underlying code. Thus, even if the unmanaged code API is functionally safe for partially trusted callers (after necessary demands), managed code must also check parameter validity exhaustively to ensure that no unintended calls are possible from malicious code using the managed code wrapper layer. Using SuppressUnmanagedCodeSecurity There is a performance aspect to asserting and then calling unmanaged code. For every such call, the security system automatically demands unmanaged code permission, resulting in a stack walk each time. If you assert and immediately call unmanaged code, the stack walk can be meaningless: it consists of your assert and your unmanaged code call.
A custom attribute called SuppressUnmanagedCodeSecurity can be applied to unmanaged code entry points to disable the normal security check that demands SecurityPermission.UnmanagedCode. Extreme caution must always be taken when doing this because this action creates an open door into unmanaged code with no runtime security checks. It should be noted that even with SuppressUnmanagedCodeSecurity applied, there is a one-time security check that happens at JIT time to ensure that the immediate caller has permission to call unmanaged code.
If you use the SuppressUnmanagedCodeSecurity attribute, check the following points:
Make the unmanaged code entry point inaccessible outside your code (for example, "internal"). Any place you call into unmanaged code is a potential security hole. Make sure your code is not a portal for malicious code to indirectly call into unmanaged code and avoid a security check. Demand permissions, if appropriate. Use a naming convention to make it explicit when you are creating a dangerous path into unmanaged code, as described in the next section. Naming Convention for Unmanaged Code Methods A useful and highly recommended convention has been established for naming unmanaged code methods. All unmanaged code methods are separated into three categories: safe, native, and unsafe. These keywords can be used as class names within which the various kinds of unmanaged code entry points are defined. In source code these keywords should be added to the class name; for example, Safe.GetTimeOfDay or Native.Xyz or Unsafe.DangerousAPI. Each of these categories should send a strong message to the developers using them as described in the following table.
Keyword Security considerations safe Completely harmless for any code (even malicious) to call. Can be used just like other managed code. Example: get time of day. native Security neutral; that is, unmanaged code that requires unmanaged code permission to call. Security is checked, which stops an unauthorized caller. unsafe Potentially dangerous unmanaged code entry point with security suppressed. Developers should use the greatest caution when using such unsafe code, making sure that other protections are in place to avoid a security vulnerability. Developers must be responsible as this keyword overrides the security system.
User Input User data, which is any kind of input (data from a Web request or URL, inputs to controls of a Microsoft Windows Forms application, and so on), can adversely influence code because often that data is used directly as parameters to call other code. This situation is analogous to malicious code calling your code with strange parameters and the same precautions should be taken. User input is actually harder to make safe because there is no stack frame to trace the presence of the potentially untrusted data.
These are among the subtlest and hardest security bugs to find because although they can exist in code that is seemingly unrelated to security, they are a gateway to pass the bad data through to other code. To look for these bugs, follow any kind of input data, imagine what the range of possible values might be, and consider whether the code seeing this data can handle all those cases. You can fix these bugs thorough range checking and rejecting all inputs the code cannot handle.
Some common mistakes involving user data include the following:
Any user data in server response runs in the context of the server's site on the client. If your Web server takes user data and inserts it into the returned Web page, it might, for example, include a
|
Responses
|
No responses found. Be the first to respond and make money from revenue sharing program.
|
|