Новое в Symfony 5.1: Защита от подделки запросов на стороне сервера

Уязвимости безопасности, такие как CSRF (подделка межсайтовых запросов), хорошо известны большинству веб-разработчиков, и Symfony обеспечивает автоматическую защиту от них. Связанная, но менее известная уязвимость называется SSRF (подделка запросов на стороне сервера).

SSRF позволяет злоумышленнику заставить серверное приложение отправлять HTTP-запросы в произвольный домен. Эти атаки также могут быть направлены на внутренние хосты и IP-адреса атакованного сервера. Следующий упрощенный пример был извлечен из этой статьи, которая подробно объясняет проблему:

Шаг 1: Ваш бэкэнд админки доступна, но только с внутренних IP-адресов (например, https://192.168.0.68/admin).

Шаг 2: Ваше веб-приложение отправляет API-запросы, подобные следующим, чтобы получить определенную информацию (например, информацию о товареку):

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=https://stock.weliketoshop.net:8080/product/stock/check%3FproductId%3D6%26storeId%3D1

Шаг 3: Злоумышленник может отправить следующий запрос для доступа к администратору бэкэнда:

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=https://192.168.0.68/admin

Решение, как это происходит со многими уязвимостями безопасности, требует фильтрации пользовательского ввода (в данном случае IP-адрес, запрошенный пользователем). В Symfony 5.1 улучшили компонент HttpClient, добавив новый NoPrivateNetworkHttpClient, который по умолчанию блокирует все внутренние IP-адреса.

Этот новый клиент украшает HttpClient по умолчанию, поэтому вы можете использовать его следующим образом:

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient;

$client = new NoPrivateNetworkHttpClient(HttpClient::create());
// nothing changes when requesting public networks
$client->request('GET', 'https://example.com/');

// however, all requests to private networks are now blocked by default
$client->request('GET', 'http://localhost/');

// the second optional argument defines the networks to block
// in this example, requests from 104.26.14.0 to 104.26.15.255 will result in an exception
// but all the other requests, including other internal networks, will be allowed
$client = new NoPrivateNetworkHttpClient(HttpClient::create(), ['104.26.14.0/23']);