Creating a unique * and * random URL in C #

My ultimate goal is to create a URL that is unique and cannot be predicted / predicted. The purpose of this URL is to allow users to perform operations such as checking their email address and password reset. These URLs expire within the set time (currently set to 24 hours).

I originally used Guid for this purpose, but now I understand that it is somewhere between โ€œjust fineโ€ and โ€œvery insecure,โ€ depending on who you are listening to. So, I thought I would strengthen my code a bit just in case. At first it seemed to me that I was just using Guid , but I created it from random bytes, and not from 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 donโ€™t quite understand what exactly happens when you use new Guid(bytes) instead of Guid.NewGuid() , but I think that this whole method creates an array of random bytes and stores it in the Guid data structure. In other words, it is no longer guaranteed to be unique; it is guaranteed to be random.

Since my URLs must be both unique and random, this doesn't seem like a solid solution. Now I think that I should base my URLs on a combination as a unique identifier (which can be a Guid , or, if available, an automatically incrementing database id) and a random sequence generated from RNGCryptoServiceProvider .

Questions

What is the best way to create a validation / password URL - reset, which is guaranteed to be unique and extremely difficult / impossible to predict / guess?

  • Should I just create my URL by combining a unique string with a random string?

  • Is there a built-in way in the .NET Framework to easily create a unique and random (unpredictable) sequence that can be used for URLs?

  • If not, is there an open source open source solution?

Update

If anyone has a similar requirement, I am 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.

+6
source share
5 answers

A Guid is not designed to be safe. Guid creation standards do not claim how safe it is or how easy / difficult it is to guess. He simply declares his uniqueness.

If you try to protect your system with Guid, then you will not have a secure system.

+5
source

[Edit: I missed the call to RNGCryptoServiceProvider above. Sorry.]

The problem with RNG generators such as RNGCryptoServiceProvider for your case is that they do not guarantee uniqueness. Guides, as you know, are statistically unlikely to be unique, but do not guarantee them. The only real way to guarantee uniqueness and randomness is to generate a GUID just like you, then put it in a searchable repository, such as a database table. Whenever you create a new value, check that it is not already present. If so, drop it and create a new value.

0
source

You can generate 128-bit "random" unique numbers by running the counter through the AES counter, to which a random key is entered. As long as the same key is used, it will never repeat any output.

 static byte[] AESCounter(byte[] key, ulong counter) { byte[] InputBlock = new byte[16]; InputBlock[0] = (byte)(counter & 0xffL); InputBlock[1] = (byte)((counter & 0xff00L) >> 8); InputBlock[2] = (byte)((counter & 0xff0000L) >> 16); InputBlock[3] = (byte)((counter & 0xff000000L) >> 24); InputBlock[4] = (byte)((counter & 0xff00000000L) >> 32); InputBlock[5] = (byte)((counter & 0xff0000000000L) >> 40); InputBlock[6] = (byte)((counter & 0xff000000000000L) >> 48); InputBlock[7] = (byte)((counter & 0xff00000000000000L) >> 54); using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider()) { AES.Key = key; AES.Mode = CipherMode.ECB; AES.Padding = PaddingMode.None; using (ICryptoTransform Encryptor = AES.CreateEncryptor()) { return Encryptor.TransformFinalBlock(InputBlock, 0, 16); } } } 
0
source

Get md5 of all user login credentials and associate it with the director created by Guid.NewGuid (). ToString () and use it in your url, it should work fine.

0
source

Create a table in the database using linkID and the Datesent column, to generate a send insert DateTime.Now link to the table and return linkId, set linkID as the querystring parameter to activLink.

When loading the activation page, extract the linkId and use it to call the stored procedure, which will return the date when passing the corresponding linkId as a parameter, when you get the date back, you can add how long you want the link to stay active with .AddDays() / .AddMonths (these are C # methods for datetime). Then compare the date you returned with today's date. If it went through a few days or months, it will display an error message or continue to view the contents of the page.

I try to save the contents of the page in the panel and set it visible = "false" , and then make the panel visible="true" if the date is still within the range.

0
source

Source: https://habr.com/ru/post/924414/


All Articles