Session ID not random enough - ASP.NET

ryanulit picture ryanulit · Aug 1, 2011 · Viewed 11.7k times · Source

UPDATE

We eventually had a meeting with some programmers on the Acunetix team and they realized there may be a few bugs in their code that are causing this to be displayed in the scan as more of an issue than it actually may be. The general consensus was to ignore the scan results and use the out-of-the-box ASP.NET Session ID generation as it should be secure enough for our site.

@Vasile Bujac since your answer was the only one and mentioned using the ASP.NET standard solution I took that as the answer, but thanks everyone for your help.


We use Acunetix's Retina scanner at work to do security scans on our applications. It's telling us that our session ID's are not random enough and too predictable. I'm not exactly sure how ASP.NET generates the session ID by default (I thought it was GUID anyways?), but I went ahead and implemented the method of extending the SessionIDManager class and overriding the CreateSessionID and Validate methods to use a Guid as explained in this MSDN article.

While this makes it slightly more random, it is still not producing the "desired" effect according to Acunetix. I even added the regenerateExpiredSessionId="true" property to the web.config and that had no effect. I have a feeling that I may need to deliberately call Session.Abandon() to truly clear the session and get a new ID. Problem is then I have to call it right before a user logs in since it's the only fail-proof way to know the user is starting a new session. So I couldn't set anything in session until the next page is loaded with the way the Abandon method works, and that would mean an in-between page which isn't very ideal but would do the trick.

Has anyone ever experienced this or successfully implemented a fix?

Also, just an FYI, we don't use membership/forms authentication, we just create a new custom user class when someone logs in and save that in session for later use.


Report from Acunetix:

CWE-330 CAPEC-59 OWASP2007-A7

Description: Session tokens that exhibit low entropy ("randomness") are often susceptible to prediction attacks. Insecure tokens can be due to inadequate pseudo-random number generator, time-based values, static values, or values based on user attributes (username or user ID). This means that an attacker would be able to guess a valid session token after monitoring the application for a short period of time and gathering the session tokens it creates. If the attacker determines a valid session token for another user, then it may be possible to view, modify, or delete arbitrary users' data without having to guess the victim's username or password. Consequently, the ability to deduce valid session tokens enables the attacker to bypass login pages and obviate the need to brute force accounts. Additionally, static tokens can enable the attacker to target users even if the victim is not currently logged into the application. This increases the pool of victims which the attacker can target.

Session tokens should be created with a strong random number generator and gathered from a large pool of numbers. For example, an operating system's rand() function can usually be sufficient if it can produce 32-bit values that are a statistically uniform distribution. Poor session tokens are incremental, rely on the user's account ID, only use time stamps, or have other highly deterministic information. Other methods of protecting a session token's security are to always transmit them over SSL, automatically expire the token after a certain period of time, and explicitly expiring the token whenever a user logs out of the application.

Recommendations: If the session values exhibit strong randomness, but are chosen from a small pool of values, then the attacker has a better chance of simply guessing a valid token. A web application's session management can be improved by implementing several complementary techniques:

  • Make sure that the Token values are at least 32 bits in size, especially for applications with large numbers of concurrent users and high amounts of daily page requests.
  • The bit size of the source of the entropy (random values) is more important than the bit size of the actual session token. For example, an MD5 hash produces a 128 bit value. However, the MD5 hash of incremental values, a timestamp, or 8-bit random numbers are each insecure because the source of the random values can be easily predicted. Consequently, the 128 bit size does not represent an accurate measure of the session token. The minimum size of the entropy source is 32 bits, although larger pools (48 or 64 bits) may be necessary for sites with over 10,000 concurrent users per hour.
  • In most cases, application-generated tokens (e.g. ASP.NET_SessionId, ASPSESSIONID, JSPSESSIONID, PHPSESSIONID) provide sufficiently large random values to prevent session prediction attacks. The application should use these session management alogorithms unless a custom session mechanism has been thoroughly reviewed and tested.
  • Track user attributes associated with the session token with server-side objects to prevent user impersonation attacks. If the application does not strictly associate a user's session token with that user's profile information, then an attacker may be able to view arbitrary information by manipulating client-side values. For example, if the application sets a strong session token, but performs SQL queries based on a "UserId" cookie, then an attacker only needs to modify the "UserId" cookie to impersonate someone else. The application would be more secure if it associated the "UserId" value with the server-side session object because the attacker would not be able to modify the value.
  • Expire session tokens when the user logs out of the application or after a predetermined period of inactivity. We recommend using a 20 minute timeout for a session token, although this largely depends on the type of application and the expected usage.

Answer

Vasea picture Vasea · Aug 1, 2011

As I remember, ASP.NET session id generator gives good protection against session prediction. The session id has 24 characters using [a-z] chars and [0-5] digits (total of 32 possible chars which is 2^5) which gives a total of 2^(5*24) = 2^120 possible values. However you can implement a SessionIDManager to append some information (like user hostaddress, user-agent, a validation token using a HMAC algorithm) for even better protection - so that a session id comming from a different IP Address or different browser wouldn't pass the validation. If you have forms authentication implemented, this is not necessary since the authentication ticket already provides these kinds of protection.

If you want a better random session id you can use a RandomNumberGenerator such as RNGCryptoServiceProvider in your SessionIDManager and fill a bunch of bytes (say 32 which is 256 bits), then encode them using Base64

byte[] random = new byte[100];
//RNGCryptoServiceProvider is an implementation of a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random); // The array is now filled with cryptographically strong random bytes.
return Convert.ToBase64String(random) 

However, this article says that the max length of your session id is 80, so you must override the Validate method also in order for it to work.