OWASP O2 Platform Blog

Humm … .NET Random class is not Thread Safe?

I was doing some stress testing on a app (using O2), and suddenly my test data was all ‘aaaaaaa’ (vs random letters). After some debbuging it seems that that problem is that the .NET Random class is NOT thread safe. This as quite a lot of security implications and is defenitely not what I was expecting (see references at the bottom for links that confirm this behaviour).

Basically what happens is that if a random object is accessed from multiple threads, eventually it gets corrupted and starts returning 0 (zero).

For example, O2 has a couple helper classes to return random values:

//return 10.randomLetters();      // EXtjJkudEI
//return 20.randomLetters();      // rkjdQCFBzhCASriyhpzG
//return 10.randomNumbers();    // 1440637687
//return 20.randomNumbers();    // 70412467593222068252
//return 10.randomString();        // m8}XEYhy#G
//return 20.randomString();        // \('VVx%0f0,63>Ar35'!
//return 10.random();            // 4
//return 1000.random();            // 831
//return 100000.random();        // 72394
return 1000000.random();        // 261239

The problem happened that on my multi-thread tests sudently the 10.randomLetters() method returned ‘aaaaaaaaaa’ vs returning a random string with 10 letters.

If you look at the O2 API file with those Extension Methods (in Crypto_ExtensionMethods.cs) you see can how they work. The scenario where you will get all ‘a’ in this method will happen when  random.NextDouble() returns 0. As I was coding this API I have to say that I never expected this to happen (i.e. even assuming that there could be some colisions, I never expected the Random class to completely stop working!)

To find this issue, I first isolated the use of the randomLetters() method using this script:

Action startLoop =    
        var loop  = 10;
        var count = 100000;
        for(var i = 0 ; i < loop; i++)
            var startTime = DateTime.Now;
            for(var j =0 ; j < count ; j++)
            var timeSpan = DateTime.Now - startTime;
            "[{5}/{6}] added {0} in {1}:{2} : {3} : {4}".info(count,timeSpan.Seconds, timeSpan.Milliseconds , 2.randomLetters(), 10.randomLetters(), i, loop);
            if (2.randomLetters() == "aa")
O2Thread.mtaThread(()=> startLoop());   
O2Thread.mtaThread(()=> startLoop());    
return 15.randomLetters();

This is the execution result:

And in order to find out the exact root cause (and to make sure it was not a problem with my code), I wrote the following PoC to replicate the problem using new instances of the the Random class :

var randomObject = new Random((int)DateTime.Now.Ticks);  
var sync = new ManualResetEvent(false);</pre>

var threadCount = 5;
var innerLoopMax = 400000;
var totalCounter = 0;       

Action<int> startLoop =    
    (id)=> {
                "Running Loop for: {0}".info(id);
                for(var j =0 ; j < innerLoopMax ; j++)           
                    if (randomObject.Next() == 0 )
                        "PROB!! : {0} : {1}".error(j, totalCounter);
                "done: {0}".info(id);                       

for(var i = 0 ; i < threadCount ; i++)            
    O2Thread.mtaThread(()=> startLoop(i));    


//using System.Threading

run #1:

run #2


run #3



It seems that others have noted this, and the answer eventually comes down to ‘the Random is not Thread Safe …. just live with it”:

This issue could introduce quite suble security vulnerabilites, specially in multithreaded environments like Asp.Net

July 16, 2011 - Posted by | .NET

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: