Уязвимость ‘Host Header Injection’: Обзор и методы воспроизведения

При использовании HTTPS (TLS+SNI) мы отправляем доменное имя 2 раза:

  1. В SNI для получения сертификата.
  2. Когда сервер расшифрует полученные данные и прочтет в секции header HOST .

Тут у нас возникает Host Header Injection уязвимость.

Как воспроизвести уязвимость

Добавим в index.php код с выводом $_SERVER

var_dump(
$_SERVER['HTTP_HOST']
);

Выполним Host Header Injection через curl команду

curl -v -H "Host: hacker-yoda.com" wp-yoda.com

Если наш сайт подвержен этой уязвимости, в консоли в ответе сайта мы увидим (string) hacker-yoda.com.

Если вы используете $_SERVER['HTTP_HOST'] без обработки для формирования ссылок, редиректов, итд это может быть большой проблемой.

В WordPress само ядро и многие плагины полагаются на $_SERVER['HTTP_HOST'].

Защита от Host Header Injection

  1. Нет ничего лучше чем правильная настройка сервера. Вы можете проксировать в PHP-FPM домен указанный на сервере строкой или в server_name.
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/example.com.crt;
    ssl_certificate_key /path/to/example.com.key;

    root /path/to/your/webroot;
    index index.php index.html index.htm;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTP_HOST $server_name;  # Insatll HTTP_HOST as a value of server_name
        include fastcgi_params;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

или делать проверку что server_name = host

map $ssl_server_name $expected_host {
    hostnames;
    example.com         example.com;
    another-example.com another-example.com;
}

server {
    listen 443 ssl;
    server_name example.com another-example.com;

    if ($host != $expected_host) {
        return 444;
    }

    # Общая конфигурация...
}

Одна из этих конфигураций поможет защититься от атак Host Header Injection, гарантируя, что имя хоста в TLS-рукопожатии (SNI) соответствует ожидаемому заголовку Host в HTTP-запросе.

2. Установить Load-Balancer впереди Nginx/Apache. Это позволит делать проверку сертификатов сделать на Load-Balancer, а дальше отправлять данные по HTTP (незашифрованно) в Nginx по внутрнней сети.

3. Не использовать `$_SERVER[‘HTTP_HOST’]`. Вместо него использовать env variables с заданными вами строками.

К счастью подавляющее большинство хостинговых компаний имеют проверку на стороне сервера. Но с кастомными серверами лучше удосторовериться, что вы настроили все верно.


Андрей Писаревский

Автор: Андрей Писаревский 

PHP | WordPress Team Lead. Имею коммерческий опыт в программировании с 2010 года и экспертизу в полном цикле веб разработки: Frontend, Backend, QA, Server administration, управление крупными командами и Enterprise проектами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *