고유 한 임의 문자열 생성


97

예를 들어 MSDN 라이브러리에서 생성되는 것과 같은 임의의 고유 문자열을 생성하고 싶습니다. ( Error Object ). 't9zk6eay'와 같은 문자열이 생성되어야합니다.


1
이것을 string randoms = Guid.NewGuid().ToString().Replace("-", string.Empty).Replace("+", string.Empty).Substring(0, 4);여기
shaijut

1
무언가가 완전히 독특하려면 시간, 위치 등과 같이 무작위가 아닌 무언가를 기반으로해야하므로 실제로 완전히 무작위 일 수는 없습니다. Guid는 무작위로 보일 수 있지만 실제로는 그렇지 않습니다. IMO의 유일한 희망은 모든 실제 목적을 위해 값이 고유 할 수 있도록 무작위적이고 복잡하게 만드는 것입니다 (즉, 충돌 가능성이 매우 낮습니다).
bytedev dec.

답변:


84

Guid를 사용하는 것은 꽤 좋은 방법이지만 예제와 같은 것을 얻으려면 아마도 Base64 문자열로 변환하고 싶을 것입니다.

    Guid g = Guid.NewGuid();
    string GuidString = Convert.ToBase64String(g.ToByteArray());
    GuidString = GuidString.Replace("=","");
    GuidString = GuidString.Replace("+","");

예제에 좀 더 가까워 지도록 "="및 "+"를 제거합니다. 그렇지 않으면 문자열 끝에 "=="가 표시되고 중간에 "+"가 표시됩니다. 다음은 출력 문자열의 예입니다.

"OZVV5TpP4U6wJthaCORZEQ"


15
/ 교체를 고려해야합니다.
Jason Kealey

20
Guid는 시퀀스를 추측 할 수 있으므로 안전한 임의의 문자열로 간주해서는 안됩니다. Guid는 무작위가 아닌 키 충돌을 피하기 위해 설계되었습니다. 스택 오버플로에 대한 Guid의 무작위성에 대한 좋은 토론이 있습니다.
Daniel Bradley

무엇의 명확하고 간단한 설명을 위해 Convert.ToBase64String약, 여기 좀 봐 .
jwaliszko 2014 년

2
guid를 base64로 변환하고 + 및 =를 대체하여 충돌 확률을 높일 수 있습니까?
Milan Aggarwal 2015 년

5
@SimonEjsing new Guid()"해킹"(시계 또는 내부 Windows 데이터 구조 조작)없이 사용할 때 충돌이 발생하는 애플리케이션을 실제로 작성할 수 있다면 맥주에 초대하겠습니다 . 원하는만큼 코어, 스레드, 동기화 기본 요소 등을 자유롭게 사용하십시오.
Lucero

175

2016 년 1 월 23 일 업데이트

이 답변이 유용하다고 생각되면 내가 게시 한 간단한 (~ 500 SLOC) 암호 생성 라이브러리에 관심이있을 수 있습니다 .

Install-Package MlkPwgen

그런 다음 아래 답변과 같이 임의의 문자열을 생성 할 수 있습니다.

var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);

라이브러리의 한 가지 장점은 코드가 더 잘 분해되어 문자열을 생성하는 것보다 더 안전한 임의성 사용할 수 있다는 것 입니다. 체크 아웃 프로젝트 사이트를 자세한 내용은.

원래 답변

아직 아무도 보안 코드를 제공하지 않았기 때문에 누군가 유용하다고 생각되면 다음을 게시합니다.

string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
    if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
    if (string.IsNullOrEmpty(allowedChars)) throw new ArgumentException("allowedChars may not be empty.");

    const int byteSize = 0x100;
    var allowedCharSet = new HashSet<char>(allowedChars).ToArray();
    if (byteSize < allowedCharSet.Length) throw new ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize));

    // Guid.NewGuid and System.Random are not particularly random. By using a
    // cryptographically-secure random number generator, the caller is always
    // protected, regardless of use.
    using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create()) {
        var result = new StringBuilder();
        var buf = new byte[128];
        while (result.Length < length) {
            rng.GetBytes(buf);
            for (var i = 0; i < buf.Length && result.Length < length; ++i) {
                // Divide the byte into allowedCharSet-sized groups. If the
                // random value falls into the last group and the last group is
                // too small to choose from the entire allowedCharSet, ignore
                // the value in order to avoid biasing the result.
                var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);
                if (outOfRangeStart <= buf[i]) continue;
                result.Append(allowedCharSet[buf[i] % allowedCharSet.Length]);
            }
        }
        return result.ToString();
    }
}

.NET Core에서 코드를 작동시키는 방법을 알려준 Ahmad에게 감사드립니다.


@Keltex 솔루션이 meh에 대해 제대로 작동하지 않았습니다 (몇 번 사용 후 동일한 문자열을 반환했습니다). 이 솔루션은 완벽한 :) 작동
JoanComasFdz

2
@LeeGrissom, 바이어 싱은 중요한 측면입니다. 예를 들어 알파벳이 255자를 포함하고 0-255 사이의 임의 값을 얻는다고 가정 해 보겠습니다. 링 버퍼에서 값 0과 255는 알파벳의 첫 번째 문자에 유리하게 결과를 왜곡하는 동일한 문자에 해당하며 덜 무작위입니다. 이 문제는 물론 응용 프로그램에 따라 다릅니다.
Oskar Sjöberg 2015 년

4
누가 겨냥한 .netcore: 교체 var rng = new RNGCryptoServiceProvider()와 함께var rng = RandomNumberGenerator.Create()
AMD

1
왜 'var outOfRangeStart = byteSize-(byteSize % allowedCharSet.Length);'를 계산합니까? 각 반복에 대해? '사용하기'전에 계산할 수 있습니다.
mtkachenko 2011

1
@BartCalixto 고정. 감사!
Michael Kropat

38

GUID는 임의의 숫자아니라는 점에주의해야 합니다 . 완전히 무작위로 예상되는 것을 생성하기위한 기초로 사용해서는 안됩니다 ( http://en.wikipedia.org/wiki/Globally_Unique_Identifier 참조 ).

WinAPI GUID 생성기의 암호 분석은 V4 GUID 시퀀스가 ​​의사 랜덤이므로 초기 상태가 주어지면 UuidCreate 함수에서 반환되는 다음 250,000 개의 GUID를 예측할 수 있음을 보여줍니다. 이것이 GUID가 암호화에서, 예를 들어 임의의 키로 사용되어서는 안되는 이유입니다.

대신 C # Random 메서드를 사용하십시오. 다음과 같은 것 ( 코드는 여기에 있음 ) :

private string RandomString(int size)
{
  StringBuilder builder = new StringBuilder();
  Random random = new Random();
  char ch ;
  for(int i=0; i<size; i++)
  {
    ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
    builder.Append(ch);
  }
  return builder.ToString();
}

GUID는 고유 한 항목 (예 : 데이터베이스의 고유 한 파일 이름 또는 키) 을 원할 경우 괜찮지 만 무작위로 원하는 항목 (예 : 암호 또는 암호화 키) 에는 적합하지 않습니다 . 따라서 응용 프로그램에 따라 다릅니다.

편집 . Microsoft는 Random도 그다지 좋지 않다고 말합니다 ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ) :

예를 들어 임의 암호를 만드는 데 적합한 암호화 보안 난수를 생성하려면 System.Security.Cryptography.RNGCryptoServiceProvider와 같은 System.Security.Cryptography.RandomNumberGenerator에서 파생 된 클래스를 사용합니다.


5
C # 랜덤 클래스는 특정 시드 번호에서 시작하는 클래식 랜덤 생성기이기 때문에 "무작위"가 아니며 모든 암호화 코드에 적합하지 않습니다. 동일한 시드는 또한 반환 된 동일한 일련의 숫자를 반환합니다. GUID 접근 방식은 이미 여기에서 훨씬 낫습니다 ( "무작위"가 아니라 "고유").
Lucero

3
@Lucero : 맞아요. Microsoft는 "예를 들어 임의 암호를 만드는 데 적합한 암호화 보안 난수를 생성하려면 System.Security.Cryptography.RNGCryptoServiceProvider와 같은 System.Security.Cryptography.RandomNumberGenerator에서 파생 된 클래스를 사용하십시오."라고 권장합니다.
Keltex 2009

글쎄, 질문은 이미 그가 (의사) 임의의 고유 문자열을 원하므로 암호화 요구 사항이 없거나 특정 무작위 배포를 따를 필요가 없다고 이미 명시했습니다. 따라서 GUID는 아마도 가장 쉬운 방법 일 것입니다.
Joey

1
"초기 상태가 주어지면 다음 250,000 개의 GUID를 예측할 수 있습니다"라는 진술은 본질적으로 모든 PRNG에 대한 진정한 진술처럼 보입니다. 또한 안전하지는 않지만 생성에 많은 가치가 있는지는 잘 모르겠습니다. 진정한 임의의 URL, 그게 OP의 목적이라면. ;)
ojrac

1
(어쨌든 +1-PRNG 교육이 중요합니다.)
ojrac

13

@Michael Kropats 솔루션을 단순화하고 LINQ-esque 버전을 만들었습니다.

string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
{       
    var outOfRange = byte.MaxValue + 1 - (byte.MaxValue + 1) % alphabet.Length;

    return string.Concat(
        Enumerable
            .Repeat(0, int.MaxValue)
            .Select(e => RandomByte())
            .Where(randomByte => randomByte < outOfRange)
            .Take(length)
            .Select(randomByte => alphabet[randomByte % alphabet.Length])
    );
}

byte RandomByte()
{
    using (var randomizationProvider = new RNGCryptoServiceProvider())
    {
        var randomBytes = new byte[1];
        randomizationProvider.GetBytes(randomBytes);
        return randomBytes.Single();
    }   
}

11

나는 그들이 실제로 무작위라고 생각하지 않지만 내 추측은 그것들이 해시라는 것입니다.

임의의 식별자가 필요할 때마다 일반적으로 GUID를 사용하여 "네이 키드"표현으로 변환합니다.

Guid.NewGuid().ToString("n");

@Keltex가 지적했듯이 WinAPI GUID 생성기의 암호 분석은 V4 GUID의 시퀀스가 ​​의사 랜덤이기 때문에 초기 상태가 주어지면 UuidCreate 함수에서 반환되는 다음 250,000 개의 GUID를 예측할 수 있음을 보여줍니다.
JoanComasFdz

4

Guid와 Time을 조합 해보십시오.

 var randomNumber = Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + DateTime.Now.Ticks;
     randomNumber = System.Text.RegularExpressions.Regex.Replace(randomNumber, "[^0-9a-zA-Z]+", "");

3

CrytpoGraphic 솔루션이없는 이유에 놀랐습니다. GUID는 고유하지만 암호화로 안전하지 않습니다 . 이 Dotnet Fiddle을 참조하십시오.

var bytes = new byte[40]; // byte size
using (var crypto = new RNGCryptoServiceProvider())
  crypto.GetBytes(bytes);

var base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);

Guid를 앞에 추가하려는 경우 :

var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);

더 깨끗한 영숫자 문자열 :

result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);

1

VB.net의 Michael Kropats 솔루션

Private Function RandomString(ByVal length As Integer, Optional ByVal allowedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") As String
    If length < 0 Then Throw New ArgumentOutOfRangeException("length", "length cannot be less than zero.")
    If String.IsNullOrEmpty(allowedChars) Then Throw New ArgumentException("allowedChars may not be empty.")


    Dim byteSize As Integer = 256
    Dim hash As HashSet(Of Char) = New HashSet(Of Char)(allowedChars)
    'Dim hash As HashSet(Of String) = New HashSet(Of String)(allowedChars)
    Dim allowedCharSet() = hash.ToArray

    If byteSize < allowedCharSet.Length Then Throw New ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize))


    ' Guid.NewGuid and System.Random are not particularly random. By using a
    ' cryptographically-secure random number generator, the caller is always
    ' protected, regardless of use.
    Dim rng = New System.Security.Cryptography.RNGCryptoServiceProvider()
    Dim result = New System.Text.StringBuilder()
    Dim buf = New Byte(128) {}
    While result.Length < length
        rng.GetBytes(buf)
        Dim i
        For i = 0 To buf.Length - 1 Step +1
            If result.Length >= length Then Exit For
            ' Divide the byte into allowedCharSet-sized groups. If the
            ' random value falls into the last group and the last group is
            ' too small to choose from the entire allowedCharSet, ignore
            ' the value in order to avoid biasing the result.
            Dim outOfRangeStart = byteSize - (byteSize Mod allowedCharSet.Length)
            If outOfRangeStart <= buf(i) Then
                Continue For
            End If
            result.Append(allowedCharSet(buf(i) Mod allowedCharSet.Length))
        Next
    End While
    Return result.ToString()
End Function

1

이것은 나를 위해 완벽하게 작동합니다.

    private string GeneratePasswordResetToken()
    {
        string token = Guid.NewGuid().ToString();
        var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(token);
        return Convert.ToBase64String(plainTextBytes);
    }

0

이것은 다양한 언어로 요청되었습니다. 여기에도 적용 할 수있는 암호에 대한 한 가지 질문 이 있습니다.

URL 단축에 문자열을 사용하려면 생성 된 ID가 이미 사용되었는지 여부를 확인하기 위해 Dictionary <> 또는 데이터베이스 검사가 필요합니다.


0

소문자 대문자 ([a-zA-Z0-9])가 있는 영숫자 문자열을 원하는 경우 빠르고 간단한 솔루션을 위해 Convert.ToBase64String ()을 사용할 수 있습니다.

고유성에 관해서는 생일 문제 를 확인 하여 충돌이 (A) 생성 된 문자열의 길이와 (B) 생성 된 문자열의 수가 주어질 가능성을 계산하십시오.

Random random = new Random();

int outputLength = 10;
int byteLength = (int)Math.Ceiling(3f / 4f * outputLength); // Base64 uses 4 characters for every 3 bytes of data; so in random bytes we need only 3/4 of the desired length
byte[] randomBytes = new byte[byteLength];
string output;
do
{
    random.NextBytes(randomBytes); // Fill bytes with random data
    output = Convert.ToBase64String(randomBytes); // Convert to base64
    output = output.Substring(0, outputLength); // Truncate any superfluous characters and/or padding
} while (output.Contains('/') || output.Contains('+')); // Repeat if we contain non-alphanumeric characters (~25% chance if length=10; ~50% chance if length=20; ~35% chance if length=32)

-1
  • Microsoft의 링크가 무작위로 생성되었는지 확실하지 않음
  • new Guid (). ToString () 살펴보기

4
Guid.NewGuid (). ToString ()-Guid에는 공개 생성자가 없습니다
cjk apr

3
당신의 말이 맞습니다. 검증없이 타이핑하고있었습니다. 나는 원래 포스터에 요점이 있다고 확신합니다.
Fabian Vilers

-1

GUID 해시 코드를 사용하여 고유 키 가져 오기

public static string GetUniqueKey(int length)
{
    string guidResult = string.Empty;

    while (guidResult.Length < length)
    {
        // Get the GUID.
        guidResult += Guid.NewGuid().ToString().GetHashCode().ToString("x");
    }

    // Make sure length is valid.
    if (length <= 0 || length > guidResult.Length)
        throw new ArgumentException("Length must be between 1 and " + guidResult.Length);

    // Return the first length bytes.
    return guidResult.Substring(0, length);
}

이것은 완벽하게 작동하지만 임의의 단어에는 고유 한 문자가 포함되어 있지 않습니다. 문자는 114e3 (2 개의 1), eaaea (3 개의 a와 2 개의 e), 60207 (2 개의 0) 등과 같이 반복됩니다. 영숫자 조합으로 문자를 반복하지 않고 임의의 문자열을 생성하는 방법은 무엇입니까?
vijay

@vijay : 16 진수를 출력하기 때문에 16 자, 16 자로 제한됩니다! 가능한 출력. 무작위 문자열은 그저 무작위입니다. 이론적으로 모든 a의 문자열 (aaaaaaaaaaaaaaa)을 얻을 수 있습니다. 매우 가능성이 없지만 다른 임의의 문자열보다 더 많지 않습니다. 왜 그 제약이 필요한지 잘 모르겠지만 문자열에 문자를 추가 할 때 HashSet <T>에서 문자를 팝하고 존재를 확인한 다음 문자열에 추가하거나 그에 따라 건너 뜁니다.
Chris Doggett
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.