В веб-приложениях пароль почти всегда поступает из формы ввода, где
пользователь вручную вводит строку. На стороне клиента это поле типа
password, которое скрывает вводимые символы, но не влияет
на сам процесс передачи данных.
Типичная HTML-разметка:
<form id="loginForm">
<label for="password">Пароль</label>
<input type="password" id="password" name="password" autocomplete="current-password" />
<button type="submit">Войти</button>
</form>
Обработка на клиенте в Jav * aScript:
const form = document.getElementById('loginForm');
form.addEventListener('submit', (event) => {
event.preventDefault();
const password = document.getElementById('password').value;
handlePassword(password);
});
Ключевой момент: пароль извлекается как обычная строка. На этом этапе он уже становится чувствительными данными в памяти приложения, поэтому любые операции с ним должны быть минимальными и контролируемыми.
При архитектуре клиент–сервер пароль обычно отправляется через HTTPS-запрос и принимается сервером. Пример на Node.js с использованием Express:
import express from 'express';
const app = express();
app.use(express.json());
app.post('/login', (req, res) => {
const password = req.body.password;
handlePassword(password);
res.sendStatus(200);
});
Важно учитывать, что пароль приходит в открытом виде внутри защищённого канала. Сервер должен обработать его немедленно и не сохранять в промежуточных структурах без необходимости.
Перед использованием библиотеки хеширования (например,
password-hash) выполняется предварительная проверка. Она не
заменяет криптографическую защиту, но отсекает очевидно некорректные
значения.
Основные цели базовой обработки:
Простейшая функция валидации:
function normalizePassword(password) {
return password.trim();
}
Удаление пробелов по краям важно, так как пользователи часто случайно добавляют их при копировании или автозаполнении.
Одним из самых частых сценариев является отправка пустого пароля. Это необходимо отсеивать до любых дальнейших операций.
function validatePasswordNotEmpty(password) {
return typeof password === 'string' && password.length > 0;
}
Более строгий вариант:
function validatePasswordNotEmpty(password) {
return typeof password === 'string' && password.trim().length > 0;
}
Пустые или состоящие только из пробелов строки не должны попадать в систему хранения или проверки.
Слишком длинные строки могут использоваться для атак на отказ в обслуживании или просто создавать избыточную нагрузку на систему хеширования.
Рекомендуемые ограничения:
Пример проверки:
function validatePasswordLength(password) {
const min = 8;
const max = 128;
if (password.length < min) return false;
if (password.length > max) return false;
return true;
}
Ограничение максимальной длины особенно важно, так как алгоритмы хеширования (bcrypt, argon2 и аналогичные) имеют вычислительную стоимость, пропорциональную размеру входа.
На уровне минимальной безопасности часто вводятся требования к составу пароля. Это не заменяет криптографическую стойкость, но повышает устойчивость к простым атакам перебора.
Пример проверки:
function validatePasswordComposition(password) {
const hasLetter = /[a-zA-Z]/.test(password);
const hasNumber = /\d/.test(password);
return hasLetter && hasNumber;
}
Расширенный вариант:
function validatePasswordStrength(password) {
const hasLower = /[a-z]/.test(password);
const hasUpper = /[A-Z]/.test(password);
const hasDigit = /\d/.test(password);
const hasSpecial = /[^a-zA-Z0-9]/.test(password);
return hasLower && hasUpper && hasDigit && hasSpecial;
}
Подобные проверки должны использоваться осторожно: излишняя строгость может ухудшить пользовательский опыт без существенного выигрыша в безопасности.
Пароли могут содержать символы разных языков и кодировок. Это создаёт риск визуально одинаковых, но технически разных строк.
Пример проблемы:
pаssword (латинская a)password (кириллическая а)Для базовой нормализации можно использовать:
function normalizeUnicode(password) {
return password.normalize('NFKC');
}
Это приводит строку к стандартной форме, уменьшая риск скрытых различий.
Даже на этапе получения и валидации критически важно исключить попадание пароля в логи.
Плохая практика:
console.log(password);
Корректный подход:
console.log('password received');
или полное отсутствие логирования значения.
После первичной валидации пароль может быть передан в библиотеку
хеширования. Например, в password-hash:
import passwordHash from 'password-hash';
function hashPassword(password) {
return passwordHash.generate(password);
}
В этом контексте важно понимать: библиотека не должна получать «грязные» данные. Все проверки выполняются до вызова хеширования.
Пример полного пайплайна:
function processPassword(rawPassword) {
const password = normalizePassword(rawPassword);
if (!validatePasswordNotEmpty(password)) {
throw new Error('Empty password');
}
if (!validatePasswordLength(password)) {
throw new Error('Invalid password length');
}
if (!validatePasswordComposition(password)) {
throw new Error('Weak password format');
}
return passwordHash.generate(password);
}
После получения пароль должен существовать в памяти минимальное время. В JavaScript нельзя полностью контролировать очистку памяти, но можно уменьшить время жизни переменной.
Практика:
let password = normalizePassword(inputPassword);
const hashed = passwordHash.generate(password);
password = null;
Это не гарантирует физическое удаление данных из памяти, но снижает вероятность случайного повторного использования.
GET вместо POST, из-за чего
пароль попадает в URL;Каждая из этих ошибок увеличивает поверхность атаки и усложняет последующую защиту системы.
Корректная архитектура предполагает разделение этапов:
password-hash или аналогичную
библиотеку.Такой порядок предотвращает преждевременную обработку некорректных данных и снижает нагрузку на криптографические операции.