Chcesz nauczyć się, jak w praktyce zabezpieczyć stronę internetową przed nieautoryzowanym dostępem? Mamy tutaj proste rozwiązanie, w postaci krótkiego poradnika a mowa o mechanizmie sesji w PHP. Dzięki przykładowi, jaki tutaj opisałem, dowiesz się, czym są sesje w PHP, dlaczego są ważne i jak poprawnie je zaimplementować w swoim kodzie.
Sesje w PHP to mechanizm, który pozwala przechowywać dane użytkownika pomiędzy żądaniami HTTP. Dzięki nim można np. zapamiętać, że ktoś jest zalogowany i nie wymaga ponownego wpisywania hasła na każdej podstronie.
Zalety sesji w PHP:
- Bezpieczeństwo – sesje są przechowywane po stronie serwera, co utrudnia ich przechwycenie przez atakujących.
- Personalizacja – pozwalają na dostosowanie zawartości strony do konkretnego użytkownika.
- Łatwość obsługi – PHP zapewnia wbudowane funkcje do zarządzania sesjami, co ułatwia ich implementację.
Dobre praktyki związane z sesjami:
- Unikaj przechowywania wrażliwych danych w sesji (np. haseł, numerów kart kredytowych).
- Regeneruj identyfikator sesji po zalogowaniu, aby zapobiec atakom typu session fixation.
- Ustaw czas ważności sesji i usuwaj je po wylogowaniu użytkownika.
- Używaj tylko HTTPS, aby zabezpieczyć dane sesji przed przechwyceniem.
Stwórzmy więc system logowania, zabezpieczmy hasła użytkowników oraz zadbajmy o przekierowania w przypadku próby wejścia na stronę bez logowania (wejścia nieautoryzowane, stanowiące potencjalne zagrożenie).
1. Tworzenie bazy danych i tabeli użytkowników
Zacznijmy od utworzenia bazy danych i tabeli użytkowników. Wykorzystamy MySQL oraz bezpieczne przechowywanie haseł za pomocą funkcji password_hash()
, która służy do bezpiecznego hashowania haseł użytkowników.
password_hash()
działa w taki sposób, że zamienia podane hasło na unikalny ciąg znaków (hash), korzystając z algorytmu bcrypt lub innego dostępnego w PHP. Dzięki temu zapisane hasło jest niemożliwe do odczytania w bazie danych.
Podczas logowania porównujemy wprowadzone hasło użytkownika z jego zapisanym odpowiednikiem w bazie przy użyciu funkcji password_verify()
, co pozwala na weryfikację poprawności hasła bez jego bezpośredniego przechowywania.
Tworzenie bazy danych i tabeli użytkowników
CREATE DATABASE secure_login;
USE secure_login;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
Pewnie zastanawiasz się, czym jest zapis USE secure_login;
to polecenie SQL, które wskazuje serwerowi MySQL, że wszystkie kolejne operacje na bazie danych mają być wykonywane w kontekście bazy secure_login
. Innymi słowy, przełącza aktywną bazę danych na secure_login
, co oznacza, że każda następna komenda, taka jak CREATE TABLE
czy SELECT
, będzie odnosić się właśnie do tej bazy, o ile nie zostanie podana inna.
Bez tego polecenia, jeśli mamy wiele baz danych na serwerze, MySQL nie wiedziałby, w której bazie powinien wykonać daną operację.
Teraz dodajmy użytkownika admin
z hasłem admin123
, zabezpieczonym przy użyciu password_hash()
.
Dodanie użytkownika admin
Dodawanie użytkownika przez PHP zamiast ręcznie w bazie danych jest istotne z kilku powodów:
-
Bezpieczeństwo – Jeśli dodasz użytkownika przez PHP, możesz użyć
password_hash()
, co zapewnia bezpieczne hashowanie hasła. Wpisanie hasła bezpośrednio do bazy danych bez hashowania oznaczałoby, że jest ono przechowywane w postaci jawnej, co jest poważnym zagrożeniem bezpieczeństwa. -
Automatyzacja – W prawdziwych systemach użytkownicy rejestrują się sami, a aplikacja dodaje ich do bazy dynamicznie. Ręczne dodawanie użytkowników nie jest praktyczne, zwłaszcza gdy liczba użytkowników rośnie.
-
Ochrona przed błędami – Podczas ręcznego dodawania można przypadkowo wpisać błędne dane lub użyć nieprawidłowego formatu. Kod PHP dba o to, by dane były poprawne i zgodne z założeniami aplikacji.
-
Łatwość zarządzania – Użycie PHP do dodawania użytkowników oznacza, że można łatwo rozbudować system o panel administratora do zarządzania użytkownikami.
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "secure_login";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Błąd połączenia: " . $conn->connect_error);
}
$hashed_password = password_hash("admin123", PASSWORD_DEFAULT);
$sql = "INSERT INTO users (username, password) VALUES ('admin', '$hashed_password')";
if ($conn->query($sql) === TRUE) {
echo "Użytkownik admin został dodany.";
} else {
echo "Błąd: " . $conn->error;
}
$conn->close();
?>
Po wywołaniu skryptu, w bazie danych możemy sprawdzić, że użytkownik został dodany, oraz jego hasło (dla przykładu admin123) zostało zahashowane
2. Tworzenie formularza logowania (login.php)
Stworzymy prosty formularz logowania, który przesyła dane metodą POST do skryptu login.php
.
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Logowanie</title>
</head>
<body>
<h2>Logowanie</h2>
<form action="login.php" method="POST">
<label for="username">Login:</label>
<input type="text" name="username" required>
<br>
<label for="password">Hasło:</label>
<input type="password" name="password" required>
<br>
<button type="submit">Zaloguj</button>
</form>
</body>
</html>
3. Obsługa logowania i tworzenie sesji (login.php)
Teraz napiszemy kod do weryfikacji logowania i inicjalizacji sesji użytkownika.
<?php
session_start();
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "secure_login";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Błąd połączenia: " . $conn->connect_error);
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $conn->prepare("SELECT id, password FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($id, $hashed_password);
$stmt->fetch();
if ($stmt->num_rows > 0 && password_verify($password, $hashed_password)) {
$_SESSION['user_id'] = $id;
$_SESSION['username'] = $username;
header("Location: index.php");
exit();
} else {
echo "Nieprawidłowy login lub hasło.";
}
$stmt->close();
}
$conn->close();
?>
Oto wyjaśnienie działania kodu:
-
Inicjalizacja sesji –
session_start();
uruchamia mechanizm sesji, co pozwala na przechowywanie informacji o użytkowniku między kolejnymi żądaniami HTTP. -
Łączenie z bazą danych:
- Ustawiane są parametry połączenia (
$servername
,$username
,$password
,$dbname
). - Tworzony jest nowy obiekt
mysqli
, który odpowiada za połączenie z bazą danych. - Jeśli wystąpi błąd połączenia, skrypt zwraca komunikat o błędzie i zatrzymuje dalsze wykonywanie (
die()
).
- Ustawiane są parametry połączenia (
-
Obsługa żądania POST:
- Sprawdzane jest, czy dane zostały przesłane metodą POST (
if ($_SERVER["REQUEST_METHOD"] == "POST")
). - Pobierane są dane z formularza (
$_POST['username']
i$_POST['password']
).
- Sprawdzane jest, czy dane zostały przesłane metodą POST (
-
Zapytanie do bazy danych:
- Tworzone jest przygotowane zapytanie SQL do wyszukania użytkownika o podanej nazwie (
$stmt = $conn->prepare("SELECT id, password FROM users WHERE username = ?")
). bind_param("s", $username);
wiąże podany login z parametrem SQL, zabezpieczając przed SQL Injection.execute();
wykonuje zapytanie.store_result();
przechowuje wynik zapytania, co pozwala na sprawdzenie, czy użytkownik istnieje.bind_result($id, $hashed_password);
przypisuje wyniki zapytania do zmiennych.fetch();
pobiera wynik z bazy danych.
- Tworzone jest przygotowane zapytanie SQL do wyszukania użytkownika o podanej nazwie (
-
Weryfikacja hasła:
password_verify($password, $hashed_password);
porównuje hasło wpisane przez użytkownika z zaszyfrowanym hasłem w bazie.- Jeśli hasło jest poprawne:
- Tworzone są zmienne sesyjne (
$_SESSION['user_id']
,$_SESSION['username']
). - Użytkownik zostaje przekierowany do
index.php
.
- Tworzone są zmienne sesyjne (
- Jeśli hasło jest błędne lub użytkownik nie istnieje, wyświetla się komunikat
Nieprawidłowy login lub hasło.
.
-
Zamykanie połączenia:
$stmt->close();
zamyka przygotowane zapytanie.$conn->close();
zamyka połączenie z bazą.
Dzięki temu kodowi użytkownik może się zalogować, a jego dane sesyjne będą przechowywane, umożliwiając mu dostęp do chronionych stron.
4. Zabezpieczenie strony głównej (index.php)
Jeśli użytkownik nie jest zalogowany, przekierujemy go na stronę logowania.
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Panel użytkownika</title>
</head>
<body>
<h2>Witaj, <?php echo htmlspecialchars($_SESSION['username']); ?>!</h2>
<a href="logout.php">Wyloguj</a>
</body>
</html>
5. Wylogowanie użytkownika (logout.php)
Aby umożliwić użytkownikowi wylogowanie, dodajmy skrypt logout.php
, który usunie dane sesji.
<?php
session_start();
session_unset();
session_destroy();
header("Location: login.php");
exit();
?>
Ten kod realizuje funkcję wylogowania użytkownika poprzez usunięcie jego sesji i przekierowanie go na stronę logowania. Oto jego działanie krok po kroku:
-
session_start();
– Rozpoczyna lub wznawia sesję, co jest konieczne do manipulowania danymi sesji. -
session_unset();
– Usuwa wszystkie zmienne sesyjne. Nie kończy samej sesji, ale czyści wszystkie zapisane w niej dane. -
session_destroy();
– Niszczy całą sesję, usuwając jej identyfikator oraz wszystkie związane z nią dane po stronie serwera. -
header("Location: login.php");
– Przekierowuje użytkownika na stronę logowania po zniszczeniu sesji, co oznacza, że użytkownik musi zalogować się ponownie, aby uzyskać dostęp do chronionych stron. -
exit();
– Zapewnia, że skrypt zakończy działanie natychmiast po przekierowaniu, uniemożliwiając wykonanie dodatkowego kodu.
To proste, ale skuteczne rozwiązanie zapewnia, że po wylogowaniu użytkownik traci dostęp do stron wymagających aktywnej sesji.
Podsumujmy więc cały mechanizm obsługi Sesji w PHP
Stworzyliśmy prosty i bezpieczny system logowania w PHP z wykorzystaniem MySQL. Kluczowe kroki:
- Tworzenie bazy danych i tabeli użytkowników.
- Zabezpieczenie haseł funkcją
password_hash()
. - Tworzenie formularza logowania i weryfikacja danych.
- Implementacja sesji w PHP.
- Zabezpieczenie stron przed nieautoryzowanym dostępem.
- Możliwość wylogowania użytkownika.
Teraz masz gotowy szkielet do rozbudowy systemu logowania w Twojej aplikacji!
Jak zabezpieczyć kolejne pliki mechanizmem sesji?
Aby zabezpieczyć inne strony, wystarczy dodać na początku każdego pliku następujący kod:
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
?>
Dzięki temu każda strona będzie sprawdzać, czy użytkownik jest zalogowany. Jeśli nie – zostanie przekierowany na stronę logowania.