Генератор паролей на JavaScript: урок
Попробуйте готовый инструмент: генератор паролей →
Генератор паролей (crypto)
Работает в браузере, ничего не уходит на сервер.
Что такое JavaScript Password Generator?
Генератор паролей берёт случайные символы из выбранного набора и ставит их в ряд. Главный вопрос — откуда случайность. В браузере есть два пути. Math.random быстрый, но не для паролей: его результат можно предсказать. crypto.getRandomValues даёт байты из криптографического источника операционной системы. Для паролей используют только второй. Всё происходит внутри страницы, на сервер ничего не уходит.
Для чего нужен JavaScript Password Generator?
Этот урок показывает в одном месте безопасные случайные числа, форму и копирование в JavaScript.
- Получить сильный пароль для нового аккаунта
- Длинная строка для Wi-Fi или API-ключа
- Понять разницу между Math.random и crypto
- Кнопка копирования через Clipboard API
Что можно делать с JavaScript Password Generator?
Пользователь выбирает длину (например, 8–64) и наборы: строчные, заглавные, цифры, символы. Код склеивает выбранные наборы в одну строку. Затем берёт случайный индекс для каждого символа. Готовый пароль копируется одной кнопкой. На HTTPS браузер даёт navigator.clipboard, иначе остаётся старый путь execCommand. Пароль не пишется в localStorage и никуда не отправляется. Готовый инструмент — на странице /tools/password.
Сложно ли освоить JavaScript Password Generator?
Код короткий, но есть ловушка. Если просто взять случайный байт «% длина», одни символы выпадают чаще других. Это называется смещением по модулю. Решение — rejection sampling: число выше наибольшей границы, кратной длине набора, отбрасывают и берут новое. И ещё: чтобы был хотя бы один символ из каждого набора, нужно потом перемешать, и перемешивание тоже через crypto.
Плюсы и ограничения
Плюс: нет сервера, нет следов, код работает в любом браузере. Ограничение: хранить пароль — твоя задача, для этого нужен менеджер паролей. Длина даёт больше силы, чем типы символов.
Основные понятия
Если знаешь эти четыре понятия, каждая строка кода понятна.
- crypto.getRandomValues — криптографическая случайность
- Math.random — для игр, не для паролей
- Rejection sampling — против смещения по модулю
- Энтропия ≈ длина × log2(размер набора)
Короткий пример
Функция, берущая случайный индекс без смещения, и цикл, собирающий пароль:
1. Случайный индекс без смещения:
function randomIndex(max) {
const limit = Math.floor(0x100000000 / max) * max;
const buf = new Uint32Array(1);
do { crypto.getRandomValues(buf); } while (buf[0] >= limit);
return buf[0] % max;
}Эта функция возвращает случайный индекс от 0 до max-1.
limit — самое большое число меньше 2^32, которое делится на max без остатка.
crypto.getRandomValues записывает в buf криптографическое случайное число.
Если число больше или равно limit, оно отбрасывается и берётся новое. Так ни один индекс не выпадает чаще других.
В конце % max переводит число в диапазон 0…max-1.
2. Наборы символов:
const SETS = {
lower: "abcdefghijklmnopqrstuvwxyz",
upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
digits: "0123456789",
symbols: "!@#$%^&*()-_=+[]{};:,.?",
};Этот объект хранит четыре набора: строчные, заглавные, цифры, символы.
Пароль берётся только из тех наборов, которые пользователь отметил.
Чем больше набор, тем больше вариантов у каждого символа и тем труднее угадать пароль.
3. Цикл, собирающий пароль:
function makePassword(length, chosen) {
const pool = chosen.map((k) => SETS[k]).join("");
if (!pool) throw new Error("Choose at least one set");
let out = "";
for (let i = 0; i < length; i++) out += pool[randomIndex(pool.length)];
return out;
}chosen — имена выбранных наборов, например ["lower", "digits"]. pool склеивает их символы в одну строку.
Если ничего не выбрано, функция бросает ошибку, а не возвращает пустой пароль.
Цикл выполняется length раз. Каждый раз randomIndex берёт один символ из набора и добавляет его в конец out.
Результат: готовая строка пароля на экране, например k7#Qm2…
4. Хотя бы один символ из каждого набора и перемешивание:
function makeStrongPassword(length, chosen) {
const chars = chosen.map((k) => SETS[k][randomIndex(SETS[k].length)]);
const pool = chosen.map((k) => SETS[k]).join("");
while (chars.length < length) chars.push(pool[randomIndex(pool.length)]);
for (let i = chars.length - 1; i > 0; i--) {
const j = randomIndex(i + 1);
[chars[i], chars[j]] = [chars[j], chars[i]];
}
return chars.join("");
}Первая строка берёт по одному обязательному символу из каждого выбранного набора. Если выбраны цифры, в пароле точно будет цифра.
while заполняет остальные места из общего набора.
Цикл for — перемешивание Фишера–Йейтса: он случайно меняет места, чтобы обязательные символы не стояли всегда в начале.
Результат: пароль со всеми выбранными типами в непредсказуемом порядке.
Частые вопросы
- Можно ли Math.random? Для паролей нет. Его результат не криптографический и предсказуем.
- Пароль уходит на сервер? Нет. Он считается в браузере и нигде не хранится.
- Сколько символов хорошо? Не меньше 16. Длина помогает больше, чем типы символов.
- Где готовый инструмент? На nibrascode.com/tools/password.