Dlaczego hasła w bazach danych nie powinny być szyfrowane, tylko haszowane? - Koper - 02-19-2026
1️⃣ Wiele osób myśli:
„Hasło trzeba zaszyfrować.”
To błąd projektowy.
2️⃣ 🔐 Szyfrowanie (encryption) jest odwracalne.
Jeśli ktoś zdobędzie klucz szyfrujący – może odzyskać wszystkie hasła użytkowników w czystej postaci.
3️⃣ 🔑 Haszowanie (hashing) jest jednokierunkowe.
Z funkcji skrótu nie da się odtworzyć oryginalnego hasła (w praktyce obliczeniowej).
4️⃣ Dlatego system przy logowaniu:
– haszuje wpisane hasło
– porównuje hash z tym w bazie
– nigdy nie zna prawdziwego hasła użytkownika
5️⃣ Ale to jeszcze nie wszystko…
Dobre systemy używają:
– saltu (losowa wartość dodana do hasła przed haszowaniem)
– algorytmów odpornych na brute-force, np. bcrypt, Argon2, PBKDF2
6️⃣ Dlaczego to ważne?
Wyciek bazy ≠ wyciek haseł wprost.
Atakujący musi je łamać pojedynczo, co przy dobrze dobranych parametrach może trwać lata.
💡 Ciekawostka historyczna:
Wiele dużych wycieków (np. w pierwszych latach istnienia Facebooka czy LinkedIna) wynikało z używania zbyt szybkich funkcji skrótu typu MD5 czy SHA-1 bez saltu.
RE: Dlaczego hasła w bazach danych nie powinny być szyfrowane, tylko haszowane? - Jarek - 02-22-2026
Przykłady skryptu bezpiecznej rejestracji i logowania do serwisów z haszowaniem haseł na przykładzie mojego serwisu:
Rejestracja konta:
Kod: <?php
// register.php
session_start();
require 'db.php';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 1. Walidacja danych
$username = trim($_POST['username'] ?? '');
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$password_confirm = $_POST['password_confirm'] ?? '';
if (empty($username) || empty($email) || empty($password) || empty($password_confirm)) {
$error = 'Wszystkie pola są wymagane.';
} elseif ($password !== $password_confirm) {
$error = 'Hasła nie pasują do siebie.';
} elseif (strlen($password) < 8) {
$error = 'Hasło musi mieć co najmniej 8 znaków.';
} else {
// 2. Weryfikacja unikalności username/email
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = ? OR email = ?');
$stmt->execute([$username, $email]);
if ($stmt->fetch()) {
$error = 'Nazwa użytkownika lub email jest już zajęta.';
} else {
// 3. Bezpieczne haszowanie hasła
$password_hashed = password_hash($password, PASSWORD_DEFAULT);
// 4. Wstawienie do bazy danych z użyciem Prepared Statements
$stmt = $pdo->prepare('INSERT INTO users (username, email, password) VALUES (?, ?, ?)');
if ($stmt->execute([$username, $email, $password_hashed])) {
// Sukces
$_SESSION['message'] = 'Konto zostało utworzone pomyślnie. Możesz się zalogować.';
header('Location: login.php');
exit();
} else {
$error = 'Wystąpił błąd podczas rejestracji.';
}
}
}
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Rejestracja</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="auth-wrapper bg-primary-custom">
<div class="card-auth">
<h2 class="text-center mb-4">Rejestracja</h2>
<?php if ($error): ?>
<div class="alert alert-danger" role="alert"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<form action="register.php" method="POST">
<div class="form-group">
<label for="username">Nazwa użytkownika</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="email">Adres E-mail</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="form-group">
<label for="password">Hasło</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="form-group">
<label for="password_confirm">Powtórz hasło</label>
<input type="password" class="form-control" id="password_confirm" name="password_confirm" required>
</div>
<button type="submit" class="btn btn-primary btn-block mt-4">Zarejestruj się</button>
<p class="mt-3 text-center">Masz już konto? <a href="login.php" class="text-primary">Zaloguj się</a></p>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
Logowanie:
Kod: <?php
// login.php
session_start();
require 'db.php';
// Jeśli użytkownik jest już zalogowany, przekieruj
if (isset($_SESSION['user_id'])) {
header('Location: index.php');
exit();
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username_or_email = trim($_POST['username_or_email'] ?? '');
$password = $_POST['password'] ?? '';
if (empty($username_or_email) || empty($password)) {
$error = 'Nazwa użytkownika/Email i hasło są wymagane.';
} else {
// 1. Znalezienie użytkownika po nazwie lub emailu
$stmt = $pdo->prepare('SELECT id, username, password FROM users WHERE username = ? OR email = ?');
$stmt->execute([$username_or_email, $username_or_email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
// 2. Sukces logowania - Ustawienie sesji
session_regenerate_id(true); // Kluczowe dla bezpieczeństwa, zapobiega Session Fixation
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header('Location: index.php');
exit();
} else {
// 3. Błąd logowania
$error = 'Nieprawidłowa nazwa użytkownika/adres e-mail lub hasło.';
}
}
}
// Obsługa wiadomości z register.php
$message = $_SESSION['message'] ?? '';
unset($_SESSION['message']);
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Logowanie</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="auth-wrapper bg-primary-custom">
<div class="card-auth">
<h2 class="text-center mb-4">Logowanie</h2>
<?php if ($message): ?>
<div class="alert alert-success" role="alert"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-danger" role="alert"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<form action="login.php" method="POST">
<div class="form-group">
<label for="username_or_email">Nazwa użytkownika lub E-mail</label>
<input type="text" class="form-control" id="username_or_email" name="username_or_email" required>
</div>
<div class="form-group">
<label for="password">Hasło</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-success btn-block mt-4">Zaloguj się</button>
<p class="mt-3 text-center">Nie masz konta? <a href="register.php" class="text-primary">Zarejestruj się</a></p>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>
|