Security Tips
Always use the principle of least privilege to develop and
run applications.
Least privilege implies using an account that has only the minimum rights
necessary to execute a thread. This way, if a vulnerability (such as a buffer
overrun) exists in the thread's application and is exploited, the thread will
only be able to perform operations that are granted to the account. This could
help prevent an attacker from using a buffer overrun exploit and perform
administrative tasks on a computer. For example, if you log on to your computer
using a least privileged (non-administrative) account, an attacker would not be
able to perform administrative tasks on your behalf.
Ensure that only user-friendly error messages that do not compromise
security are returned to end users.
Unhandled exceptions can compromise security. Therefore, they should never be
available to the end user. For example, a SqlException that reveals the name
and structure of a user table used by a Web application could allow an attacker
to easily modify that table if a security vulnerability also exists in the Web
application itself, or in its host process.
Fail safely when exceptions are thrown.
You must always attempt to recover from unhandled exceptions. In most cases,
this can be accomplished by using Try/Catch/Finally blocks. Resource access
attempts should be coded in Try blocks. Exceptions should be caught in Catch
blocks. Any cleanup code should be placed in Finally blocks, which should
also ensure that the code has not been made insecure due to the exception.
Implement pessimistic variable defaults.
This simply means planning for the worst, assuming some type
of attack, whether intentional or not, will always take place. For
example, access levels should always be set to none by default. Similarly,
newly created user accounts should always represent the most restricted user.
Ensure that your application canonicalizes all references to external
resources.
Canonicalization is the process of translating all possible forms of an entity
into one form. For example, the following two domain user names are identical:
janedoe@example.com and EXAMPLE\janedoe (assuming that the fully qualified
domain name of the EXAMPLE domain is example.com). Therefore, if your ASP.NET
Web application's code is implemented to deny access to a user who logged in as
EXAMPLE\janedoe, it would grant access to that same user if that user logs in
as janedoe@example.com. Note that this does not apply to URL authorization when
Windows authentication is used. The ASP.NET runtime automatically canonicalizes
the names.
Assume that all user input is malicious, and validate it accordingly.
A good rule of thumb of a security engineer should be to always assume the
worst could happen. This includes assuming that all user input is bad,
regardless of the type of application and user input being entered. A simple
Search field on a Web page could be hijacked to wipe out an entire hard drive.
Use application domains to execute third-party external applications from
within a process.
When you need to execute third-party applications from within one of your
applications, it is wise to consider using application domains. Application
domains allow multiple applications to run within the same process, with each
having direct access to only its own memory. This prevents the failure of a
third-party application from affecting the host process.
Always secure confidential data.
Confidential data should almost always be secured through encryption. There are
three primary ways you can secure your confidential data in a Microsoft
Windows environment. The first way is to use managed classes. The Microsoft
.NET Framework exposes classes in the System.Security.Cryptography namespace to
help secure confidential data through both encryption and data integrity. These
classes are devided into managed cryptography classes, which are written
entirely in managed code, and service provider cryptography classes, which are
wrappers around the associated cryptographic service providers implemented by
the operating system. Secondly, you can use the Data Protection
application programming interface (DPAPI) to encrypt and decrypt data. This is
an unmanaged API that does not use the cryptographic services used by the
managed cryptography services. Finally, you can use access control lists (ACLs)
to secure data. ACLs work by granting or denying access to a specific user or
group of users.
Use code access permissions to help keep resources secure.
The Microsoft .NET Framework introduces code access permissions to grant or deny
resource access to code, rather than users. This allows you to not only
restrict an application from performing an operation on behalf of a
specific user or group of users, but you can also restrict an application from
performing an operation based on its evidence. Evidence identifies code,
such as where it came from, who published it, etc. By demanding, denying, and
requesting certain code access permissions, you can ensure that your code does
nothing more than what it is supposed to do. This can help prevent your code
from being called by malicious code in an attempt to perform a malicious
operation.
Secure your Web services using WS-Security.
WS-Security is a standard that defines how Extensible Markup Language (XML)
signatures and XML encryption should be used with XML data. The Microsoft .NET
Framework 1.1 provides the System.Security.Cryptography.Xml.SignedXml class for
digital signing. The .NET Framework 2.0 provides the
System.Security.Cryptography.Xml.EncryptedXml for encryption. The Web Services
Enhancements (WSE) 2.0 Framework also provides classes for signing and
encrypting XML data. By using WS-Security, you can be sure that your
confidential XML data is signed and encrypted using a standard mechanism. This
allows your data to be used in Internet scenarios where you do not have control
over the implementation used by the recipient.
Use Internet Information Services (IIS) to secure Microsoft .NET Remoting
functionality.
Microsoft .NET Remoting allows applications running in different application
domains or processes to communicate. By default, remote components communicate
either over transmission control protocol (TCP) or Hypertext Transfer Protocol
(HTTP). One of the problems with cross-process communication is authentication.
To take advantage of Windows authentication, you should use HTTP for remote
communication. This allows you to host the remote component in IIS, which
supports Windows authentication. If you use TCP for remote communication, you
would need to implement a custom authentication mechanism.
Use the Microsoft .NET Framework Configuration tool to secure Microsoft .NET
Framework-based applications.
The .NET Framework Configuration tool allows you to group code into code groups,
to which membership conditions and permission sets can be associated.
Membership conditions group code into code groups based on evidence. Once this
happens, the associated permission sets are then granted to the code in the
code group. Always place the most restricted code in code groups higher in the
hierarchy. This forces you to manually define code groups that should contain
code with greater permissions.
Always secure your logon page with Secure Sockets Layer (SSL) when a custom
authentication mechanism is implemented.
SSL uses digital signing and encryption to authenticate a computer and a Web
server. Confidentiality is maintained through a secret shared key, which only
the computer and the Web server know for a certain amount of time. Therefore,
any data that is intercepted during transmission after the key exchange cannot
be understood. SSL should be used to secure all pages where confidential data
will be posted. An example is the logon page for a Web site that uses a type of
forms-based authentication. This ensures that the logon credentials cannot be
interpreted if they are intercepted during the post from the Web browser to the
Web server.
Use impersonation when appropriate to help secure resources used by your
applications.
Impersonation allows a thread to run in the context of a user account other than
the one that initially ran the process. You should use impersonation when
you want an application to run with privileges granted to the logged-on user.
However, you should also be aware that this can also elevate privileges that
were granted to the account used to start the application.
Perform a security unit test on each component in your applications.
When unit-testing your applications for security, you should test every possible
entry point in each component. For example, you should test each public method
call in a business component with both valid and invalid input values and
examine the results. This helps to identify vulnerabilities in each component.
Use strong names to secure your Microsoft .NET Framework-based applications.
Strong names help identify a component that is referenced by an application. A
strong name consists of an assembly name, version number, culture, and public
key. The public key is associated with a private key that is used to digitally
sign the assembly. Because a client application that uses a strong-named
assembly references the public key at design time, the client application can
be sure that the correct assembly is loaded at run time. For example, if a
strong-named assembly is replaced with a malicious assembly with the same file
name, the common language runtime (CLR) will immediately realize this and
handle it accordingly, usually by throwing an exception. Note that you should
not use strong names when the creator of an assembly is important. Strong names
do not provide this type of security. You would need to use digital
certificates instead. Strong names simply protect an application by preventing
a malicious assembly with the same file name and path from being loaded.
Back to Tips and Tricks