My ultimate goal is to create a URL that is unique and cannot be guessed/predicted. The purpose of this URL is to allow users to perform operations like verifying their email address and resetting their password. These URLs would expire within a set amount of time (currently set to 24 hours).
I was originally using a Guid
for this purpose, but I now understand this to be somewhere between "just fine" and "very insecure", depending on which expert you listen to. So, I thought I'd beef up my code a little bit, just in case. At first I thought I'd just stick with using a Guid
, but generate it from random bytes rather than the Guid.NewGuid()
factory method. Here is the method I came up with:
public static Guid GetRandomGuid()
{
var bytes = new byte[16];
var generator = new RNGCryptoServiceProvider();
generator.GetBytes(bytes);
return new Guid(bytes);
}
I'm not quite clear on what exactly happens when you use new Guid(bytes)
instead of Guid.NewGuid()
, but I think all this method does is generate a random byte array and store it in a Guid
data structure. In other words, it's no longer guaranteed to be unique, it's only guaranteed to be random.
Since my URLs need to be both unique and random, this does not seem like a solid solution. I'm now thinking, I should base my URLs on a combination of both a unique ID (which could be a Guid
or, if available, a database auto-incremented id) and a random sequence generated from RNGCryptoServiceProvider
.
Questions
What's the best way to generate a verification/password-reset URL that is both guaranteed unique and extremely difficult/impossible to predict/guess?
Should I simply construct my URL by concatenating a unique string with a random string?
Does the .NET Framework have a built-in way to easily generate a unique and random (unpredictable) sequence that can be used for URLs?
If not, is there a good solution available open source?
Update
In case anyone has a similar requirement, I'm currently using the following method:
public static string GenerateUniqueRandomToken(int uniqueId)
// generates a unique, random, and alphanumeric token
{
const string availableChars =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
using (var generator = new RNGCryptoServiceProvider())
{
var bytes = new byte[16];
generator.GetBytes(bytes);
var chars = bytes
.Select(b => availableChars[b % availableChars.Length]);
var token = new string(chars.ToArray());
return uniqueId + token;
}
}
Please comment if you see any problems with this.
A Guid is not meant to be a security feature. The standards for creating a Guid make no claims about how secure it is, or how easy/hard it is to guess. It simply makes a claim about it's uniqueness.
If you attempt to secure your system by using a Guid then you will not have a secure system.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With