In my previous post I started a list of best practices that should be followed for
deploying applications to production systems. This is continuation of that post.
Create new Virtual Application in IIS
Right-click [website app will live in] > Create Application
Creating a new application provides each ASP.NET application its own sandbox environment.
The benefit to this is that site resources do not get shared between applications.
It is a requirement for all new web applications written in ASP.NET.
Create a new application pool for Virtual App
Right click on Application Pools and select Add Application Pool
Define name: “apAppName” - ‘ap’ followed by the Application Name
Set Framework version to 2.0
Set the Managed Pipeline mode: Most applications should use the default setting
An application pool is a distinct process running on the web server. It segregates
processes and system resources in an attempt to prevent errant web applications from
allocating all system resources. It also prevents any nasty application crashes from
taking the entire website down. It is also necessary for creating distinct security
contexts for applications. Setting this up is essential for high availability.
Set the memory limit for application pool
There is a finite amount of available resources on the web servers. We do not want
any one application to allocate them all. Setting a reasonable max per application
lets the core website run comfortably and allows for many applications to run at any
given time. If it is a small lightweight application, the max limit could be set lower.
Create and appropriately use an app_Offline.htm file
Friendlier than an ASP.NET exception screen (aka the Yellow Screen of Death)
If this file exists it will automatically stop all traffic into a web application.
Aptly named, it is best used when server updates occur that might take the application
down for an extended period of time. It should be stylized to conform to the application
style. Best practice is to keep the file in the root directory of the application renamed
to app_Online.htm, that way it can easily be found if an emergency update were to
Don’t use the Default Website instance
This should be disabled by default
Either create a new website instance or create a Virtual Application under existing
Numerous vulnerabilities in the wild make certain assumptions that the default website
instance is used, which creates reasonably predictable attack vectors given that default
properties exist. If we disable this instance and create new instances it will mitigate
a number of attacks immediately.
Create two Build Profiles
One for development/testing
One for production
Using two build profiles is very handy for managing configuration settings such as
connection strings and application keys. It lessens the manageability issues associated
with developing web applications remotely. This is not a necessity, though it does
make development easier.
Don’t use the wwwroot folder to host web apps
Define a root folder for all web applications other than wwwroot
As with the previous comment, there are vulnerabilities that use the default wwwroot
folder as an attack vector. A simple mitigation to this is to move the root folders
for websites to another location, preferably on a different disk than the Operating
These two lists sum up what I believe to be a substantial set of best practices for
application deployments. The intent was not to create a list of best development
best practices, or which development model to follow, but as an aid in strictly deployment.
It should be left to you or your department to define development models.
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: AssemblyDescription("This is My Awesome Assembly…")]
[assembly: AssemblyCompany("My Awesome Company")]
[assembly: AssemblyCopyright("Copyright © 2009")]
[assembly: AssemblyTrademark("TM Application Name")]
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
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
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
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
Good enough is sometimes not good enough. I’ve been doing a lot of thinking
lately (well, I’m always thinking), and security has been an issue that has come up
a lot. Frankly, I’m a two-bit software developer. I know my code isn’t
the best, nor the most secure. I use strong passwords, encrypt my sensitive
data, and try to limit access to the applications for those who need to use it.
In theory this works. Problem is, it’s a lame theory. There are so many
unknown factors that have to be taken into account. Often times they aren’t.
When I go to build an application I spend time designing it and architecting it.
This is usually the case for most developers. What I’ve noticed though, is that
I don’t spend time securing it. I can’t.
Imagine building a house. You put locks on the doors, bars on the windows, and
someone breaks in. Why? Because someone left the key in the door.
You can’t build against that. You just can’t.
You can follow the Security
Development Lifecycle, which I recommend to each every single developer I meet.
There are tons of resources available.
But it can only go so far. It’s designed more for being part of the iterative
processes, not the architecture. Or at least, that’s how most people interpret
My last post talked about Single
Sign-On (SSO). It’s a great sellable feature for any product. What most
people don’t realize though is the inherent security benefit to it. With it,
that means one less password to remember, one less password that could get intercepted,
one less password to change every month. This is a fundamental architectural
issue. But at the same time, it’s common sense.
What is sometimes the simplest idea, is usually the correct solution
What the hell does that mean? It means keep it simple. Security is simple.
Keep data from prying eyes, and keep it from getting lost. This is common sense.
Security is not difficult to comprehend. It becomes difficult when academics
get involved. Spouting theories and methodologies scares people into thinking
security is extremely difficult to implement. It’s not!
Follow the Data
Understanding the flow of data is crucial in properly architecting an application.
It’s crucial in properly securing an application as well. SSO
is a perfect example of this.
The SSO feature in Office SharePoint Server 2007 maps user credentials to back-end
data systems. Using SSO, you can access data from server computers and services that
are external to Office SharePoint Server 2007. From within Office SharePoint Server
2007 Web Parts, you can view, create, and change this data. The SSO feature ensures
It makes perfect sense. It’s simple when you think about, and it affects every
subsystem of SharePoint. Make security a feature.
To configure Active Directory Federation Services (ADFS) to work with SharePoint follow these instructions:
I have to say that it's awesome that we can configure SharePoint to use ADFS for user authentication as eases the burden on the SharePoint users because they don't have to remember another username and password. This is especially useful, if you're using SharePoint for public-facing website. I wish it was easier to configure though. Here are a few "gotchas" that I have encountered trying to get ADFS working with SharePoint:
- Extend your SharePoint web application to dedicate a separate section/URL for ADFS authentication
- The configuration guides are very exact, in the sense that everything must be done exactly as it says in the guide. If you do not follow the instructions to the point or if you miss a step or two, ADFS authentication won't work and it will be nearly impossible to figure out what you did wrong. More often than not, it will be a lot easier to uninstall/reinstall ADFS and try again
- Read your old notes on PKI and DNS, because configuring ADFS with SharePoint requires your PKI and DNS skills to be very sharp. Let's face it we tend to forget skills that we do not use on day to day basis
- Use ADFS Diagnostics Tool, it is a very useful tool
- Use ADFS Organizational Group Claims when assigning access permissions in SharePoint
- To assign permissions to a specific user (instead of the assigning permissions through ADFS Organizational Group Claims), user must log in to the SharePoint first.
For some reason, Microsoft has decided to hide Event content type in SharePoint (MOSS/WSS) and prevent users from creating a custom list based on that content type. To unhide Event content type:
- Open your existing calendar on the site and go to List Settings
- Click on Advanced Settings and change the settings to "Allow Management of Content Types", which will reveal the Event content type in that list settings
- Click on the Event in the list of content types
- Under List Content Type Information click on the Parent link, which is strangely enough also called Event
- Under Settings click on the "Name, Description & Group" link and assign Event content type to the new group, for example "List Content Types". That's it, from now on you will be able to create custom lists based on the Event content type
There is another way to unhide Event content type, and even though I find it less graceful, I think it's worth mentioning:
- Go to [Drive]:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\ctypes\ folder and backup the contents of that folder
- To unhide Event content type, run
stsadm -o deactivatefeature -filename "ctypes\feature.xml" -url http://[SharePointWebApp]
stsadm -o activatefeature -filename "ctypes\feature.xml" -url http://[ SharePointWebApp]
To change a port number that SharePoint Central Administration site is running on:
- Open Command Prompt
- Go to BIN folder in SharePoint install directory (by default, it would be "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN")
- To get the port number that Central Administration site is currently running on, type
stsadm.exe -o getadminport
- To change a port number that SharePoint Central Administration site is using, type
stsadm.exe -o setadminport -port <portnumber>
For a sophisticated web application, SharePoint (WSS or MOSS) is missing a feature as simple as Deny access (Deny Read, Deny Write, Deny All). To deny access to the SharePoint for single user or a group of users, you modify Policy for Web Application in SharePoint Central Administration:
- Open SharePoint Central Administration
- Click on Application Management
- Then, under Application security, click on Policy for Web Application
- Select correct web application in the drop down
- Click on Add Users
- Select web application and the zone. Click Next
- Enter the username or security group. Select Deny Write or Deny All and click on Finish
Note: This will deny access to the whole web application in SharePoint! There is no way to deny access to a specific SharePoint item (site, list, document library and so on)
Hopefully Microsoft will fix this weakness in the next service pack or so…
When you have a public-facing site built using SharePoint technologies, opening Microsoft Office documents (Word, Excel, PowerPoint, Visio, etc.) stored on this website requires user to login. You can hit Cancel at the login prompt and still be able to see the document, but having a login prompt displayed to the Internet users, sort of defeats the purpose of having SharePoint-built public facing website with anonymous access turned on. This happens becuase Microsoft Office is closely integrated with MOSS or WSS 3.0 now, and MS Office is now able to recognize that the document is stored within SharePoint, so the appropriate SharePoint authentication/authorization tools kick in. This problem can be resolved mostly by implementing two simple steps (assuming you have already enabled anonymous access on SharePoint):
- Disable 'Client Integration' for the web application under Central Admin Home Page >> Application Management >> Authentication Providers
- Remove the OPTIONS verb from the <HTTPHandlers> registration line in web.config file
To enable anonymous access for a web application within SharePoint:
1. Go to Central Administration >> Application Management >> Authentication Providers.
- make sure to pick correct web application from the drop-down list at the top-right corner of the page.
- select the Membership Provider (most likely it will be "Default") and enable check "Enable anonymous access" checkbox.
- click OK to save the settings.
2. The step above will usually enable anonymous access in IIS Manager, but just be sure:
- open IIS Manager
- right-click on your website and click on "Edit" under Authentication and Access Control
- make sure "Enable anonymous access" is checked
3. We now need to explicitly enable anonymous access on our website(s)
- browse to the website
- click Site Actions >> Site Settings >> People and Groups >> Site Permissions
- click on Settings >Anonymous Access and enable anonymous access for the site
* Anonymous access will be also enabled on all subsites that inherit security settings from the parent site.
If you have a public Sharepoint site (MOSS 2007 or WSS 3.0) that is accessible to anonymous users and you’re not using custom scopes, you probably already noticed that every time users try to search they get a user prompt. To get pass this prompt you must enter valid username, otherwise you’ll get famous “Access Denied” page. So much for anonymous access, right?
Anyway, the problem is with OSSSearchResults.aspx page, specifically with one of the inheritance reference that ASPX page. I’m talking about the part of the code that sets the inheritance of the page from the generic application page base class, which is not really required for this page to function properly.
To allow anonymous users to search your publicly available sites you need to remove that inheritance from the code, so find part of the code inside the <Page> tag that states “Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" and remove that part of the code (not the whole line, just the part that inhertis the application page base.) OSSSearchResults.aspx page is usually stored at C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS on your SharePoint server. Make sure you backup the file before making any changes!
Making those changes will not only allow anonymous users to search the SharePoint content, but also will keep the SharePoint search secure, meaning that anonymous users will only be able to search the part of the SharePoint they have permissions to view.