Over the last few months I have been collecting best practices for deploying ASP.NET
applications to production. The intent was to create a document that described
the necessary steps needed to deploy consistent, reliable, secure applications that
are easily maintainable for administrators. The result was an 11 page document.
I would like to take a couple excerpts from it and essentially list what I believe
to be key requirements for production applications.
The key is consistency.
-
Generate new encryption keys
The benefit to doing this is that internal hashing and encrypting schemes use different
keys between applications. If an application is compromised, the private keys that
can get recovered will have no effect on other applications. This is most important
in applications that use Forms Authentication such as the member’s section. This Key
Generator app is using built-in .NET key generation code in the RNGCryptoServiceProvider.
-
Version and give Assemblies Strong Names
Use AssemblyInfo.cs file:
[assembly: AssemblyTitle("NameSpace.Based.AssemblyTitle")]
[assembly: AssemblyDescription("This is My Awesome Assembly…")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("My Awesome Company")]
[assembly: AssemblyProduct("ApplicationName")]
[assembly: AssemblyCopyright("Copyright © 2009")]
[assembly: AssemblyTrademark("TM Application Name")]
[assembly: AssemblyCulture("en-CA")]
Strong names and versioning is the backbone of .NET assemblies. It helps distinguish
between different versions of assemblies, and provides copyright attributes to code
we have written internally. This is especially helpful if we decide to sell any of
our applications.
-
Deploy Shared Assemblies to the GAC
-
Assemblies such as common controls
-
gacutil.exe -I "g:\dev\published\myApp\bin\myAssembly.dll"
If any assemblies are created that get used across multiple applications they should
be deployed to the GAC (Global Assembly Cache). Examples of this could be Data Access
Layers, or common controls such as the Telerik controls. The benefit to doing this
is that we will not have multiple copies of the same DLL in different applications.
A requirement of doing this is that the assembly must be signed and use a multipart
name.
-
Pre-Compile Site: [In Visual Studio] Build > Publish Web Site
Any application that is in production should be running in a compiled state. What
this means is that any application should not have any code-behind files or App_Code
class files on the servers. This will limit damage if our servers are compromised,
as the attacker will not be able to modify the source.
-
Encrypt SQL Connections and Connection Strings
Encrypt SQL Connection Strings
Aspnet_regiis.exe -pe connectionStrings -site myWebSite -app /myWebApp
Encrypt SQL Connections
Add ‘Encrypt=True’ to all connection strings before encrypting
SQL Connections contain sensitive data such as username/password combinations for
access to database servers. These connection strings are stored in web.config files
which are stored in plain-text on the server. If malicious users access these files
they will have credentials to access the servers. Encrypting the strings will prevent
the ability to read the config section.
However, encrypting the connection string is only half of the issue. SQL transactions
are transmitted across the network in plain-text. Sensitive data could be acquired
if a network sniffer was running on a compromised web server. SQL Connections should
also be encrypted using SSL Certificates.
-
Use key file generated by Strong Name Tool:
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\sn.exe
“sn.exe -k g:\dev\path\to\app\myAppKey.snk”
Signing an assembly provides validation that the code is ours. It will also allow
for GAC deployment by giving the assembly a signature. The key file should be unique
to each application, and should be kept in a secure location.
-
Set retail=”true” in machine.config
<configuration>
<system.web>
<deployment retail="true"/>
</system.web>
</configuration>
In a production environment applications do not want to show exception errors or trace
messages. Setting the retail property to true is simple way to turn off debugging,
tracing, and force the application to use friendly error pages.
In part 2 I continue my post on more best practices for deployment to a production
environment.