[ui] Opraveny odkazy na registraci a reset hesla v login.php
This commit is contained in:
+18
-49
@@ -26,11 +26,6 @@ if (isset($_SESSION['uzivatel_id'])) {
|
|||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// CSRF TOKEN
|
// CSRF TOKEN
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// CSRF token je náhodný řetězec, který se vygeneruje při načtení
|
|
||||||
// stránky a uloží do session. Formulář ho odešle jako skryté pole.
|
|
||||||
// Při zpracování formuláře ověříme, že token sedí – tím zabráníme
|
|
||||||
// útoku, kdy by cizí web odeslal formulář jménem přihlášeného
|
|
||||||
// uživatele.
|
|
||||||
|
|
||||||
if (empty($_SESSION['csrf_token'])) {
|
if (empty($_SESSION['csrf_token'])) {
|
||||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
@@ -41,29 +36,25 @@ $csrf_token = $_SESSION['csrf_token'];
|
|||||||
// ZPRACOVÁNÍ FORMULÁŘE
|
// ZPRACOVÁNÍ FORMULÁŘE
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
$chyba = ''; // chybová hláška pro uživatele
|
$chyba = '';
|
||||||
$email_hodnota = ''; // předvyplnění emailového pole po chybě
|
$email_hodnota = '';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
|
||||||
// -- Ověření CSRF tokenu ----------------------------------
|
// -- Ověření CSRF tokenu ----------------------------------
|
||||||
$csrf_z_formulare = $_POST['csrf_token'] ?? '';
|
$csrf_z_formulare = $_POST['csrf_token'] ?? '';
|
||||||
// hash_equals porovnává řetězce v konstantním čase –
|
|
||||||
// chrání před timing útoky na CSRF token
|
|
||||||
if (!hash_equals($csrf_token, $csrf_z_formulare)) {
|
if (!hash_equals($csrf_token, $csrf_z_formulare)) {
|
||||||
$chyba = 'Neplatný požadavek. Zkuste stránku obnovit a přihlásit se znovu.';
|
$chyba = 'Neplatný požadavek. Zkuste stránku obnovit a přihlásit se znovu.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($chyba)) {
|
if (empty($chyba)) {
|
||||||
|
|
||||||
// -- Načtení hodnot z formuláře -----------------------
|
$email = trim($_POST['email'] ?? '');
|
||||||
$email = trim($_POST['email'] ?? '');
|
$heslo = $_POST['heslo'] ?? '';
|
||||||
$heslo = $_POST['heslo'] ?? '';
|
|
||||||
$zapamatovat = isset($_POST['zapamatovat']);
|
$zapamatovat = isset($_POST['zapamatovat']);
|
||||||
|
|
||||||
$email_hodnota = htmlspecialchars($email); // pro předvyplnění pole
|
$email_hodnota = htmlspecialchars($email);
|
||||||
|
|
||||||
// -- Základní validace --------------------------------
|
|
||||||
if (empty($email) || empty($heslo)) {
|
if (empty($email) || empty($heslo)) {
|
||||||
$chyba = 'Zadejte email a heslo.';
|
$chyba = 'Zadejte email a heslo.';
|
||||||
}
|
}
|
||||||
@@ -72,9 +63,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if (empty($chyba)) {
|
if (empty($chyba)) {
|
||||||
|
|
||||||
// -- Kontrola brute force -----------------------------
|
// -- Kontrola brute force -----------------------------
|
||||||
// Spočítáme neúspěšné pokusy z této IP adresy
|
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||||
// nebo pro tento email za poslední časové okno
|
|
||||||
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
|
||||||
$okno_od = date('Y-m-d H:i:s', time() - BRUTE_OKNO);
|
$okno_od = date('Y-m-d H:i:s', time() - BRUTE_OKNO);
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
@@ -91,7 +80,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$pocet_pokusu = $stmt->fetch()['pocet'];
|
$pocet_pokusu = $stmt->fetch()['pocet'];
|
||||||
|
|
||||||
if ($pocet_pokusu >= BRUTE_MAX_POKUSU) {
|
if ($pocet_pokusu >= BRUTE_MAX_POKUSU) {
|
||||||
// Nezradíme přesný důvod – jen obecná hláška
|
|
||||||
$chyba = 'Příliš mnoho neúspěšných pokusů. Zkuste to prosím za chvíli.';
|
$chyba = 'Příliš mnoho neúspěšných pokusů. Zkuste to prosím za chvíli.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,17 +96,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$stmt->execute([':email' => $email]);
|
$stmt->execute([':email' => $email]);
|
||||||
$uzivatel = $stmt->fetch();
|
$uzivatel = $stmt->fetch();
|
||||||
|
|
||||||
// Ověříme heslo pomocí password_verify().
|
// I když uživatel neexistuje, zavoláme password_verify na fiktivní
|
||||||
// DŮLEŽITÉ: I když uživatel neexistuje, zavoláme
|
// hash – aby útočník nemohl podle doby odpovědi poznat, zda email existuje
|
||||||
// password_verify na fiktivní hash – aby útočník
|
$fiktivni_hash = '$2y$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
||||||
// nemohl podle doby odpovědi poznat, zda email existuje.
|
|
||||||
$fiktivni_hash = '$2y$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
|
||||||
$hash_k_overeni = $uzivatel ? $uzivatel['heslo'] : $fiktivni_hash;
|
$hash_k_overeni = $uzivatel ? $uzivatel['heslo'] : $fiktivni_hash;
|
||||||
$heslo_ok = password_verify($heslo, $hash_k_overeni);
|
$heslo_ok = password_verify($heslo, $hash_k_overeni);
|
||||||
|
|
||||||
if (!$uzivatel || !$heslo_ok) {
|
if (!$uzivatel || !$heslo_ok) {
|
||||||
|
|
||||||
// Přihlášení selhalo – zapíšeme neúspěšný pokus
|
// Zapíšeme neúspěšný pokus
|
||||||
$stmt2 = $pdo->prepare("
|
$stmt2 = $pdo->prepare("
|
||||||
INSERT INTO `" . DB_TABULKA_BRUTE . "`
|
INSERT INTO `" . DB_TABULKA_BRUTE . "`
|
||||||
(`ip_adresa`, `email`)
|
(`ip_adresa`, `email`)
|
||||||
@@ -130,38 +116,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
':email' => $email,
|
':email' => $email,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Obecná hláška – neříkáme, zda byl špatný email nebo heslo
|
|
||||||
$chyba = 'Nesprávný email nebo heslo.';
|
$chyba = 'Nesprávný email nebo heslo.';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// -- Přihlášení úspěšné ---------------------------
|
// -- Přihlášení úspěšné ---------------------------
|
||||||
|
|
||||||
// Regenerujeme session ID – ochrana před session fixation
|
|
||||||
// (útočník mohl podstrčit uživateli konkrétní session ID)
|
|
||||||
session_regenerate_id(true);
|
session_regenerate_id(true);
|
||||||
|
|
||||||
// Zapíšeme uživatele do session
|
|
||||||
$_SESSION['uzivatel_id'] = $uzivatel['id'];
|
$_SESSION['uzivatel_id'] = $uzivatel['id'];
|
||||||
$_SESSION['email'] = $uzivatel['email'];
|
$_SESSION['email'] = $uzivatel['email'];
|
||||||
$_SESSION['admin'] = (bool) $uzivatel['admin'];
|
$_SESSION['admin'] = (bool) $uzivatel['admin'];
|
||||||
$_SESSION['posledni_aktivita'] = time();
|
$_SESSION['posledni_aktivita'] = time();
|
||||||
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
// Vygenerujeme nový CSRF token pro další požadavky
|
|
||||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
||||||
|
|
||||||
// -- Remember me ----------------------------------
|
// -- Remember me ----------------------------------
|
||||||
if ($zapamatovat) {
|
if ($zapamatovat) {
|
||||||
|
|
||||||
// Selector = veřejný identifikátor (jde do cookie i DB)
|
$selector = bin2hex(random_bytes(16));
|
||||||
// Token = tajný řetězec (do cookie jde plaintext,
|
$token = bin2hex(random_bytes(32));
|
||||||
// do DB jen bcrypt hash)
|
$token_hash = password_hash($token, PASSWORD_DEFAULT);
|
||||||
$selector = bin2hex(random_bytes(16)); // 32 znaků hex
|
$expiruje = date('Y-m-d H:i:s', time() + REMEMBER_EXPIRACE);
|
||||||
$token = bin2hex(random_bytes(32)); // 64 znaků hex
|
|
||||||
$token_hash = password_hash($token, PASSWORD_DEFAULT);
|
|
||||||
$expiruje = date('Y-m-d H:i:s', time() + REMEMBER_EXPIRACE);
|
|
||||||
|
|
||||||
// Uložíme token do DB
|
|
||||||
$stmt3 = $pdo->prepare("
|
$stmt3 = $pdo->prepare("
|
||||||
INSERT INTO `" . DB_TABULKA_TOKENY . "`
|
INSERT INTO `" . DB_TABULKA_TOKENY . "`
|
||||||
(`uzivatel_id`, `selector`, `token_hash`, `expiruje`)
|
(`uzivatel_id`, `selector`, `token_hash`, `expiruje`)
|
||||||
@@ -175,9 +150,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
':expiruje' => $expiruje,
|
':expiruje' => $expiruje,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Nastavíme cookie v prohlížeči
|
|
||||||
// Cookie obsahuje POUZE selector a token – žádné heslo,
|
|
||||||
// žádné ID, žádný příznak admin
|
|
||||||
$cookie_expirace = time() + REMEMBER_EXPIRACE;
|
$cookie_expirace = time() + REMEMBER_EXPIRACE;
|
||||||
setcookie('auth_selector', $selector, [
|
setcookie('auth_selector', $selector, [
|
||||||
'expires' => $cookie_expirace,
|
'expires' => $cookie_expirace,
|
||||||
@@ -196,8 +168,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -- Přesměrování po přihlášení -------------------
|
// -- Přesměrování po přihlášení -------------------
|
||||||
// Pokud byl uživatel přesměrován z jiné stránky,
|
|
||||||
// vrátíme ho tam. Jinak jde na výchozí stránku.
|
|
||||||
$redirect = $_SESSION['redirect_po_prihlaseni'] ?? AUTH_REDIRECT_PO_PRIHLASENI;
|
$redirect = $_SESSION['redirect_po_prihlaseni'] ?? AUTH_REDIRECT_PO_PRIHLASENI;
|
||||||
unset($_SESSION['redirect_po_prihlaseni']);
|
unset($_SESSION['redirect_po_prihlaseni']);
|
||||||
|
|
||||||
@@ -231,7 +201,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
<form method="POST" action="">
|
<form method="POST" action="">
|
||||||
|
|
||||||
<!-- CSRF token – skryté pole, ověřuje se při odeslání formuláře -->
|
|
||||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token); ?>">
|
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token); ?>">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -271,10 +240,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<?php if (REGISTRACE_OTEVRENA): ?>
|
<?php if (REGISTRACE_OTEVRENA): ?>
|
||||||
<p><a href="<?php echo htmlspecialchars(__DIR__); ?>/registrace.php">Nemáš účet? Zaregistruj se.</a></p>
|
<p><a href="<?php echo htmlspecialchars(AUTH_REGISTRACE_URL); ?>">Nemáš účet? Zaregistruj se.</a></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<p><a href="<?php echo htmlspecialchars(__DIR__); ?>/reset_hesla.php">Zapomněl jsi heslo?</a></p>
|
<p><a href="<?php echo htmlspecialchars(AUTH_RESET_URL); ?>">Zapomněl jsi heslo?</a></p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user