🧱 Суть

Безопасность веб-приложения – это защита от ситуаций, когда пользователь может:

  • выполнить чужой код
  • получить доступ к чужим данным
  • изменить действия без разрешения
  • повлиять на работу сервера

В PHP основные угрозы, с которыми нужно знать базовый уровень:

  • SQL Injection – внедрение SQL-кода через запросы к БД
  • XSS – выполнение чужого JavaScript в браузере пользователя
  • CSRF – выполнение действий от имени пользователя без его согласия

Схема:

Пользователь
      |

PHP-приложение
      |
      ├── База данных → SQL Injection
      |
      ├── HTML → XSS
      |
      └── Запросы → CSRF

💻 Код

SQL Injection

Что это

SQL Injection – атака, при которой пользовательские данные попадают внутрь SQL-запроса и изменяют его логику.

Проблемный код:

$id = $_GET['id'];
 
$sql = "
SELECT *
FROM users
WHERE id = $id
";

Обычный запрос:

?id=5

Получается:

SELECT *
FROM users
WHERE id = 5

Но злоумышленник может отправить:

?id=5 OR 1=1

И получить:

SELECT *
FROM users
WHERE id = 5 OR 1=1

Условие всегда истинно.

Защита

Использовать подготовленные запросы:

$stmt = $pdo->prepare(
    "
    SELECT *
    FROM users
    WHERE id = ?
    "
);
 
$stmt->execute([$id]);

Теперь данные не могут стать частью SQL-кода.

Правила

Использовать:

  • PDO
  • prepare()
  • execute()

Не использовать:

$sql = "SELECT * FROM users WHERE id=$id";

XSS (Cross-Site Scripting)

Что это

XSS – атака, при которой пользовательский код попадает в HTML-страницу и выполняется в браузере другого пользователя.

Пример:

Пользователь вводит:

<script>
alert('hack')
</script>

Если вывести это напрямую:

echo $_POST['comment'];

браузер выполнит JavaScript.

Где возникает XSS

Частые места:

  • комментарии
  • профили пользователей
  • сообщения
  • поиск
  • любые поля ввода

Опасный код:

echo $username;

Если $username содержит HTML:

<img src=x onerror=alert(1)>

код выполнится.

Защита от XSS

Экранирование HTML

Использовать:

htmlspecialchars();

Пример:

echo htmlspecialchars(
    $username,
    ENT_QUOTES,
    'UTF-8'
);

Теперь:

<script>alert(1)</script>

превратится в:

&lt;script&gt;alert(1)&lt;/script&gt;

Браузер покажет текст, а не выполнит код.

Правило

Данные пользователя нельзя выводить напрямую.

Плохо:

echo $userInput;

Хорошо:

echo htmlspecialchars($userInput);

XSS в JavaScript

Проблема существует и на фронтенде:

Опасно:

element.innerHTML = userInput;

Безопаснее:

element.textContent = userInput;

CSRF (Cross-Site Request Forgery)

Что это

CSRF – атака, когда злоумышленник заставляет пользователя выполнить действие на сайте, где он уже авторизован.

Например:

Пользователь вошёл в банк:

bank.com

У него есть cookie:

session=abc123

Он открывает вредный сайт:

evil.com

Там есть:

<form action="bank.com/transfer">
    <input name="amount" value="10000">
</form>

Браузер автоматически отправляет cookie.

Банк думает:

“Это настоящий пользователь”

Защита от CSRF

  1. CSRF-токен
    Сервер создаёт уникальный токен:
<input
    type="hidden"
    name="csrf"
    value="a8f92..."
>

При отправке:

Форма
+
Токен

Сервер проверяет:

if ($token !== $_SESSION['csrf']) {
    die('Invalid request');
}
  1. SameSite Cookies
    Современные браузеры поддерживают:
setcookie(
    'session',
    $value,
    [
        'samesite' => 'Strict'
    ]
);

Cookie не отправляется при подозрительных запросах.

Общие правила безопасности PHP

  1. Проверять входные данные
    Все данные пользователя потенциально опасны:
$_GET
$_POST
$_COOKIE
$_FILES

Нужно проверять:

  • тип
  • длину
  • формат
  • допустимые значения

Пример:

if (!filter_var(
    $email,
    FILTER_VALIDATE_EMAIL
)) {
    die('Invalid email');
}
  1. Не доверять клиенту
    HTML:
<input maxlength="20">

не является защитой.

Пользователь может отправить запрос вручную:

username=оченьдлиннаястрока

Проверка должна быть на сервере.

  1. Не показывать ошибки пользователю
    Плохо:
echo $exception->getMessage();

Пользователь может увидеть:

SQL connection failed
Table users missing

Лучше:

log_error($exception);
 
echo "Server error";
  1. Использовать HTTPS
    Без HTTPS злоумышленник может перехватить:
  • cookies
  • токены
  • данные формы
  1. Хранить пароли правильно
    Нельзя:
$password = "123456";

или:

password = "123456"

Использовать:

$passwordHash = password_hash(
    $password,
    PASSWORD_DEFAULT
);

Проверка:

password_verify(
    $password,
    $hash
);

Частые ошибки

Выводить данные напрямую

Плохо:

echo $_GET['name'];

Правильно:

echo htmlspecialchars(
    $_GET['name']
);

Склеивать SQL

Плохо:

$sql =
"SELECT * FROM users WHERE id="
.$id;

Правильно:

$stmt = $pdo->prepare(
    "SELECT * FROM users WHERE id=?"
);

Верить скрытым полям формы

Плохо:

<input
    type="hidden"
    value="admin"
/>

Пользователь может изменить его.

Хранить секреты в коде

Плохо:

$password = "database_password";

Лучше:

.env

и переменные окружения.

🎯 Вывод

  • SQL Injection возникает из-за вставки данных пользователя в SQL-код
  • защита → PDO + подготовленные запросы
  • XSS позволяет выполнить чужой JavaScript в браузере
  • защита → экранирование через htmlspecialchars()
  • CSRF заставляет пользователя выполнять действия без его ведома
  • защита → CSRF-токены и безопасные cookies
  • нельзя доверять данным клиента
  • вся валидация должна быть на сервере
  • ошибки нельзя показывать пользователю
  • безопасность – это не одна функция, а набор правильных практик

🔗 Связано