Когда пользователь на нашем сайте теряет свой пароль и переходит на страницу «Утерянный пароль», нам необходимо дать ему новый временный пароль. Я действительно не возражаю, насколько это случайный случай, или если он соответствует всем «необходимым» правилам надежных паролей, все, что я хочу сделать, это дать им пароль, который они могут изменить позже.
Приложение представляет собой веб-приложение, написанное на C#. так что я подумал о том, чтобы быть злым и пойти по легкому пути использования части гида. т.е.
Guid.NewGuid().ToString("d").Substring(1,8)
Предложения? мысли?
Я добавил ответ, который использует KeePass в качестве генератора паролей, и из множества представленных опций я также включил опцию для исключения похожих символов, как упоминалось @ stian.net.





Это намного больше, но я думаю, что это выглядит немного более исчерпывающим: http://www.obviex.com/Samples/Password.aspx
///////////////////////////////////////////////////////////////////////////////
// SAMPLE: Generates random password, which complies with the strong password
// rules and does not contain ambiguous characters.
//
// To run this sample, create a new Visual C# project using the Console
// Application template and replace the contents of the Class1.cs file with
// the code below.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//
// Copyright (C) 2004 Obviex(TM). All rights reserved.
//
using System;
using System.Security.Cryptography;
/// <summary>
/// This class can generate random passwords, which do not include ambiguous
/// characters, such as I, l, and 1. The generated password will be made of
/// 7-bit ASCII symbols. Every four characters will include one lower case
/// character, one upper case character, one number, and one special symbol
/// (such as '%') in a random order. The password will always start with an
/// alpha-numeric character; it will not start with a special symbol (we do
/// this because some back-end systems do not like certain special
/// characters in the first position).
/// </summary>
public class RandomPassword
{
// Define default min and max password lengths.
private static int DEFAULT_MIN_PASSWORD_LENGTH = 8;
private static int DEFAULT_MAX_PASSWORD_LENGTH = 10;
// Define supported password characters divided into groups.
// You can add (or remove) characters to (from) these groups.
private static string PASSWORD_CHARS_LCASE = "abcdefgijkmnopqrstwxyz";
private static string PASSWORD_CHARS_UCASE = "ABCDEFGHJKLMNPQRSTWXYZ";
private static string PASSWORD_CHARS_NUMERIC= "23456789";
private static string PASSWORD_CHARS_SPECIAL= "*$-+?_&=!%{}/";
/// <summary>
/// Generates a random password.
/// </summary>
/// <returns>
/// Randomly generated password.
/// </returns>
/// <remarks>
/// The length of the generated password will be determined at
/// random. It will be no shorter than the minimum default and
/// no longer than maximum default.
/// </remarks>
public static string Generate()
{
return Generate(DEFAULT_MIN_PASSWORD_LENGTH,
DEFAULT_MAX_PASSWORD_LENGTH);
}
/// <summary>
/// Generates a random password of the exact length.
/// </summary>
/// <param name = "length">
/// Exact password length.
/// </param>
/// <returns>
/// Randomly generated password.
/// </returns>
public static string Generate(int length)
{
return Generate(length, length);
}
/// <summary>
/// Generates a random password.
/// </summary>
/// <param name = "minLength">
/// Minimum password length.
/// </param>
/// <param name = "maxLength">
/// Maximum password length.
/// </param>
/// <returns>
/// Randomly generated password.
/// </returns>
/// <remarks>
/// The length of the generated password will be determined at
/// random and it will fall with the range determined by the
/// function parameters.
/// </remarks>
public static string Generate(int minLength,
int maxLength)
{
// Make sure that input parameters are valid.
if (minLength <= 0 || maxLength <= 0 || minLength > maxLength)
return null;
// Create a local array containing supported password characters
// grouped by types. You can remove character groups from this
// array, but doing so will weaken the password strength.
char[][] charGroups = new char[][]
{
PASSWORD_CHARS_LCASE.ToCharArray(),
PASSWORD_CHARS_UCASE.ToCharArray(),
PASSWORD_CHARS_NUMERIC.ToCharArray(),
PASSWORD_CHARS_SPECIAL.ToCharArray()
};
// Use this array to track the number of unused characters in each
// character group.
int[] charsLeftInGroup = new int[charGroups.Length];
// Initially, all characters in each group are not used.
for (int i=0; i<charsLeftInGroup.Length; i++)
charsLeftInGroup[i] = charGroups[i].Length;
// Use this array to track (iterate through) unused character groups.
int[] leftGroupsOrder = new int[charGroups.Length];
// Initially, all character groups are not used.
for (int i=0; i<leftGroupsOrder.Length; i++)
leftGroupsOrder[i] = i;
// Because we cannot use the default randomizer, which is based on the
// current time (it will produce the same "random" number within a
// second), we will use a random number generator to seed the
// randomizer.
// Use a 4-byte array to fill it with random bytes and convert it then
// to an integer value.
byte[] randomBytes = new byte[4];
// Generate 4 random bytes.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
// Convert 4 bytes into a 32-bit integer value.
int seed = BitConverter.ToInt32(randomBytes, 0);
// Now, this is real randomization.
Random random = new Random(seed);
// This array will hold password characters.
char[] password = null;
// Allocate appropriate memory for the password.
if (minLength < maxLength)
password = new char[random.Next(minLength, maxLength+1)];
else
password = new char[minLength];
// Index of the next character to be added to password.
int nextCharIdx;
// Index of the next character group to be processed.
int nextGroupIdx;
// Index which will be used to track not processed character groups.
int nextLeftGroupsOrderIdx;
// Index of the last non-processed character in a group.
int lastCharIdx;
// Index of the last non-processed group.
int lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;
// Generate password characters one at a time.
for (int i=0; i<password.Length; i++)
{
// If only one character group remained unprocessed, process it;
// otherwise, pick a random character group from the unprocessed
// group list. To allow a special character to appear in the
// first position, increment the second parameter of the Next
// function call by one, i.e. lastLeftGroupsOrderIdx + 1.
if (lastLeftGroupsOrderIdx == 0)
nextLeftGroupsOrderIdx = 0;
else
nextLeftGroupsOrderIdx = random.Next(0,
lastLeftGroupsOrderIdx);
// Get the actual index of the character group, from which we will
// pick the next character.
nextGroupIdx = leftGroupsOrder[nextLeftGroupsOrderIdx];
// Get the index of the last unprocessed characters in this group.
lastCharIdx = charsLeftInGroup[nextGroupIdx] - 1;
// If only one unprocessed character is left, pick it; otherwise,
// get a random character from the unused character list.
if (lastCharIdx == 0)
nextCharIdx = 0;
else
nextCharIdx = random.Next(0, lastCharIdx+1);
// Add this character to the password.
password[i] = charGroups[nextGroupIdx][nextCharIdx];
// If we processed the last character in this group, start over.
if (lastCharIdx == 0)
charsLeftInGroup[nextGroupIdx] =
charGroups[nextGroupIdx].Length;
// There are more unprocessed characters left.
else
{
// Swap processed character with the last unprocessed character
// so that we don't pick it until we process all characters in
// this group.
if (lastCharIdx != nextCharIdx)
{
char temp = charGroups[nextGroupIdx][lastCharIdx];
charGroups[nextGroupIdx][lastCharIdx] =
charGroups[nextGroupIdx][nextCharIdx];
charGroups[nextGroupIdx][nextCharIdx] = temp;
}
// Decrement the number of unprocessed characters in
// this group.
charsLeftInGroup[nextGroupIdx]--;
}
// If we processed the last group, start all over.
if (lastLeftGroupsOrderIdx == 0)
lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;
// There are more unprocessed groups left.
else
{
// Swap processed group with the last unprocessed group
// so that we don't pick it until we process all groups.
if (lastLeftGroupsOrderIdx != nextLeftGroupsOrderIdx)
{
int temp = leftGroupsOrder[lastLeftGroupsOrderIdx];
leftGroupsOrder[lastLeftGroupsOrderIdx] =
leftGroupsOrder[nextLeftGroupsOrderIdx];
leftGroupsOrder[nextLeftGroupsOrderIdx] = temp;
}
// Decrement the number of unprocessed groups.
lastLeftGroupsOrderIdx--;
}
}
// Convert password characters into a string and return the result.
return new string(password);
}
}
/// <summary>
/// Illustrates the use of the RandomPassword class.
/// </summary>
public class RandomPasswordTest
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// Print 100 randomly generated passwords (8-to-10 char long).
for (int i=0; i<100; i++)
Console.WriteLine(RandomPassword.Generate(8, 10));
}
}
//
// END OF FILE
///////////////////////////////////////////////////////////////////////////////
Оказывается, фреймворк поддерживает это. Так что я скорее принимаю этот ответ!
Создание всего 2 ^ 31 различных паролей даже при больших размерах вывода - это немного неважно. Может быть достаточно против онлайн-атак, но, конечно, слишком мало для офлайн-атак. => Я бы не рекомендовал это.
Это по-прежнему хороший ответ, потому что «встроенная» поддержка - это действительно членство, а что, если вы решили не использовать членство в ASP.NET? Он по-прежнему работает, поскольку зависимость - это System.Web.dll, но это немного неудобно, потому что метод не является самодостаточным. @GEOCHET: Спасибо, что разместили эту альтернативу.
public string CreatePassword(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
res.Append(valid[rnd.Next(valid.Length)]);
}
return res.ToString();
}
Это дает хорошее преимущество, заключающееся в возможности выбора из списка доступных символов для сгенерированного пароля (например, только цифры, только прописные буквы или только строчные буквы и т. д.)
этот метод (база 62) превосходит GUID (база 16) по прочности: шестнадцатеричная строка из 8 знаков эквивалентна буквенно-цифровой строке из 4-5 знаков
Random не является криптографически безопасным; System.Security.Cryptography.RNGCryptoServiceProvider - лучший выбор.
Это будет генерировать один и тот же пароль каждый раз при вызове метода, поскольку каждый раз создается экземпляр класса Random. Это можно сделать безопасным, убрав Random из этого метода и повторно используя экземпляр.
Нет, не пойдет. Если только два человека не решили сменить пароли в одно и то же время.
@anaximander Как бы вы заменили Random на RNGCryptoServiceProvider?
См. мой ответ для простой реализации. RNGCryptoServiceProvider генерирует байты данных с высокой энтропией, поэтому вы можете просто преобразовать этот вывод в символы. Если хотите, вы можете удалить любые не буквенно-цифровые символы.
Если мне нужна строка, содержащая числа, буквы и заглавные буквы, и если я сгенерирую короткую строку (например, длиной 8 символов), все еще есть шанс, что она даст результат, который не соответствует моим требованиям.
У @Wish есть очень важный момент. Используйте эту реализацию НЕТ! Это не сработает на любой машине Windows с принудительной политикой паролей!
цитата из вопроса: неважно, "соответствует ли он всем" необходимым "правилам надежных паролей ... спасибо, что проголосовали против этого ответа
Это действительно создавало для меня один и тот же пароль много раз; только 150 различных значений из 500.
только из-за того, как вы это тестируете: docs.microsoft.com/en-us/dotnet/api/…
Для такого рода паролей я обычно использую систему, которая может генерировать более простые «используемые» пароли. Короткие, часто состоящие из произносимых фрагментов и нескольких чисел, без двусмысленности между символами (это 0 или O? A 1 или I?). Что-то вроде
string[] words = { 'bur', 'ler', 'meh', 'ree' };
string word = "";
Random rnd = new Random();
for (i = 0; i < 3; i++)
word += words[rnd.Next(words.length)]
int numbCount = rnd.Next(4);
for (i = 0; i < numbCount; i++)
word += (2 + rnd.Next(7)).ToString();
return word;
(Набирается прямо в браузере, поэтому используйте только в качестве руководства. Кроме того, добавьте больше слов).
Мне нравится создавать пароли, как и программные ключи. Вы должны выбирать из множества символов, которые следуют хорошей практике. Возьмите то, с чем @ Radu094 ответил, и измените его, чтобы следовать хорошей практике. Не помещайте каждую букву в массив символов. Некоторые буквы сложнее сказать или понять по телефону.
Вам также следует подумать об использовании контрольной суммы для сгенерированного пароля, чтобы убедиться, что он был сгенерирован вами. Хороший способ добиться этого - использовать Алгоритм LUHN.
Всегда есть System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters).
Не знал, что у Framework есть такой метод! Потрясающие! Заменю на это мой текущий код!
Я нашел его, потратив почти день на совершенствование собственного кода pw gen. Представьте, как я себя чувствовал;)
AFAIK этот метод не генерирует пароль, соответствующий политике паролей в домене, поэтому он не подходит для каждого использования.
Это работает, даже если вы не зависели от членства в ASP.NET, но если вы решили использовать другого поставщика, это становится неудобным выбором, поскольку он частично зависит от другой конфигурации членства.
Основная проблема с этим решением заключается в том, что вы не можете управлять набором символов, поэтому вы не можете устранить визуально неоднозначные символы (0oOl1i! |), Которые могут быть действительно важны на практике.
Любой эквивалентный API для MVC 5.
Еще одна странность заключается в том, что даже когда вы устанавливаете второй параметр (numberOfNonAlphanumericCharacters) на 0, вы получаете пароль, содержащий круглые скобки и другие знаки препинания. Для меня буквенно-цифровой означает [a-zA-Z0-9].
@ JennyO'Reilly Вы правы, более информативное имя параметра было бы minimumNumberOfAlphaNumericCharacters, но это немного длинновато.
Что-нибудь для ASP.NET Core?
Это работает в .Net Core или мог, но не всегда генерирует цифры, поэтому не работает ..
@Lonefish см. Мой комментарий от 06.02.2016 выше, вероятно, та же проблема.
Не совсем, я сгенерировал пароль длиной 15 и минимум 5 не буквенно-цифровых символов. Однако при первом проходе (шансы, вероятно, довольно малы, но все же) он не сгенерировал пароль с номером в нем. Так что это не удалось в Identity, так как ему нужны цифры, буквы и не буквенно-цифровые. Исправлено путем добавления числа, буквы и нечисловых символов к сгенерированному паролю, поскольку это просто заполнитель, пока человек не выберет реальный пароль (обязательно).
А как насчет Core? Я даже не могу скомпилировать, если напишу это, и ничего не работает с использованием состояний
Хотя OP заявляет, что он использует это в веб-приложении, я думаю, что это создает ненужную зависимость от библиотеки, которую можно заменить менее чем 10 строками кода.
@Lonefish Это точно не будет работать в .NET Core: github.com/PowerShell/PowerShell/issues/5352
вы заслуживаете двух трофеев, если пропустите первый. Молодец
Отличный ответ для .NET Core: stackoverflow.com/a/38997554/7053420
Мне не нравятся пароли, которые создает Membership.GeneratePassword (), поскольку они слишком уродливы и содержат слишком много специальных символов.
Этот код генерирует не слишком уродливый пароль из 10 цифр.
string password = Guid.NewGuid().ToString("N").ToLower()
.Replace("1", "").Replace("o", "").Replace("0","")
.Substring(0,10);
Конечно, я мог бы использовать Regex для всех замен, но это более читаемый и поддерживаемый IMO.
GUID не следует использовать как крипто-ГПСЧ
Если вы собираетесь использовать этот метод, вы можете использовать .ToString («N»), и вам не придется заменять «-». Также нет необходимости заменять «l», поскольку это не шестнадцатеричная цифра.
Полностью понимаю, почему вы это сделали. Мне просто нужен был недолговечный (менее суток) пароль, который не должен был быть слишком уникальным для каждого пользователя. Удаление единиц и нулей - отличный способ избавиться от путаницы. Я также просто перевел свой на верхний регистр, а затем сократил длину до 6. Как и предложение «N». Спасибо!
Я создал этот метод, аналогичный доступному в провайдере членства. Это полезно, если вы не хотите добавлять веб-ссылку в некоторые приложения.
Отлично работает.
public static string GeneratePassword(int Length, int NonAlphaNumericChars)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
Random rd = new Random();
if (NonAlphaNumericChars > Length || Length <= 0 || NonAlphaNumericChars < 0)
throw new ArgumentOutOfRangeException();
char[] pass = new char[Length];
int[] pos = new int[Length];
int i = 0, j = 0, temp = 0;
bool flag = false;
//Random the position values of the pos array for the string Pass
while (i < Length - 1)
{
j = 0;
flag = false;
temp = rd.Next(0, Length);
for (j = 0; j < Length; j++)
if (temp == pos[j])
{
flag = true;
j = Length;
}
if (!flag)
{
pos[i] = temp;
i++;
}
}
//Random the AlphaNumericChars
for (i = 0; i < Length - NonAlphaNumericChars; i++)
pass[i] = allowedChars[rd.Next(0, allowedChars.Length)];
//Random the NonAlphaNumericChars
for (i = Length - NonAlphaNumericChars; i < Length; i++)
pass[i] = allowedNonAlphaNum[rd.Next(0, allowedNonAlphaNum.Length)];
//Set the sorted array values by the pos array for the rigth posistion
char[] sorted = new char[Length];
for (i = 0; i < Length; i++)
sorted[i] = pass[pos[i]];
string Pass = new String(sorted);
return Pass;
}
Не используйте System.Random для важных для безопасности вещей, таких как пароли. Используйте RNGCryptoServiceProvider
Я знаю, что это старый поток, но у меня есть довольно простое решение для кого-то. Легко реализовать, легко понять и легко проверить.
Учтите следующее требование:
I need a random password to be generated which has at least 2 lower-case letters, 2 upper-case letters and 2 numbers. The password must also be a minimum of 8 characters in length.
Следующее регулярное выражение может подтвердить этот случай:
^(?=\b\w*[a-z].*[a-z]\w*\b)(?=\b\w*[A-Z].*[A-Z]\w*\b)(?=\b\w*[0-9].*[0-9]\w*\b)[a-zA-Z0-9]{8,}$
Это выходит за рамки этого вопроса, но регулярное выражение основано на взгляд вперед / назад и смотреть по сторонам.
Следующий код создаст случайный набор символов, соответствующих этому требованию:
public static string GeneratePassword(int lowercase, int uppercase, int numerics) {
string lowers = "abcdefghijklmnopqrstuvwxyz";
string uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string number = "0123456789";
Random random = new Random();
string generated = "!";
for (int i = 1; i <= lowercase; i++)
generated = generated.Insert(
random.Next(generated.Length),
lowers[random.Next(lowers.Length - 1)].ToString()
);
for (int i = 1; i <= uppercase; i++)
generated = generated.Insert(
random.Next(generated.Length),
uppers[random.Next(uppers.Length - 1)].ToString()
);
for (int i = 1; i <= numerics; i++)
generated = generated.Insert(
random.Next(generated.Length),
number[random.Next(number.Length - 1)].ToString()
);
return generated.Replace("!", string.Empty);
}
Чтобы выполнить указанное выше требование, просто позвоните по следующему номеру:
String randomPassword = GeneratePassword(3, 3, 3);
Код начинается с недопустимого символа ("!"), чтобы строка имела длину, в которую можно вставить новые символы.
Затем он выполняет цикл от 1 до # требуемых символов нижнего регистра и на каждой итерации захватывает случайный элемент из списка нижнего регистра и вставляет его в случайное место в строке.
Затем цикл повторяется для прописных букв и для цифр.
Это возвращает вам строки длиной = lowercase + uppercase + numerics, в которые в случайном порядке помещены строчные, прописные и числовые символы нужного вам количества.
Не используйте System.Random для важных для безопасности вещей, таких как пароли. Используйте RNGCryptoServiceProvider
lowers[random.Next(lowers.Length - 1)].ToString() Этот код никогда не будет генерировать букву «z». random.Next производит целые числа меньше, чем предоставленное число, поэтому вы не должны вычитать это лишнее число из длины.
Вставьте Timer: timer1, 2 кнопки: button1, button2, 1 textBox: textBox1 и comboBox: comboBox1. Убедитесь, что вы заявили:
int count = 0;
Исходный код:
private void button1_Click(object sender, EventArgs e)
{
// This clears the textBox, resets the count, and starts the timer
count = 0;
textBox1.Clear();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
// This generates the password, and types it in the textBox
count += 1;
string possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
string psw = "";
Random rnd = new Random { };
psw += possible[rnd.Next(possible.Length)];
textBox1.Text += psw;
if (count == (comboBox1.SelectedIndex + 1))
{
timer1.Stop();
}
}
private void Form1_Load(object sender, EventArgs e)
{
// This adds password lengths to the comboBox to choose from.
comboBox1.Items.Add("1");
comboBox1.Items.Add("2");
comboBox1.Items.Add("3");
comboBox1.Items.Add("4");
comboBox1.Items.Add("5");
comboBox1.Items.Add("6");
comboBox1.Items.Add("7");
comboBox1.Items.Add("8");
comboBox1.Items.Add("9");
comboBox1.Items.Add("10");
comboBox1.Items.Add("11");
comboBox1.Items.Add("12");
}
private void button2_click(object sender, EventArgs e)
{
// This encrypts the password
tochar = textBox1.Text;
textBox1.Clear();
char[] carray = tochar.ToCharArray();
for (int i = 0; i < carray.Length; i++)
{
int num = Convert.ToInt32(carray[i]) + 10;
string cvrt = Convert.ToChar(num).ToString();
textBox1.Text += cvrt;
}
}
Не используйте System.Random для безопасности.
Основные цели моего кода:
Первое свойство достигается за счет взятия 64-битного значения по модулю размера алфавита. Для маленьких алфавитов (таких как 62 символа из вопроса) это приводит к незначительной систематической ошибке. Второе и третье свойство достигаются за счет использования RNGCryptoServiceProvider вместо System.Random.
using System;
using System.Security.Cryptography;
public static string GetRandomAlphanumericString(int length)
{
const string alphanumericCharacters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789";
return GetRandomString(length, alphanumericCharacters);
}
public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
if (length < 0)
throw new ArgumentException("length must not be negative", "length");
if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
throw new ArgumentException("length is too big", "length");
if (characterSet == null)
throw new ArgumentNullException("characterSet");
var characterArray = characterSet.Distinct().ToArray();
if (characterArray.Length == 0)
throw new ArgumentException("characterSet must not be empty", "characterSet");
var bytes = new byte[length * 8];
new RNGCryptoServiceProvider().GetBytes(bytes);
var result = new char[length];
for (int i = 0; i < length; i++)
{
ulong value = BitConverter.ToUInt64(bytes, i * 8);
result[i] = characterArray[value % (uint)characterArray.Length];
}
return new string(result);
}
(Это копия моего ответа на Как я могу сгенерировать случайные 8-символьные буквенно-цифровые строки на C#?)
Если UInt64.MaxValue не делится равномерно на characterArray.Length, тогда случайно выбранные символы не будут равномерно распределены (хотя это будет очень незначительным эффектом).
@JeffWalkerCodeRanger Вот почему я сказал незначительную предвзятость, а не отсутствие предвзятости. Даже с петабайтом вывода у вас есть менее 1%, чтобы отличить его от совершенно беспристрастного строкового генератора. Дополнительная сложность идеального несмещения явно не стоит здесь теоретического выигрыша в случайности.
Для тех, кто использует .NET Core, замените «новый RNGCryptoServiceProvider (). GetBytes (bytes);» с "System.Security.Cryptography.RandomNumberGenerator.Create () .GetBytes (байты);"
Это коротко, и мне он отлично подходит.
public static string GenerateRandomCode(int length)
{
Random rdm = new Random();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; i++)
sb.Append(Convert.ToChar(rdm.Next(101,132)));
return sb.ToString();
}
Это может «работать», но это, конечно, небезопасно. Пароли должны быть надежными.
Я думаю, что случайные пароли - это временные пароли. Не понимаю, почему они должны быть безопасными, и даже если они это сделают, вы можете добавлять числа и специальные символы в диапазон.
Добавление чисел и специальных символов не улучшает безопасность, если вы генерируете их с помощью предсказуемого ГПСЧ. Если вы знаете, когда был сгенерирован пароль, вы можете сузить его до нескольких кандидатов.
Я создал этот класс, который использует RNGCryptoServiceProvider, и он гибкий. Пример:
var generator = new PasswordGenerator(minimumLengthPassword: 8,
maximumLengthPassword: 15,
minimumUpperCaseChars: 2,
minimumNumericChars: 3,
minimumSpecialChars: 2);
string password = generator.Generate();
Отлично, какая у этого класса лицензия? Могу я его использовать?
Используйте его так, как хотите!
public string GenerateToken(int length)
{
using (RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider())
{
byte[] tokenBuffer = new byte[length];
cryptRNG.GetBytes(tokenBuffer);
return Convert.ToBase64String(tokenBuffer);
}
}
(У вас также может быть класс, в котором находится этот метод, реализующий IDisposable, содержащий ссылку на RNGCryptoServiceProvider и удаляющий его должным образом, чтобы избежать его повторного создания экземпляров.)
Было отмечено, что, поскольку это возвращает строку base-64, длина вывода всегда кратна 4, с дополнительным пробелом, использующим = в качестве символа заполнения. Параметр length указывает длину байтового буфера, а не выходную строку (и поэтому, возможно, это не лучшее имя для этого параметра, теперь я думаю об этом). Это контролирует, сколько байтов энтропия будет иметь пароль. Однако, поскольку base-64 использует 4-символьный блок для кодирования каждых 3 байтов ввода, если вы запросите длину, не кратную 3, будет некоторое дополнительное «пространство», и он будет использовать = для заполнения доп.
Если вам по какой-либо причине не нравится использовать строки base-64, вы можете заменить вызов Convert.ToBase64String() либо преобразованием в обычную строку, либо любым из методов Encoding; например. Encoding.UTF8.GetString(tokenBuffer) - просто убедитесь, что вы выбрали набор символов, который может представлять полный диапазон значений, исходящих из ГСЧ, и который создает символы, совместимые с тем, где вы его отправляете или храните. Например, при использовании Unicode появляется много китайских символов. Использование base-64 гарантирует широко совместимый набор символов, и характеристики такой строки не должны делать ее менее безопасной, если вы используете достойный алгоритм хеширования.
Я думаю, вы хотите разместить tokenBuffer там, где у вас есть linkBuf.
Когда я использую этот код и передаю длину 10, возвращаемая строка всегда имеет длину 16 символов, а последние 2 символа всегда равны «==». Я неправильно его использую? Длина указана в шестнадцатеричном формате?
Указанная длина - это количество байтов случайности (или «энтропии», как ее называют технически). Однако возвращаемое значение имеет кодировку base-64, что означает, что из-за того, как работает кодировка base-64, длина вывода всегда кратна 4. Иногда символов больше, чем необходимо для кодирования всех символов, поэтому он использует = символы для заполнения остальных.
RNGCryptoServiceProvider - это IDisposable, поэтому я бы реализовал его с использованием шаблона (т.е. используя (var cryptRNG = new RNGCryptoServiceProvider ()) {...})
@kloarubeek Верный момент и хорошее предложение. Я добавил это в свой образец кода.
На своем сайте я использую этот метод:
//Symb array
private const string _SymbolsAll = "~`!@#$%^&*()_+=-\|[{]}'\";:/?.>,<";
//Random symb
public string GetSymbol(int Length)
{
Random Rand = new Random(DateTime.Now.Millisecond);
StringBuilder result = new StringBuilder();
for (int i = 0; i < Length; i++)
result.Append(_SymbolsAll[Rand.Next(0, _SymbolsAll.Length)]);
return result.ToString();
}
Отредактируйте строку _SymbolsAll для вашего списка массивов.
Как уже было сказано в описании редактирования. Если вы ссылаетесь на свой веб-сайт, не являясь ссылкой на код, вы рекламируете исключительно, что делает его спамом, поэтому, пожалуйста, удалите эту ссылку из своего ответа.
Я всегда был очень доволен встроенным в KeePass генератором паролей. Поскольку KeePass - это программа .Net с открытым исходным кодом, я решил немного покопаться в коде. В итоге я просто сослался на KeePass.exe, копию, предоставленную при стандартной установке приложения, в качестве ссылки в моем проекте и написал код ниже. Вы можете увидеть, насколько он гибкий благодаря KeePass. Вы можете указать длину, какие символы включать / не включать и т. д.
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Security;
public static string GeneratePassword(int passwordLength, bool lowerCase, bool upperCase, bool digits,
bool punctuation, bool brackets, bool specialAscii, bool excludeLookAlike)
{
var ps = new ProtectedString();
var profile = new PwProfile();
profile.CharSet = new PwCharSet();
profile.CharSet.Clear();
if (lowerCase)
profile.CharSet.AddCharSet('l');
if (upperCase)
profile.CharSet.AddCharSet('u');
if (digits)
profile.CharSet.AddCharSet('d');
if (punctuation)
profile.CharSet.AddCharSet('p');
if (brackets)
profile.CharSet.AddCharSet('b');
if (specialAscii)
profile.CharSet.AddCharSet('s');
profile.ExcludeLookAlike = excludeLookAlike;
profile.Length = (uint)passwordLength;
profile.NoRepeatingCharacters = true;
KeePassLib.Cryptography.PasswordGenerator.PwGenerator.Generate(out ps, profile, null, _pool);
return ps.ReadString();
}
Вот что я быстро собрал.
public string GeneratePassword(int len)
{
string res = "";
Random rnd = new Random();
while (res.Length < len) res += (new Func<Random, string>((r) => {
char c = (char)((r.Next(123) * DateTime.Now.Millisecond % 123));
return (Char.IsLetterOrDigit(c)) ? c.ToString() : "";
}))(rnd);
return res;
}
public string Sifre_Uret(int boy, int noalfa)
{
// 01.03.2016
// Genel amaçlı şifre üretme fonksiyonu
//Fonskiyon 128 den büyük olmasına izin vermiyor.
if (boy > 128 ) { boy = 128; }
if (noalfa > 128) { noalfa = 128; }
if (noalfa > boy) { noalfa = boy; }
string passch = System.Web.Security.Membership.GeneratePassword(boy, noalfa);
//URL encoding ve Url Pass + json sorunu yaratabilecekler pass ediliyor.
//Microsoft Garanti etmiyor. Alfa Sayısallar Olabiliyorimiş . !@#$%^&*()_-+=[{]};:<>|./?.
//https://msdn.microsoft.com/tr-tr/library/system.web.security.membership.generatepassword(v=vs.110).aspx
//URL ve Json ajax lar için filtreleme
passch = passch.Replace(":", "z");
passch = passch.Replace(";", "W");
passch = passch.Replace("'", "t");
passch = passch.Replace("\"", "r");
passch = passch.Replace("/", "+");
passch = passch.Replace("\", "e");
passch = passch.Replace("?", "9");
passch = passch.Replace("&", "8");
passch = passch.Replace("#", "D");
passch = passch.Replace("%", "u");
passch = passch.Replace(" = ", "4");
passch = passch.Replace("~", "1");
passch = passch.Replace("[", "2");
passch = passch.Replace("]", "3");
passch = passch.Replace("{", "g");
passch = passch.Replace("}", "J");
//passch = passch.Replace("(", "6");
//passch = passch.Replace(")", "0");
//passch = passch.Replace("|", "p");
//passch = passch.Replace("@", "4");
//passch = passch.Replace("!", "u");
//passch = passch.Replace("$", "Z");
//passch = passch.Replace("*", "5");
//passch = passch.Replace("_", "a");
passch = passch.Replace(",", "V");
passch = passch.Replace(".", "N");
passch = passch.Replace("+", "w");
passch = passch.Replace("-", "7");
return passch;
}
Не могли бы вы объяснить, что делает ваш код и почему? Из обзора
Ответы, содержащие только код, без объяснения причин, скорее всего, будут удалены.
К принятому ответу добавлен дополнительный код. Он улучшает ответы, просто используя случайный выбор, и позволяет использовать некоторые параметры пароля. Мне также понравились некоторые варианты ответа KeePass, но я не хотел включать исполняемый файл в свое решение.
private string RandomPassword(int length, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
if (length < 8 || length > 128) throw new ArgumentOutOfRangeException("length");
if (!includeCharacters && !includeNumbers && !includeNonAlphaNumericCharacters) throw new ArgumentException("RandomPassword-Key arguments all false, no values would be returned");
string pw = "";
do
{
pw += System.Web.Security.Membership.GeneratePassword(128, 25);
pw = RemoveCharacters(pw, includeCharacters, includeNumbers, includeUppercase, includeNonAlphaNumericCharacters, includeLookAlikes);
} while (pw.Length < length);
return pw.Substring(0, length);
}
private string RemoveCharacters(string passwordString, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
if (!includeCharacters)
{
var remove = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
foreach (string r in remove)
{
passwordString = passwordString.Replace(r, string.Empty);
passwordString = passwordString.Replace(r.ToUpper(), string.Empty);
}
}
if (!includeNumbers)
{
var remove = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
if (!includeUppercase)
passwordString = passwordString.ToLower();
if (!includeNonAlphaNumericCharacters)
{
var remove = new string[] { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", " = ", "{", "}", "[", "]", "|", "\", ":", ";", "<", ">", "/", "?", "." };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
if (!includeLookAlikes)
{
var remove = new string[] { "(", ")", "0", "O", "o", "1", "i", "I", "l", "|", "!", ":", ";" };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
return passwordString;
}
Это была первая ссылка, когда я искал генерацию случайных паролей, и следующее выходит за рамки текущего вопроса, но может быть важно рассмотреть.
System.Web.Security.Membership.GeneratePassword является криптографически безопасным, и как минимум 20% символов не являются буквенно-цифровыми.К вашему сведению, вам не нужно включать исполняемый файл KeyPass, так как он с открытым исходным кодом (исходный код доступен для загрузки здесь)
validChars может быть любой конструкцией, но я решил выбрать на основе диапазонов кода ascii, удалив управляющие символы. В этом примере это 12-символьная строка.
string validChars = String.Join("", Enumerable.Range(33, (126 - 33)).Where(i => !(new int[] { 34, 38, 39, 44, 60, 62, 96 }).Contains(i)).Select(i => { return (char)i; }));
string.Join("", Enumerable.Range(1, 12).Select(i => { return validChars[(new Random(Guid.NewGuid().GetHashCode())).Next(0, validChars.Length - 1)]; }))
Generate random password of specified length with
- Special characters
- Number
- Lowecase
- Uppercase
public static string CreatePassword(int length = 12)
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!@#$%^&*";
var middle = length / 2;
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
if (middle == length)
{
res.Append(number[rnd.Next(number.Length)]);
}
else if (middle - 1 == length)
{
res.Append(special[rnd.Next(special.Length)]);
}
else
{
if (length % 2 == 0)
{
res.Append(lower[rnd.Next(lower.Length)]);
}
else
{
res.Append(upper[rnd.Next(upper.Length)]);
}
}
}
return res.ToString();
}
Ответы только на код не приветствуются, поскольку они не предоставляют много информации для будущих читателей, пожалуйста, объясните то, что вы написали
Создает один и тот же пароль снова и снова. Необходимо иметь экземпляр Random как статический
Обратите внимание, что этот ответ будет генерировать один и тот же пароль при вызове несколько раз подряд !!! Между вызовами должна быть добавлена энтропия, если вы хотите использовать функцию для назначения паролей с помощью кода сразу нескольким записям. Тем не менее, полезно ....
public static string GeneratePassword(int passLength) {
var chars = "abcdefghijklmnopqrstuvwxyz@#$&ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, passLength)
.Select(s => s[random.Next(s.Length)])
.ToArray());
return result;
}
Пожалуйста, объясните свой ответ
Эта функция работает очень хорошо с небольшими изменениями. 1. Добавлена энтропия, если вы выполняете несколько вызовов одновременно. Это означает, что вызывается функция Sleep () или другая функция, вызывающая энтропию между вызовами. 2. Увеличьте количество и случайность исходных символов. Я создал серию паролей из 500 символов с keypass, исключив кучу похожих и других экранируемых символов, с которыми я не хотел иметь дело, и использовал полученную строку из 2000 символов. Случайность даже после 100 мс энтропии была довольно хорошей.
Я добавлю еще один опрометчивый ответ в горшок.
У меня есть случай использования, когда мне нужны случайные пароли для машинно-машинной связи, поэтому у меня нет требований к удобочитаемости. У меня также нет доступа к Membership.GeneratePassword в моем проекте, и я не хочу добавлять зависимость.
Я почти уверен, что Membership.GeneratePassword делает что-то подобное, но здесь вы можете настроить пулы персонажей для рисования.
public static class PasswordGenerator
{
private readonly static Random _rand = new Random();
public static string Generate(int length = 24)
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!@#$%^&*_-=+";
// Get cryptographically random sequence of bytes
var bytes = new byte[length];
new RNGCryptoServiceProvider().GetBytes(bytes);
// Build up a string using random bytes and character classes
var res = new StringBuilder();
foreach(byte b in bytes)
{
// Randomly select a character class for each byte
switch (_rand.Next(4))
{
// In each case use mod to project byte b to the correct range
case 0:
res.Append(lower[b % lower.Count()]);
break;
case 1:
res.Append(upper[b % upper.Count()]);
break;
case 2:
res.Append(number[b % number.Count()]);
break;
case 3:
res.Append(special[b % special.Count()]);
break;
}
}
return res.ToString();
}
}
И пример вывода:
PasswordGenerator.Generate(12)
"pzY=64@-ChS$"
"BG0OsyLbYnI_"
"l9#5^2&adj_i"
"#++Ws9d$%O%X"
"IWhdIN-#&O^s"
Чтобы предупредить жалобы на использование Random: основным источником случайности по-прежнему является криптографический ГСЧ. Даже если бы вы могли детерминированно предопределить последовательность, исходящую из Random (скажем, он произвел только 1), вы все равно не знали бы, какой следующий символ будет выбран (хотя этот бы ограничивает диапазон возможностей).
Одним из простых расширений было бы добавление веса к различным наборам символов, что могло бы быть таким простым, как увеличение максимального значения и добавление случаев провала для увеличения веса.
switch (_rand.Next(6))
{
// Prefer letters 2:1
case 0:
case 1:
res.Append(lower[b % lower.Count()]);
break;
case 2:
case 3:
res.Append(upper[b % upper.Count()]);
break;
case 4:
res.Append(number[b % number.Count()]);
break;
case 5:
res.Append(special[b % special.Count()]);
break;
}
Для более гуманного генератора случайных паролей я однажды реализовал систему подсказок, используя список слов EFF.
Я использую этот код для генерации пароля с балансом, состоящим из буквенных, числовых и non_alpha_numeric символов.
public static string GeneratePassword(int Length, int NonAlphaNumericChars)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
string pass = "";
Random rd = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < Length; i++)
{
if (rd.Next(1) > 0 && NonAlphaNumericChars > 0)
{
pass += allowedNonAlphaNum[rd.Next(allowedNonAlphaNum.Length)];
NonAlphaNumericChars--;
}
else
{
pass += allowedChars[rd.Next(allowedChars.Length)];
}
}
return pass;
}
Не используйте этот ответ. Он использует обычный класс "Random", а не криптографически безопасный.
Этот пакет позволяет вам сгенерировать случайный пароль, бегло указывая, какие символы он должен содержать (при необходимости):
https://github.com/prjseal/PasswordGenerator/
Пример:
var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();
Если вы хотите использовать криптографически безопасную генерацию случайных чисел, используемую System.Web.Security.Membership.GeneratePassword, но также хотите ограничить набор символов буквенно-цифровыми символами, вы можете отфильтровать результат с помощью регулярного выражения:
static string GeneratePassword(int characterCount)
{
string password = String.Empty;
while(password.Length < characterCount)
password += Regex.Replace(System.Web.Security.Membership.GeneratePassword(128, 0), "[^a-zA-Z0-9]", string.Empty);
return password.Substring(0, characterCount);
}
проверьте этот код ... Я добавил .remove (length), чтобы улучшить ответ анаксимандр
public string GeneratePassword(int length)
{
RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider();
byte[] tokenBuffer = new byte[length];
cryptRNG.GetBytes(tokenBuffer);
return Convert.ToBase64String(tokenBuffer).Remove(length);
}
Вот несколько хороших решений, но небольшой совет: не создавайте пароли, содержащие какие-либо из этих символов: Oo0Ili (вы понимаете, почему) :)