В области информационной безопасности и разработки программного обеспечения термины «шифрование», «кодирование» и «хеширование» часто используются рядом, однако они решают принципиально разные задачи. Непонимание различий между ними приводит к критическим ошибкам: хранению паролей в открытом виде, неправильной защите API, небезопасной передаче данных и уязвимостям аутентификации.
| Технология | Основная цель | Возможность восстановления данных | Используется ключ | Пример |
|---|---|---|---|---|
| Кодирование | Представление данных в другом формате | Да | Нет | Base64 |
| Шифрование | Защита данных от чтения | Да | Да | AES |
| Хеширование | Получение уникального отпечатка данных | Нет | Нет | SHA-256 |
Кодирование применяется для преобразования данных в формат, удобный для хранения, передачи или обработки различными системами.
Главная особенность:
Кодирование не предназначено для защиты информации.
После кодирования данные можно восстановить без секретного ключа.
Base64 — один из самых распространённых способов кодирования.
const text = "password123";
const encoded = Buffer.from(text).toString("base64");
console.log(encoded);
Результат:
cGFzc3dvcmQxMjM=
const decoded = Buffer.from(encoded, "base64").toString();
console.log(decoded);
Результат:
password123
Например:
const value = encodeURIComponent("hello world");
console.log(value);
Результат:
hello%20world
Одна из самых опасных ошибок начинающих разработчиков — считать Base64 защитой.
Неправильно:
const password = Buffer
.from("myPassword")
.toString("base64");
Такой «защищённый» пароль мгновенно восстанавливается.
Шифрование используется для сокрытия информации от посторонних лиц.
Данные можно восстановить только при наличии:
Один и тот же ключ используется:
const crypto = require("crypto");
const algorithm = "aes-256-cbc";
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const text = "secret data";
const cipher = crypto.createCipheriv(
algorithm,
key,
iv
);
let encrypted = cipher.update(
text,
"utf8",
"hex"
);
encrypted += cipher.final("hex");
console.log(encrypted);
const decipher = crypto.createDecipheriv(
algorithm,
key,
iv
);
let decrypted = decipher.update(
encrypted,
"hex",
"utf8"
);
decrypted += decipher.final("utf8");
console.log(decrypted);
TLS использует шифрование для защиты:
Создание защищённых туннелей связи.
Например:
Используется:
Используются два ключа:
| Ключ | Назначение |
|---|---|
| Публичный | Шифрование |
| Приватный | Расшифровка |
const crypto = require("crypto");
const {
publicKey,
privateKey
} = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048
});
const encrypted = crypto.publicEncrypt(
publicKey,
Buffer.from("secret")
);
console.log(encrypted.toString("base64"));
const decrypted = crypto.privateDecrypt(
privateKey,
encrypted
);
console.log(decrypted.toString());
Хеширование создаёт фиксированный отпечаток данных.
Главная особенность:
Исходные данные невозможно восстановить обратно.
Одинаковые данные всегда дают одинаковый результат.
hash("123") === hash("123")
Из хеша невозможно получить исходное значение.
Даже минимальное изменение данных полностью меняет результат.
Сложно найти:
A != B
но:
hash(A) === hash(B)
const crypto = require("crypto");
const hash = crypto
.createHash("sha256")
.update("password123")
.digest("hex");
console.log(hash);
ef92b778bafe771e...
Простое хеширование небезопасно для хранения паролей.
Причины:
Для хранения паролей применяются специальные алгоритмы:
| Алгоритм | Статус |
|---|---|
| bcrypt | Популярный |
| scrypt | Более устойчивый |
| Argon2 | Современный стандарт |
npm install bcrypt
const bcrypt = require("bcrypt");
const password = "mySecretPassword";
const hash = await bcrypt.hash(password, 10);
console.log(hash);
const isValid = await bcrypt.compare(
"mySecretPassword",
hash
);
console.log(isValid);
bcrypt:
Salt — случайная строка, добавляемая к паролю перед хешированием.
Пример:
password + randomSalt
Без salt два одинаковых пароля создают одинаковые хеши.
С salt:
password123 -> hash1
password123 -> hash2
const hash = await bcrypt.hash(password, 10);
Salt уже встроен внутрь результата.
Argon2 победил в конкурсе Password Hashing Competition.
Сильные стороны:
npm install argon2
const argon2 = require("argon2");
const hash = await argon2.hash(
"superPassword"
);
console.log(hash);
const valid = await argon2.verify(
hash,
"superPassword"
);
console.log(valid);
Данные должны быть восстановлены.
Примеры:
Данные восстанавливать не нужно.
Примеры:
const encryptedPassword =
encrypt(password);
Проблема:
если злоумышленник получит ключ шифрования — все пароли будут раскрыты.
const passwordHash =
await bcrypt.hash(password, 12);
Проверка выполняется сравнением хешей.
const fs = require("fs");
const crypto = require("crypto");
const file = fs.readFileSync("file.zip");
const hash = crypto
.createHash("sha256")
.update(file)
.digest("hex");
console.log(hash);
HMAC объединяет:
const crypto = require("crypto");
const hmac = crypto
.createHmac(
"sha256",
"secret-key"
)
.update("message")
.digest("hex");
console.log(hmac);
Rainbow table — заранее вычисленная база:
пароль -> хеш
Если два пользователя имеют пароль:
123456
то SHA-256 создаст одинаковый хеш.
Даже одинаковые пароли получают разные хеши.
Атакующий массово проверяет варианты:
123456
password
qwerty
admin
bcrypt и Argon2 специально делают вычисления дорогими.
Это:
Pepper — секретное значение, известное только серверу.
const pepper = process.env.PEPPER;
const hash = await bcrypt.hash(
password + pepper,
12
);
| Salt | Pepper |
|---|---|
| Хранится рядом с хешем | Хранится отдельно |
| Уникален для пользователя | Общий для системы |
| Не секретен | Секретен |
Ошибка:
Buffer.from(password)
.toString("base64");
MD5 считается криптографически сломанным.
Нельзя использовать:
SHA-1 также считается устаревшим.
Одинаковые пароли получают одинаковые хеши.
Например:
bcrypt.hash(password, 2)
Такой хеш слишком быстрый.
| Задача | Рекомендуемое решение |
|---|---|
| Хранение паролей | Argon2 |
| Совместимость со старыми системами | bcrypt |
| Контроль целостности | SHA-256 |
| Подпись запросов | HMAC-SHA256 |
| Шифрование данных | AES-256 |
myPassword123
const hash =
await argon2.hash(password);
$argon2id$v=19$m=65536...
myPassword123
await argon2.verify(
storedHash,
enteredPassword
);
Даже администратор базы данных не должен видеть реальные пароли пользователей.
| Сценарий | Технология |
|---|---|
| Передача бинарных данных | Кодирование |
| Сокрытие содержимого | Шифрование |
| Хранение паролей | Хеширование |
| Проверка целостности | Хеширование |
| Безопасная связь | Шифрование |
| JWT payload | Кодирование |
| HTTPS | Шифрование |
| API signatures | HMAC |
Кодирование меняет формат данных.
Шифрование скрывает данные.
Хеширование создаёт необратимый отпечаток данных.
Для паролей применяется не обычное хеширование, а специализированные алгоритмы password hashing:
Именно они обеспечивают устойчивость современных систем аутентификации к массовому перебору, утечкам баз данных и криптографическим атакам.