Skip to content
English
  • There are no suggestions because the search field is empty.

ServicePass Web.config Hardening Recommendations

This is a summary of security recommendations from existing documentation and guides.  Many of these are probably already implemented but a period review is important. 

 Web.config Security Hardening

This document describes the hardening recommendations for Microsoft .net Framework 4.8 web.config files,  and why each change is recommended.

Apply and validate these changes in a staging environment first. A few settings (notably Content-Security-Policy and requestValidationMode="4.5") can affect application behavior and may require page-level tuning.


1. Secrets stored in clear text (highest priority)

The following values are secrets and are currently stored in plain text:

Setting Location
recaptchaPrivateKey <appSettings>
Server.CompanyAccountKey <appSettings>
SMTP password <system.net><mailSettings><smtp><network>

Recommendation

  • Encrypt the sensitive configuration sections with the ASP.NET protected configuration provider, e.g.:
    aspnet_regiis -pe "appSettings" -app "/YourApp"
    aspnet_regiis -pe "system.net/mailSettings/smtp" -app "/YourApp"
  • Or move secrets out of the file entirely (environment variables, a vault, or a machine-protected store) and reference them at runtime.
  • Rotate any secret that has ever been committed to source control (the repo already contains sample keys).
  • SurePassID provides the Installation Manager app that can be used to rotate all encryption keys in a cadence that matches your organization policies. 
  • See Protecting sensitive configuration data for more info.

The hardened file keeps the values in place but flags each one with a comment; the encryption/relocation step must be performed as part of deployment.


2. system.web changes

2.1 Custom errors

  • Before: customErrors mode="On" with a single 404 -> home.aspx.
  • After: mode="RemoteOnly" (developers still see errors locally), an explicit defaultRedirect, plus generic redirects for 403, 404, and 500.
  • Why: Guarantees clients never receive detailed exception/stack-trace pages while still covering server errors.
<customErrors mode="RemoteOnly" defaultRedirect="home.aspx">
<error statusCode="403" redirect="home.aspx" />
<error statusCode="404" redirect="home.aspx" />
<error statusCode="500" redirect="home.aspx" />
</customErrors>

2.2 Session state

  • Before: sessionState timeout="60" (1 hours).
  • After: timeout="20", cookieless="UseCookies", regenerateExpiredSessionId="true".
  • Why: A 60-minute idle session dramatically widens the window for session hijacking on shared machines. Twenty minutes is a common baseline; adjust to policy. Forcing cookie-based sessions prevents session IDs from appearing in URLs.
<sessionState timeout="20" mode="InProc" cookieless="UseCookies" regenerateExpiredSessionId="true" />

2.3 Cookies

  • Before: httpOnlyCookies="true" requireSSL="true".
  • After: adds sameSite="Strict".
  • Why: SameSite=Strict mitigates CSRF by preventing cookies from being sent on cross-site navigations. Use Lax if strict breaks a required cross-site flow.
<httpCookies httpOnlyCookies="true" requireSSL="true" sameSite="Strict" />

2.4 Compilation / tracing

  • After: added debug="false" on <compilation> and <trace enabled="false" localOnly="true" />.
  • Why: Debug builds disable optimizations and can leak information; ASP.NET tracing can expose sensitive request data. Both are explicitly disabled.
<compilation targetFramework="4.0" debug="false" />
<trace enabled="false" localOnly="true" />

2.5 httpRuntime

  • Before: requestValidationMode="2.0", enableVersionHeader="false".
  • After: requestValidationMode="4.5", added maxRequestLength="4096" (KB) and targetFramework="4.5".
  • Why: Request validation mode 2.0 uses the weaker legacy validation pipeline. Mode 4.5 applies validation earlier and more consistently. Capping request length reduces exposure to large-payload denial-of-service.
  • Note: Validate that no page legitimately posts HTML/markup; if it does, scope the relaxation to that page rather than globally downgrading validation.
<httpRuntime enableVersionHeader="false" requestValidationMode="4.5" maxRequestLength="4096" targetFramework="4.5" />

2.6 machineKey (optional)

  • Added a commented <machineKey> template.
  • Why: Setting explicit, per-deployment keys ensures ViewState/Forms tokens are not portable across environments and are not derived from defaults. Generate unique values.
<machineKey validationKey="GENERATE-ME" decryptionKey="GENERATE-ME" validation="HMACSHA256" decryption="AES" />


3. SMTP (system.net)


  • enableSsl="true" is already present and retained.
  • The password attribute is flagged as a secret (see Section 1).
<system.net>
<mailSettings>
<smtp><network defaultCredentials="false" host="" port="587" userName="" password="" enableSsl="true" /></smtp>
</mailSettings>
</system.net>


4. system.webServer changes


4.1 Managed modules

  • Before: runAllManagedModulesForAllRequests="true".
  • After: false.
  • Why: Running every managed module for static/every request is unnecessary, increases attack surface, and hurts performance.
<modules runAllManagedModulesForAllRequests="false" />

4.2 Response headers

Header Before After Reason
X-Frame-Options SAMEORIGIN DENY The portal should not be framed at all; blocks clickjacking. Use SAMEORIGIN only if self-framing is required.
X-XSS-Protection 1; mode=block 0 The legacy XSS auditor is deprecated and can itself be abused; modern browsers ignore it. CSP replaces it.
X-Content-Type-Options nosniff nosniff Unchanged (good).
Strict-Transport-Security max-age=31536000; includeSubDomains adds preload Stronger HTTPS enforcement. Only keep preload if you intend to submit the domain to the HSTS preload list.
Referrer-Policy (none) no-referrer Prevents leaking URLs (which may contain tokens) to third parties.
Permissions-Policy (none) geolocation=(), microphone=(), camera=() Disables powerful browser features the app does not use.
Content-Security-Policy (none) restrictive policy Primary defense against XSS/data injection; frame-ancestors 'none' also reinforces anti-framing.
X-Powered-By removed removed Unchanged (good).
  • CSP note: The supplied policy (default-src 'self', no unsafe-inline) is a strong starting point but will likely block inline scripts/styles and external CDNs. Tune it to your actual assets, preferably using nonces or hashes rather than unsafe-inline.
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="DENY" />
<add name="X-XSS-Protection" value="0" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
<add name="Referrer-Policy" value="no-referrer" />
<add name="Permissions-Policy" value="geolocation=(), microphone=(), camera=()" />
<add name="Content-Security-Policy" value="default-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" />
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>

4.3 Request filtering

  • Server header: added removeServerHeader="true" to strip the Server banner (requires IIS 10+). Remove this attribute on older IIS.
  • Verbs: added an allow-list (GET, POST, HEAD) with allowUnlisted="false" to block TRACE, PUT, DELETE, etc. Add verbs if the app requires them.
  • Request limits: maxAllowedContentLength="4194304" (4 MB), maxUrl, and maxQueryString caps to reduce DoS/overflow surface.
  • Existing hiddenSegments (account_setup, Trace) are retained.
<security>
<requestFiltering removeServerHeader="true">
<hiddenSegments>
<add segment="account_setup" />
<add segment="Trace" />
</hiddenSegments>
<verbs allowUnlisted="false">
<add verb="GET" allowed="true" />
<add verb="POST" allowed="true" />
<add verb="HEAD" allowed="true" />
</verbs>
<requestLimits maxAllowedContentLength="4194304" maxUrl="4096" maxQueryString="2048" />
</requestFiltering>
</security>

4.4 HTTP errors

  • Added <httpErrors errorMode="Custom" existingResponse="Auto" />.
  • Why: Prevents detailed IIS-level error pages from reaching remote clients, complementing the ASP.NET customErrors setting.
<httpErrors errorMode="Custom" existingResponse="Auto" />

4.5 Directory browsing

  • Added <directoryBrowse enabled="false" />.
  • Why: Explicitly ensures directory contents cannot be enumerated.
<directoryBrowse enabled="false" />


5. Deployment checklist


  1. Encrypt or externalize all secrets (Section 1) and rotate exposed keys.
  2. Generate and set a unique machineKey per environment.
  3. Confirm the site is served exclusively over HTTPS (HSTS assumes this).
  4. Deploy to staging, then exercise every page to validate:
    • Content-Security-Policy does not block required scripts/styles/resources.
    • requestValidationMode="4.5" does not reject legitimate form input.
    • Verb allow-list covers all endpoints the app uses.
  5. Verify removeServerHeader is supported by the target IIS version (10+); remove the attribute otherwise.
  6. Confirm session timeout aligns with your security policy.
  7. Re-run a security header scan (e.g., securityheaders.com or an internal scanner) after deployment.