OWASP Top 10 #6 – Security Misconfiguration

What Is It?

Security misconfiguration is anything which is considered insecure due to the settings or configuration upon a server.

This can be anything from debug settings being turned on or even out of date third party frameworks being used.

Custom Errors

Leaking of information about the implemented technology stack could be an invitation for hackers to probe a system further. With regards to an SQL injection attack, error messages can be used to view details about the database schema such as table names and then further be used to display the contents of a database table.

Error messages displayed to a user should contain information useful to the user only and nothing else. They should report to the user the minimal amount information for them to react to the error.

Any information such as details of the error or the trace stack should be hidden from the user.

We can disable the standard .NET ‘yellow’ error message which contains the trace stack and the details of the error on a site basis. This is done within the customErrors node of the web.config

<customErrors mode="On" defaultRedirect="Error.aspx" />

The mode attribute can contain the following values:

  • On
    • Errors are reported in full. This is the default value.
  • Off
    • Errors are not reported. The user is redirected to the page defined within the defaultRedirect attribute
  • RemoteOnly
    • Users viewing the site on their local host are reported the errors in full
    • Users not viewing the site on their local host are redirected to the page defined within the defaultRedirect attribute.

If no defaultRedirect is provided the user is presented with a http response code of 500. This in itself is bad as it highlights our site as a potential site worthy of more probing by a hacker. The status code is easily read by batch scripts probing sites.

Providing a defaultRedirect presents the user with the page defined by the attribute along with a http status code of 302 (temporary redirect). This unfortunately creates a query string parameter of aspxerrorpath set to the relative URL of the page which caused the error. This can also be easily used by batch scripts to determine if a page is an error page.

We can redirect to the error page without the indicating that there was an error by changing the RedirectMode from ResponseRedirect (default) to ResponseRewrite.

<customErrors mode="On" defaultRedirect="Error.aspx" RedirectMode="ResponseRewrite" />

With this set, the contents of the error page is simply set to the response of the request without a redirect. The http status code is set to 200 which is the OK code. The hacker would need to read the contents of the page to try and determine if the page is an error page. This in itself is harder and slower. Anything we can do to slow down the hacker reduces the amount of hacking they can do on our site.

Disabling Trace

Trace information allows collecting, viewing and analysis of debug information that is collected and cached by ASP.NET. The information can be viewed at the bottom of individual pages or within the trace viewer which is accessed by calling the Trace.axd page from the route directory of the web site.

Like any debug information it contains details of implemented technology and potentially sensitive information that might be logged by accident. There are many instances of security issues where personal information such as credit card details or user accounts used in database connection strings which are logged as part of the debugging.

Tracing should be disabled within the web.config for all production environments.

<trace enabled="false" />

Keep Frameworks/Third Party Code Up To Date

All third party frameworks should be kept up to date to ensure that you are protected from any security issues which have been fixed within them.

With the use of NuGet this can be achieved very easily.

Encrypting Sensitive Parts Of The Web.Config

Sensitive data such as user accounts, passwords and private keys that are contained within the web.config should be encrypted.

If they are accidentally exposed to the user during an error while accessing a page or logged into an audit table and viewed by someone who should not see them, their details will not be readable.

It is also a good idea to reduce the amount of people who have access to sensitive information.

You can encrypt a node of a web.config at the visual studio command prompt by the following:

aspnet_regiis -site "Site Name In IIS" -app "/" -pe "connectionStrings"

This will update the web.config replacing the sensitive information with an encrypted version.

The file can be decrypted with the following command:

aspnet_regiis -site "Site Name In IIS" -app "/" -pd "connectionStrings"

This process uses a key which is created based upon the servers MAC address and as such is unique to the server and therefore can only be decrypted upon the web server.

Using Config Transforms To Ensure Secure Configurations

It can be very easy to leave debug settings such as non custom errors and tracing within a web.config.

Transforms for debug and release can be used to ensure that only settings for the required release are used when that release target is used.

Use Web.Release.Config to transform the Web.Config for release:

  • Remove debug attributes
  • Add custom errors
  • Remove trace

These transforms are only run during a site publish.

Retail Mode

Retail mode can be used as a back stop to ensure that no web.config setting which is considered unsafe in a production environment is actually enabled. For example in retail mode, turning off custom errors or turning on tracing will have no effect.

This setting can be set in the web.config though it is recommended to set it within the machine.config of the web server.

<deployment retail="true" />

OWASP Top 10 #4 – Insecure Direct Object References

Direct Object Reference

A direct object reference is a key or id which is used identify a piece or set of data. The data would typically be a record within a a table of a database.

They can be:

  • Patterns such as incrementing integers/ids
  • Natural keys such as a username or email address.
  • Discoverable data such as a national insurance number or a social security number.

What Is it?

An insecure direct object reference is when a user accesses a direct object reference when they are not permitted to.

This can be from an unsecured page and an unauthenticated user. It can also come from a secured page and authenticated user, where there is simply insufficient checks that they can view the data they have requested.

Quite often the user guesses or enumerates a direct object reference either manually or by an automated script.

If the data should only be visible to a subset of people then any requests to that data should be validated that they are permitted to see that data. Simply relying on not displaying links to the user is not secure enough.

How Can I Protect Against It?

Validate Access

The first point to address is to validate that the user has permission to access the data.

For example; is the person permitted to see the financial records of the bank account in question?

Quite often the validation checks are placed around populating the UI to navigate to the data but no checks are placed around querying the data.

Indirect Reference Maps

A normal approach to view database records on a web page is to expose the table fields and their direct object references on the URL

https://www.MySite/Foo.aspx?id=1

Here an attacker can simply increment the id to try and view other peoples Foo which are simple incrementing ids or identity indexes generated automatically by the database.

An indirect reference provides an abstraction between what is publicly observable in the URL and what is used to uniquely identify a record within a database.

A dictionary is used to store a map between the id and a randomly generated cryptically secure identifier. We then pass these secure identifier to the user as part of URLs which they can request.

https://www.MySite/Foo.aspx?id=ASWERDFMJSDGJSERSASKAWEOSDSDF

These keys should also be mapped to the user’s session to protect against the ids being leaked:

The following code shows how to generate a cryptically safe unique id using the RNGCryptoServiceProvider class.

using System.Security.Cryptography;

using( var rng = new RNGCryptoServiceProvider() )
{
    map[id] = HttpServerUtility.UrlTokenEncode(rng.GetBytes(new byte[32]));
}

// Store the map within the users session
HttpContext.Current.Session["Map"] = map;

In the example above it would be best to only create one instance of the RNGCryptoServiceProvider class regardless of how many direct object references are being made. Consider creating a class which implements IDisposable which calls Dispose upon the instance of RNGCryptoServiceProvider within it’s Dispose method.

Obfuscation via non-discoverable surrogate keys

A surrogate key is a set of fields which when used together can uniquely identify a record. These are harder to guess than a single column which has a distinctive pattern such as an identify index which increments by one each time.

Surrogate keys would require more space to index and are also slower, it is a trade off between performance and security.

A random unique identifier such as a GUID is harder to guess but does not perform as well as an integer when used to search upon. Also for tables such as logs and audits which are used to generate a high number records, the indexes will become fragmented and as such will have more overhead for de-fragmenting them regularly.

OWASP Top 10 #3 – Broken Authentication & Session Management

How to secure .NET websites from broken authentication and session management security attacks.

Sessions In A Stateless Protocol

To understand broken authentication attacks such as session hijacking it is important to understand how a user is logged in and kept logged in within the stateless protocol HTTP.

HTTP is a stateless protocol, each request is independent of every other request. Any knowledge of previous requests and their contents is maintained outside of the bounds of the protocol.

ASP.NET maintains session data either on the client side in browser cookies or on the server side in memory or within a database and ties the data to the user via session which is identified by unique identifier.

Web sites which require a user to log in make use of a unique identifier or session token which is created during then authentication process, associated or linked to the users account and then passed between the users web browser and the web server via a cookie.

What Is It?

If the authentication session token is discovered by a potential attacker, it can be used to steal the users session. This can be by either a session fixation or a session hijack.

Session hijacking is when an attacker gets hold of a session identifier and uses this to gain access to a users session and hence impersonates them.

Session fixation is when a user who is logged in to a site overrides their session identifier set in a cookie by passing in another session identifier within the query string; thus pretending to be someone else with potentially elevated user access.

Session ids can be passed between client and server by a query string parameter within a URL as well as cookies and form data.

How Can I Protect Myself From It?

Do Not Persist Session Tokens In The URL

Seeing as URLs are logged, shared and retrievable from a browser’s history; the first line of defence is not to persist session tokens in URLs, you should favour cookies.

Note that a default form post action is GET; I have fixed many security issues which were caused simply by forgetting to set the action to POST.

Persist Session Tokens In Cookies

To get .NET to persist the session token within cookies you can set the cookieless attribute of the sessionState node to UseCookies within the web.config.

<system.web>
  <sessionState cookieless="UseCookies" />

Other options of the variable are:

  • UseUri
  • Always use the URL regardless of device support
  • UreCookies (default)
  • Always use cookies regardless of device support
  • UseDeviceProfile
  • ASP.NET determines if cookies are supported in the browser and falls back to URL if not.
  • AutoDetect
  • ASP.NET determines if cookies are enabled in the browser and falls back to the URL if not.

Note there is a difference between enabled and supported.

Note you should perhaps question whether users who are using browsers with no cookie support or with cookies disabled should be allowed to use your site.

Secure Cookies

All cookies should be set to HttpOnly; this prevents the browser from reading the contents and as such reduces the chance of their contents being read by malicious code.

Cookies which contain session data should be configured to be served over SSL connections only.

Use ASP.NET Membership Provider For Authentication

Whenever security is concerned, it is important to use tried and tested frameworks in favour of writing your own.

The .NET membership provider is built into ASP and should be favoured.

It contains the following functionality:

  • Automatic schema creation upon first usage
  • Default website projects which are set up to allow
  • Creating user accounts
  • User login/log out
  • Session persistence between page requests
  • Automatic page/URL protection from non logged in users or users not within a user group
  • User groups for a more granular permissions

Automatically Logout Expired Sessions

A session token should only be considered valid for the minimum viable amount of time possible. If a session token is leaked the smaller the time window it is exploitable reduces the chance of the session being hijacked.

You can set the forms login session length in minutes within the web.config:

&lt forms loginUrl="~/Account/Login" timeout="30" /&gt

By default the timeout is sliding, it expires after the configured amount of time has passed after the last request has been made.

It is possible to change the timeout to be fixed, expiring after the configured amount of time has passed after the user has logged in.

&lt forms slidingExpiration="false" /&gt

Other Checks