IIS Hardening - Miscellaneous

25 March 2015

Here are a few more IIS settings that I usually set to make the whole server more secure.

deployment - retail

When using ASP.NET, you have the White/Yellow error pages. Even on production servers I sometimes see detailed error description on that page.

This happens because of:

<system.web><customErrors mode="Off" /> 


<system.web><compilation debug="true" />

makes it even worse by potentially showing more detailed information about the error and your code.

This often happens if someone needed to debug something on the server and did not switch customErrors back on.

To make sure you never have detailed errors displayed on your production server, you can add the deployment-retail node to your machine.config.

Save the following code into Set-GlobalDeploymentRetail.ps1 and run it:


[string]$retailState = "true"
if ($turnoff) {$retailState = "false"}

# ---- Adds deployment retail node in machine.config

#  <system.web>
#    <deployment retail="true" />
#  </system.web>

function SetConfig([string]$filePath)
    $currentDate = (get-date).tostring("yyyyMMdd-HHmmss") 
    $file = [System.IO.Path]::GetFileNameWithoutExtension($filePath)
    $folder = [System.IO.Path]::GetDirectoryName($filePath)
    $backup = [System.IO.Path]::Combine($folder,$file + "_$currentDate" + ".config")

    $xml = [xml](get-content($filePath))

    $aNode = $xml.SelectSingleNode("/configuration/system.web/deployment")

    if ($aNode -ne $null)
       $aNode.SetAttribute("retail", $retailState) | out-null      

       Write-Host Updated system-web-deployment-Node in $filePath 
      $cons = $xml.configuration
      $swNode = $xml.SelectSingleNode("/configuration/system.web")

      $deploymentNode = $xml.CreateElement('deployment')         
      $deploymentNode.SetAttribute("retail", $retailState)

      $swNode.AppendChild($deploymentNode) | out-null


      Write-Host Added system-web-deployment-Node to $filePath 

Get-ChildItem $env:Systemroot\Microsoft.NET -Include machine.config -Recurse | ForEach-Object {
    SetConfig $_.FullName

It updates all machine.configs found. If you really need to debug on the server, you have to disable this again. Just the -turnoff switch for the script above.

Now even with

<customErrors mode="Off" />

you just get the 'safe' yellow/white page without details.

But really, you never want that ASP.NET error page at all.

To fix that we need to change:

<system.webServer><httpErrors existingResponse="Auto" ...>

If existingResponse is missing, the default Auto is used, which means use the defined error-page except when the ASP.NET used

Response.TrySkipIisCustomErrors = true;

now the ASP.NET error page is shown, the customErrors section didn't define any custom pages so the yellow/while page was displayed.

For most production sites, you may want to change this to

<system.webServer><httpErrors existingResponse="Replace" ...>

meaning whatever ASP.NET or other modules sent, this is a 500 request and I'm using my own error page for 500s or any response with a status > 400

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/SiteName'  -filter "system.webServer/httpErrors" -name "existingResponse" -value "Replace"

The third possible value for existingResponse is PassThrough it always uses the response from the module that created the error.

Tags: IIS | IT Pro | Security

Pages in this section


ASP.Net | Community | Development | IIS | IT Pro | Security | SQL (Server) | Tools | Web | Work on the road | Windows