← Назад к вопросам

Что такое хеширование?

1.6 Junior🔥 291 комментариев
#Архитектура и паттерны#Безопасность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Хеширование (Hashing)

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

Основные свойства хеш-функций

Качественная хеш-функция должна обладать следующими свойствами:

  1. Детерминированность — одни и те же входные данные всегда дают один и тот же хеш
  2. Скорость — хеш вычисляется быстро, независимо от размера входных данных
  3. Распределение — хеши равномерно распределены по всему диапазону возможных значений
  4. Лавинный эффект — небольшое изменение входных данных кардинально меняет хеш
  5. Необратимость — невозможно восстановить исходные данные по хешу
  6. Устойчивость к коллизиям — очень сложно найти два разных входа с одинаковым хешом

Основные хеш-функции в Python

import hashlib

# Данные для хеширования
data = "Hello, World!".encode('utf-8')

# 1. MD5 (не рекомендуется для безопасности, уязвимо)
md5_hash = hashlib.md5(data).hexdigest()
print(f"MD5: {md5_hash}")
# Результат: 65a8e27d8d55e25c3d666491b6fbbf6f

# 2. SHA-1 (устарело, не использовать для криптографии)
sha1_hash = hashlib.sha1(data).hexdigest()
print(f"SHA-1: {sha1_hash}")
# Результат: 0a0a9f2a6772942557ab5355d76af442f8f65e01

# 3. SHA-256 (современный стандарт)
sha256_hash = hashlib.sha256(data).hexdigest()
print(f"SHA-256: {sha256_hash}")
# Результат: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

# 4. SHA-512
sha512_hash = hashlib.sha512(data).hexdigest()
print(f"SHA-512 (первые 64 символа): {sha512_hash[:64]}")

# 5. BLAKE2 (криптографически стойкий, быстрый)
blake2_hash = hashlib.blake2b(data).hexdigest()
print(f"BLAKE2b: {blake2_hash[:64]}")

Практические примеры использования

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

import hashlib
import os

def calculate_file_hash(filepath, algorithm='sha256'):
    """Вычислить хеш файла"""
    hash_func = hashlib.new(algorithm)
    
    # Читаем файл блоками для экономии памяти
    with open(filepath, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b''):
            hash_func.update(chunk)
    
    return hash_func.hexdigest()

def verify_file_integrity(filepath, expected_hash):
    """Проверить целостность файла"""
    actual_hash = calculate_file_hash(filepath)
    return actual_hash == expected_hash

# Пример использования
# hash_value = calculate_file_hash('/path/to/file.zip')
# print(f"SHA-256: {hash_value}")

# Позже проверяем целостность
# is_valid = verify_file_integrity('/path/to/file.zip', hash_value)
# print(f"Файл не поврежден: {is_valid}")

2. Хеширование паролей

import hashlib
import secrets

def hash_password_simple(password):
    """❌ НЕПРАВИЛЬНО: просто хеширование пароля"""
    return hashlib.sha256(password.encode()).hexdigest()

def hash_password_with_salt(password):
    """✅ ПРАВИЛЬНО: хеширование с солью"""
    salt = secrets.token_hex(32)  # Генерируем случайную соль
    password_hash = hashlib.pbkdf2_hmac(
        'sha256',
        password.encode(),
        salt.encode(),
        100000  # Количество итераций
    ).hex()
    return f"{salt}${password_hash}"

def verify_password(password, stored_hash):
    """Проверить пароль"""
    salt, password_hash = stored_hash.split('$')
    
    check_hash = hashlib.pbkdf2_hmac(
        'sha256',
        password.encode(),
        salt.encode(),
        100000
    ).hex()
    
    return check_hash == password_hash

# Использование
stored_hash = hash_password_with_salt("my_secure_password")
print(f"Хеш пароля: {stored_hash}")

# Проверка
is_valid = verify_password("my_secure_password", stored_hash)
print(f"Пароль верен: {is_valid}")

is_valid = verify_password("wrong_password", stored_hash)
print(f"Неправильный пароль: {is_valid}")

3. Использование bcrypt для паролей (рекомендуется)

# pip install bcrypt
import bcrypt

def hash_password_bcrypt(password):
    """Хеширование пароля с bcrypt"""
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt)

def verify_password_bcrypt(password, password_hash):
    """Проверка пароля"""
    return bcrypt.checkpw(password.encode(), password_hash)

# Использование
password = "my_secure_password"
hashed = hash_password_bcrypt(password)
print(f"Хеш: {hashed}")

# Проверка
is_valid = verify_password_bcrypt(password, hashed)
print(f"Пароль верен: {is_valid}")

4. Кеширование на основе хеша

import hashlib
import json
from functools import wraps

def memoize_with_hash(func):
    """Декоратор для кеширования результатов функции"""
    cache = {}
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        # Создаем ключ кеша на основе аргументов
        cache_key = hashlib.md5(
            json.dumps((args, kwargs), sort_keys=True, default=str).encode()
        ).hexdigest()
        
        if cache_key in cache:
            print(f"Из кеша: {cache_key}")
            return cache[cache_key]
        
        result = func(*args, **kwargs)
        cache[cache_key] = result
        print(f"Вычислено и закеширован: {cache_key}")
        return result
    
    return wrapper

@memoize_with_hash
def expensive_calculation(n):
    """Дорогая операция"""
    return sum(i ** 2 for i in range(n))

result1 = expensive_calculation(10000)  # Вычислено
result2 = expensive_calculation(10000)  # Из кеша
result3 = expensive_calculation(5000)   # Вычислено

5. Обнаружение дубликатов файлов

import hashlib
from pathlib import Path
from collections import defaultdict

def find_duplicate_files(directory):
    """Найти дубликаты файлов по хешу"""
    file_hashes = defaultdict(list)
    
    # Читаем все файлы и вычисляем их хеши
    for filepath in Path(directory).rglob('*'):
        if filepath.is_file():
            try:
                file_hash = calculate_file_hash(str(filepath))
                file_hashes[file_hash].append(str(filepath))
            except Exception as e:
                print(f"Ошибка при обработке {filepath}: {e}")
    
    # Возвращаем только дубликаты
    duplicates = {
        hash_val: files for hash_val, files in file_hashes.items()
        if len(files) > 1
    }
    
    return duplicates

# Использование
# duplicates = find_duplicate_files('/path/to/folder')
# for hash_val, files in duplicates.items():
#     print(f"Дубликаты (хеш: {hash_val}):")
#     for file in files:
#         print(f"  - {file}")

Различия между типами хеш-функций

# Для проверки целостности данных (не криптографические):
# - CRC32
# - Adler-32

import zlib
data = b"Hello, World!"
crc32 = zlib.crc32(data)
print(f"CRC32: {crc32}")

# Для криптографических целей:
# - SHA-256 (256-бит хеш)
# - SHA-512 (512-бит хеш)
# - BLAKE2b (универсальный, быстрый)

# Для паролей:
# - bcrypt (медленный, сложный)
# - scrypt (параметризуемый)
# - Argon2 (современный, устойчивый к GPU атакам)

Рекомендуемые хеш-функции

# ✅ Для хеширования паролей
from argon2 import PasswordHasher

hasher = PasswordHasher()
hash_value = hasher.hash("my_password")
hasher.verify(hash_value, "my_password")

# ✅ Для целостности файлов
import hashlib
hashlib.sha256(b"data").hexdigest()

# ✅ Для быстрого распределения (хеш-таблицы)
hash(("key", 42))

# ❌ НЕ ИСПОЛЬЗУЙ для криптографии
hashlib.md5(b"data").hexdigest()
hashlib.sha1(b"data").hexdigest()

Коллизии в хеширании

# Коллизия — когда два разных входа дают один хеш
# Это теоретически возможно для любой хеш-функции

def birthday_paradox_demo():
    """Демонстрация парадокса дней рождения"""
    # С 23 людьми шанс совпадения дат рождения > 50%
    # Аналогично для хешей: коллизии становятся вероятны
    # после ~2^(n/2) вычислений для n-битного хеша
    
    # SHA-256 (256 бит): коллизия ожидается после 2^128 попыток
    # Это 340 undecillion попыток - практически невозможно
    
    print("Для SHA-256:")
    print(f"Теоретическое число попыток: 2^128 = {2**128}")
    print("На практике: невозможно найти коллизию")

birthday_paradox_demo()

Хеширование — это одна из самых важных техник в компьютерной науке, используемая везде: от защиты паролей до проверки целостности данных. Понимание хеш-функций и их свойств критично для разработки безопасных систем.

Что такое хеширование? | PrepBro