0Pricing
Java Academy · Урок

Криптографическое хеширование с MessageDigest

Хешируйте пароли с помощью SHA-256, добавляйте соль для защиты от атак по радужным таблицам и безопасно сравнивайте дайджесты.

«Криптографическое хеширование с MessageDigest» — бесплатный урок Java Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Что такое криптографическое хеширование

Криптографическая хеш-функция преобразует данные любого размера в дайджест фиксированного размера. Она односторонняя (её нельзя обратить), детерминирована и устойчива к коллизиям. Хеширование используется для хранения паролей, проверки целостности данных и создания цифровых подписей.

API MessageDigest

MessageDigest.getInstance("SHA-256") возвращает средство вычисления хеша SHA-256. Вызовите digest(bytes), чтобы вычислить хеш и получить массив байтов.

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password123".getBytes(StandardCharsets.UTF_8));
String hex = HexFormat.of().formatHex(hash);
System.out.println(hex); // 64-char hex string

Распространённые алгоритмы

JDK поддерживает следующие алгоритмы: MD5 (взломан — никогда не используйте его для защиты), SHA-1 (устарел для целей защиты), SHA-256 (стандартный), SHA-512 (более стойкий), SHA3-256 (современный). Для нового кода всегда используйте SHA-256 или SHA-512.

MessageDigest.getInstance("SHA-256");  // recommended
MessageDigest.getInstance("SHA-512");  // stronger
MessageDigest.getInstance("SHA3-256"); // SHA-3 family
// Never: MessageDigest.getInstance("MD5"); // cryptographically broken

Преобразование хеша в шестнадцатеричную строку

Результат в виде массива байтов необходимо преобразовать в шестнадцатеричную строку для хранения или сравнения. Используйте HexFormat (Java 17+) или String.format в более старых версиях.

// Java 17+:
String hex = HexFormat.of().formatHex(hash);
// Older Java:
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
String hex = sb.toString();

Соль: защита от радужных таблиц

Радужная таблица сопоставляет распространённые пароли с их хешами. Добавление соли присоединяет к каждому паролю случайное значение перед хешированием, делая радужные таблицы бесполезными. Храните соль вместе с хешем.

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] hash = md.digest("password".getBytes(StandardCharsets.UTF_8));
// Store: Base64.encode(salt) + ":" + Base64.encode(hash)

Хеширование паролей — используйте BCrypt

SHA-256 с солью лучше обычного SHA-256, но всё ещё работает быстро — злоумышленник может проверять миллиарды вариантов в секунду. Для паролей используйте медленный KDF: BCryptPasswordEncoder (Spring Security), PBKDF2 или Argon2.

// Spring Security — proper password hashing:
PasswordEncoder encoder = new BCryptPasswordEncoder(12); // cost factor 12
String hash = encoder.encode("password123");
boolean match = encoder.matches("password123", hash); // true

Проверка целостности файла

Вычисляйте хеш файла, чтобы обнаружить повреждение или несанкционированное изменение. Сравнивайте вычисленный хеш с эталонным значением, которому доверяете.

MessageDigest md = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(Path.of("app.jar"))) {
    byte[] buf = new byte[8192];
    int n;
    while ((n = is.read(buf)) > 0) md.update(buf, 0, n);
}
String hash = HexFormat.of().formatHex(md.digest());
System.out.println("SHA-256: " + hash);

Безопасное сравнение хешей

Используйте MessageDigest.isEqual() для сравнения за постоянное время, чтобы предотвратить атаки по времени выполнения. Никогда не используйте String.equals() для сравнения хешей.

byte[] expected = computeHash(storedHash);
byte[] actual   = computeHash(inputPassword);
boolean match = MessageDigest.isEqual(expected, actual); // constant-time

Последовательное обновление хеша

Несколько раз вызовите md.update(bytes) перед md.digest(), чтобы хешировать данные, поступающие частями (в потоковом режиме).

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update("part1".getBytes());
md.update("part2".getBytes());
byte[] hash = md.digest(); // hash of "part1" + "part2"

Кодирование хешей для хранения

Храните двоичные хеши в формате Base64 (он короче шестнадцатеричного представления) или в виде шестнадцатеричных строк. Для SHA-256 Base64 использует 43 символа, а шестнадцатеричное представление — 64. Оба варианта корректны — главное, придерживаться единообразия.

byte[] hash = md.digest(data);
String base64 = Base64.getEncoder().encodeToString(hash); // 44 chars (with padding)
String hex    = HexFormat.of().formatHex(hash);           // 64 chars

DigestInputStream для потоковой обработки

Оберните InputStream в DigestInputStream, чтобы вычислять хеш во время чтения и не загружать весь файл в память.

MessageDigest md = MessageDigest.getInstance("SHA-256");
try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(path), md)) {
    dis.transferTo(OutputStream.nullOutputStream());
}
String hash = HexFormat.of().formatHex(md.digest());

Быстрая проверка

Почему SHA-256 с солью всё ещё не рекомендуется для хранения паролей?

Итоги

Используйте MessageDigest.getInstance("SHA-256") для проверки целостности данных. Всегда добавляйте соль к паролям, но для их хранения используйте BCrypt или Argon2, а не необработанный SHA. Для предотвращения атак по времени выполнения используйте сравнение за постоянное время (MessageDigest.isEqual).

Часто задаваемые вопросы

Урок «Криптографическое хеширование с MessageDigest» бесплатный?

Да — полный текст урока «Криптографическое хеширование с MessageDigest» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Криптографическое хеширование с MessageDigest»?

Хешируйте пароли с помощью SHA-256, добавляйте соль для защиты от атак по радужным таблицам и безопасно сравнивайте дайджесты. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Криптографическое хеширование с MessageDigest»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Криптографическое хеширование с MessageDigest
  2. Симметричное шифрование AES
  3. HMAC-SHA256 для целостности сообщений
  4. JWT: структура, создание и проверка
← Назад к Java Academy