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

Что такое hash функция?

2.0 Middle🔥 211 комментариев
#Python Core#Безопасность

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

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

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

Что такое hash функция?

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

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

1. Детерминированность

  • Одинаковый вход = одинаковый выход
  • Если f(x) = h, то f(x) всегда = h

2. Фиксированный размер выхода

  • MD5: 128 бит (32 hex символа)
  • SHA-256: 256 бит (64 hex символа)
  • Независимо от размера входа

3. Быстрое вычисление

  • Должна работать быстро (ms или меньше)

4. Лавинный эффект

  • Малое изменение входа → кардинальное изменение выхода
  • Если изменить 1 символ, хеш изменится совершенно

5. Одностороння функция (для крипто хешей)

  • Легко вычислить h = f(x)
  • Невозможно найти x по h

Примеры в Python

import hashlib

# SHA-256
text = "Hello, World!"
hash_obj = hashlib.sha256(text.encode())
print(hash_obj.hexdigest())
# Вывод: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

# Изменим 1 символ
text2 = "Hello, World!"
hash_obj2 = hashlib.sha256(text2.encode())
print(hash_obj2.hexdigest())
# Вывод: полностью другой хеш!

# Даже если изменить регистр букв
text3 = "hello, world!"  # Нижний регистр
hash_obj3 = hashlib.sha256(text3.encode())
print(hash_obj3.hexdigest())
# Вывод: опять полностью другой хеш!

Где используются хеш-функции?

1. Хранение паролей

import bcrypt

# Правильное хранение пароля
password = "MySecurePassword123"
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
print(hashed)  # b'$2b$12$R9h/cIPz0gi...'

# При входе пользователя
user_password = "MySecurePassword123"
if bcrypt.checkpw(user_password.encode(), hashed):
    print("Пароль верный!")

# Важно: два вызова с одинаковым паролем дадут разные хеши
hashed1 = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
hashed2 = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
print(hashed1 == hashed2)  # False!

Почему не просто SHA-256? Потому что SHA-256 быстрая, а хеширование паролей должно быть медленным, чтобы затруднить brute-force атаки.

2. Проверка целостности данных

import hashlib

# Файл, который отправляем
file_content = b"Important data"
file_hash = hashlib.sha256(file_content).hexdigest()
print(f"Hash: {file_hash}")

# Отправляем файл и хеш
# На стороне получателя проверяем:
received_hash = hashlib.sha256(file_content).hexdigest()
if received_hash == file_hash:
    print("Файл не повреждён!")
else:
    print("Файл был повреждён или изменён!")

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

import hashlib
from functools import lru_cache

class CacheWithHash:
    def __init__(self):
        self.cache = {}
    
    def get_hash(self, data: dict) -> str:
        # Создаём уникальный ключ для сложного объекта
        data_str = str(sorted(data.items()))
        return hashlib.md5(data_str.encode()).hexdigest()
    
    def get_or_compute(self, data: dict):
        key = self.get_hash(data)
        
        if key in self.cache:
            return self.cache[key]
        
        result = self.expensive_computation(data)
        self.cache[key] = result
        return result
    
    def expensive_computation(self, data: dict):
        # Дорогостоящая операция
        return sum(data.values()) ** 2

cache = CacheWithHash()
result1 = cache.get_or_compute({"a": 1, "b": 2})
result2 = cache.get_or_compute({"a": 1, "b": 2})  # Берётся из кеша

4. HashMap/Dictionary (в Python это dict)

# Встроенная hash функция в Python
key = "my_key"
print(hash(key))  # Возвращает integer хеш

# Это используется внутри словаря
my_dict = {"key1": "value1", "key2": "value2"}

# Внутри Python вычисляет hash(key) и использует его как индекс
# Это позволяет получать значения за O(1) время
print(my_dict["key1"])  # O(1) доступ благодаря хешированию

5. Digital Signatures (подписи)

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding

# Создаём RSA ключи
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)
public_key = private_key.public_key()

# Документ для подписи
message = b"Important contract"

# Подписываем (используем SHA-256 хеш + RSA)
signature = private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Проверяем подпись
try:
    public_key.verify(
        signature,
        message,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("Подпись верна!")
except:
    print("Подпись не верна!")

6. Blockchain (криптовалюты)

import hashlib
from datetime import datetime

class Block:
    def __init__(self, data: str, previous_hash: str = "0"):
        self.data = data
        self.previous_hash = previous_hash
        self.timestamp = datetime.now().isoformat()
        self.nonce = 0
        self.hash = self.calculate_hash()
    
    def calculate_hash(self) -> str:
        content = f"{self.data}{self.previous_hash}{self.timestamp}{self.nonce}"
        return hashlib.sha256(content.encode()).hexdigest()
    
    def mine_block(self, difficulty: int = 4):
        """Proof of Work: найти хеш начинающийся на N нулей"""
        target = "0" * difficulty
        while not self.hash.startswith(target):
            self.nonce += 1
            self.hash = self.calculate_hash()
        print(f"Блок добыт! Nonce: {self.nonce}, Hash: {self.hash}")

block = Block("Transaction: Alice -> Bob")
block.mine_block(difficulty=3)

Типы хеш-функций

ТипПримерыИспользование
КриптографическиеSHA-256, SHA-512, MD5Пароли, подписи, блокчейн
Non-криптографическиеMurmurHash, CityHashHashMap, кеширование
БыстрыеxxHashBig data обработка
Медленныеbcrypt, scryptХеширование паролей (защита от перебора)

Коллизия хешей

Проблема: Два разных входа могут дать один хеш.

# В теории это возможно, но для SHA-256 практически невозможно
# Попытаться найти коллизию для SHA-256 займёт жизнь вселенной

# Для MD5 уже найдены коллизии (поэтому он deprecated)

Вывод

Хеш-функции — это волшебный инструмент в программировании:

  • Идентификация данных
  • Проверка целостности
  • Быстрый поиск
  • Безопасность

Как разработчик Python, ты каждый день используешь хеши (в dict, при хранении паролей, при проверке целостности файлов), но часто не думаешь об этом. Понимание того, как они работают, помогает писать безопасный и эффективный код.