Jump to content

návod PHP pro začátečníky: Tvorba bezpečného kontaktního formuláře se serverovou validací a CSRF


Recommended Posts

  • Uživatel

PHP pro začátečníky: Vytvoření bezpečného kontaktního formuláře s validací a CSRF základy

Tento článek ukazuje, jak postavit jednoduchý PHP backend pro zpracování kontaktního formuláře s důrazem na serverovou validaci, sanitaci vstupů a základní bezpečnostní praktiky (včetně ochrany CSRF a bezpečného odesílání e-mailů). Je určen jak pro začátečníky, tak pro profesionály, kteří chtějí své základy upevnit a ověřit správné postupy na praktické ukázce.

Bezpečné zpracování vstupů na straně serveru

Jako první pravidlo platí: nikdy neuspěcháme se zpracováním dat jen na straně klienta. Formulář může být upraven, hacknut, nebo zneužit. Zpracování vstupů by mělo probíhat na serveru, kde lze důkladně ověřit i ošetřit data před dalším použitím (odesláním e-mailu, uložením do databáze apod.). Základní kroky zahrnují validaci, sanitaci a bezpečné nakládání s výstupy.

Ochrana CSRF a validace vstupů

CSRF (Cross-Site Request Forgery) je útok, při kterém útočník podešle nekalý požadavek za vás. Abychom tomu zabránili, vygenerujeme náhodný token a vložíme ho do formuláře. Při zpracování požadavku pak token ověříme. Společně s CSRF tokenem provádíme také validaci a sanitaci vstupů (jméno, e-mail, zpráva).

<?php
// Základní nastavení CSRF tokenu
session_start();
if (empty($_SESSION['csrf_token'])) {
  // Bezpečný náhodný token
  $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Shromáždění chyb
$errors = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  // Ověření CSRF tokenu
  $postedToken = $_POST['csrf_token'] ?? '';
  if (!isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $postedToken)) {
    $errors[] = 'Neplatný CSRF token.';
  }

  // Získání a sanitace vstupů
  $name    = trim($_POST['name'] ?? '');
  $email   = trim($_POST['email'] ?? '');
  $message = trim($_POST['message'] ?? '');

  // Validace
  if ($name === '') {
    $errors[] = 'Zadejte jméno.';
  }
  if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'Zadejte platný e-mail.';
  }
  if ($message === '' || mb_strlen($message) < 10) {
    $errors[] = 'Zpráva musí obsahovat alespoň 10 znaků.';
  }

  // Sanitace pro výstup do e-mailu / okna
  $name    = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
  $email   = filter_var($email, FILTER_SANITIZE_EMAIL);
  $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');

  if (empty($errors)) {
    // Bezpečné odesílání e-mailu
    $to      = '[email protected]';
    $subject = 'Nová zpráva z kontaktního formuláře';
    $body    = "Jméno: $name\nEmail: $email\n\nZpráva:\n$message";

    // Důležité: From by měl být doménový email odpovídající serveru
    $headers  = "From: Pawno.cz \r\n";
    $headers .= "Reply-To: $email\r\n";
    $headers .= "Content-Type: text/plain; charset=UTF-8";

    if (mail($to, $subject, $body, $headers)) {
      echo 'Zpráva byla odeslána. Děkujeme!';
      // Rotace CSRF tokenu po úspěšném odeslání
      $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    } else {
      $errors[] = 'Nepodařilo se odeslat zprávu. Zkuste to prosím později.';
    }
  }
}
?>  

Další poznámka: i když je PHP mail() funkce jednoduchá, v produkčním prostředí se často doporučuje používat knihovny jako PHPMailer nebo SwiftMailer. Ty poskytují lepší správu odchozích emailů, bezpečnostní hlavičky a lepší viditelnost nad chybami odeslání.

Praktické ukázky kódu

Následují dva jednoduché příklady, které ilustrují principy zpracování formuláře a CSRF tokenů.

HTML formulář s CSRF tokenem

<form action="process_contact.php" method="post">
  <label for="name">Jméno</label>
  <input type="text" id="name" name="name" required />

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required />

  <label for="message">Zpráva</label>
  <textarea id="message" name="message" required></textarea>

  <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES, 'UTF-8'); ?>" />

  <button type="submit">Odeslat</button>
</form>

PHP zpracování formuláře (zkrácená ukázka)

<?php
session_start();
// CSRF token initialization (opět, pokud není)
if (empty($_SESSION['csrf_token'])) {
  $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Předpokládaná zpracovávaná data z POST
$name    = trim($_POST['name'] ?? '');
$email   = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
$postedToken = $_POST['csrf_token'] ?? '';

// CSRF validace
$errors = [];
if (!isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $postedToken)) {
  $errors[] = 'Neplatný CSRF token.';
}

// Validace vstupů
if ($name === '') $errors[] = 'Zadejte jméno.';
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Zadejte platný email.';
if ($message === '' || mb_strlen($message) < 10) $errors[] = 'Zpráva musí mít alespoň 10 znaků.';

if (empty($errors)) {
  // Sanitace pro výstup
  $name    = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
  $email   = filter_var($email, FILTER_SANITIZE_EMAIL);
  $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');

  $to      = '[email protected]';
  $subject = 'Nová zpráva z kontaktního formuláře';
  $body    = "Jméno: $name\nEmail: $email\n\nZpráva:\n$message";

  $headers = "From: Pawno.cz \r\n";
  $headers .= "Reply-To: $email\r\n";
  $headers .= "Content-Type: text/plain; charset=UTF-8";

  if (mail($to, $subject, $body, $headers)) {
    echo 'Zpráva byla odeslána.';
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
  } else {
    $errors[] = 'Chyba při odesílání; zkuste to prosím později.';
  }
}
?>

Tip pro začátečníky: vkládejte CSRF tokeny jen do skrytých polí formuláře a na straně serveru vždy ověřujte tokeny. Důležité je také minimálně sanitizovat vstupy a neukládat nebo nevracet nepřesně zpracované data přímo do HTML bez escapingu. Pokud řešíte složitější e-mailové šablony nebo odesílání na více adres, zvažte použití knihovny jako PHPMailer.

Máte vlastní zkušenosti s bezpečným zpracováním formulářů v PHP? Podělte se o tipy, otázky nebo své zkušenosti v komentářích níže a zapojte se do diskuze s komunitou Pawno.cz!

  • Paráda! (+1) 1
Link to comment
Share on other sites

  • Majitel

Článek jsem rychle zkontroloval a myslím si, že je vše v pořádku - kód jsem však netestoval :) +1 tomu kdo najde případné chyby

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...