Вопрос или проблема
Мы используем прокси Cloudflare, поэтому настоящий IP скрыт. Но если вы узнаете настоящий IP, вы все равно можете получить доступ к сайту, используя его. Есть ли способ ограничить доступ по этому IP?
Я имею в виду:
по домену: https://some-domain.com -> ОК
по прокси IP: https://1.2.3.4 -> ОК
по реальному IP: https://5.6.7.8 -> ограничить.
Или бессмысленно пытаться ограничить его?
Пример серверных блоков nginx.conf:
server {
listen 80 default_server;
server_name some-domain.com;
return 301 https://$host$request_uri;
}
charset utf-8;
server {
server_name some-domain.com;
listen 443 ssl http2;
...
...
}
Вы смешиваете две разные вещи здесь. Первое — это ограничение доступа для клиентов, у которых в запросах не установлен правильный заголовок Host
(это обычно боты, сетевые сканеры и т.д.). Для этого вам нужен какой-то блок сервера типа catch-all, чтобы отклонять такие запросы. Обратитесь к этому ответу на StackOverflow для примеров.
Второе — это ограничение запросов с правильным заголовком Host
, но исходящих из источников, отличных от серверов, находящихся на периферии сети Cloudflare. Это, как правило, хорошая практика, так как Cloudflare действует как анти-DDoS (и, возможно, WAF) услуга для вашего сайта. Официальный список диапазонов IP-адресов Cloudflare доступен на их сайте: IP Ranges, или в виде простого текста по адресам IPv4 и IPv6. Вы можете использовать этот список, чтобы отклонять такие запросы с помощью ngx_http_geo_module
следующим образом:
geo $denied {
default 1;
173.245.48.0/20 0;
103.21.244.0/22 0;
...
}
server {
server_name some-domain.com;
listen 443 ssl http2;
if ($denied) {
# незамедлительно завершить запрос
return 444;
}
...
Список диапазонов IP обновляется периодически, так что я использую следующий скрипт для автоматической генерации списка диапазонов:
#!/bin/sh
{
echo "# Cloudflare IP ranges - generated on $(date)"
curl -s https://www.cloudflare.com/ips-v4/ | sed 's/$/ 0;/'
echo # просто пустая строка
curl -s https://www.cloudflare.com/ips-v6/ | sed 's/$/ 0;/'
echo # еще одна пустая строка
} > /etc/nginx/cloudflare.inc
Затем вы можете включить этот список в вашу конфигурацию nginx следующим образом:
geo $denied {
default 1;
include cloudflare.inc;
# вы можете добавить сюда дополнительные IP-адреса
# (как я иногда добавляю свои домашние/рабочие IP)
}
Вы также можете использовать список диапазонов IP, чтобы восстановить оригинальные IP посетителей (см. официальную статью Cloudflare “Восстановление оригинальных IP посетителей” для деталей). Вообще, в последнее время я использую другой скрипт для автоматической генерации двух файлов:
#!/bin/bash
echo "# Cloudflare IP ranges - generated on $(date)" | tee /etc/nginx/cloudflare.inc > /etc/nginx/real_ip.inc
curl -s https://www.cloudflare.com/ips-v4/ | tee >(sed 's/$/ 0;/' >> /etc/nginx/cloudflare.inc) | sed 's/^/set_real_ip_from /; s/$/;/' >> /etc/nginx/real_ip.inc
echo >> /etc/nginx/cloudflare.inc # Пустая строка для cloudflare.inc
echo >> /etc/nginx/real_ip.inc # Пустая строка для real_ip.inc
curl -s https://www.cloudflare.com/ips-v6/ | tee >(sed 's/$/ 0;/' >> /etc/nginx/cloudflare.inc) | sed 's/^/set_real_ip_from /; s/$/;/' >> /etc/nginx/real_ip.inc
echo >> /etc/nginx/cloudflare.inc # Еще одна пустая строка для cloudflare.inc
echo >> /etc/nginx/real_ip.inc # Еще одна пустая строка для real_ip.inc
Второй файл будет содержать записи в следующем формате:
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
...
Вы можете использовать этот файл следующим образом:
server {
server_name some-domain.com;
listen 443 ssl http2;
if ($denied) {
# незамедлительно завершить запрос
return 444;
}
include real_ip.inc;
real_ip_header CF-Connecting-IP;
...
Могут быть случаи, когда такая настройка необходима (вот проблема, с которой я однажды столкнулся). Однако, если вы используете эту конфигурацию, помните, что переменная $remote_addr
, которая используется по умолчанию в блоке geo
для проверки совпадения IP-адреса с заданными диапазонами, более не будет содержать адрес сервера Cloudflare. Вместо этого, вам нужно будет явно указать переменную $realip_remote_addr
:
geo $realip_remote_addr $denied {
default 1;
include cloudflare.inc;
...
}
Ответ или решение
Ограничение доступа по IP в Nginx для работы с Cloudflare
Проблема: Вы используете прокси-сервер Cloudflare, из-за чего реальный IP-адрес пользователя скрыт. Однако если реальный IP-адрес известен, он может быть использован для доступа к вашему сайту напрямую. Вам необходимо ограничить доступ, чтобы запросы могли проходить только через разрешенные IP-адреса (например, прокси-сервера Cloudflare).
Решение:
-
Ограничение доступа по IP-адресу:
Используйте модульngx_http_geo_module
, чтобы разрешать доступ только с IP-адресов, принадлежащих циклу IP Cloudflare. Например, можно сделать это следующим образом:geo $denied { default 1; 173.245.48.0/20 0; 103.21.244.0/22 0; ... } server { server_name some-domain.com; listen 443 ssl http2; if ($denied) { return 444; # Прерывание запроса } ... }
-
Автоматизация обновления IP-диапазонов Cloudflare:
IP-диапазоны Cloudflare регулярно обновляются, поэтому рекомендуется автоматизировать процесс их обновления. Пример скрипта:#!/bin/bash echo "# Cloudflare IP ranges - generated on $(date)" | tee /etc/nginx/cloudflare.inc > /etc/nginx/real_ip.inc curl -s https://www.cloudflare.com/ips-v4/ | tee >(sed 's/$/ 0;/' >> /etc/nginx/cloudflare.inc) | sed 's/^/set_real_ip_from /; s/$/;/' >> /etc/nginx/real_ip.inc echo >> /etc/nginx/cloudflare.inc echo >> /etc/nginx/real_ip.inc curl -s https://www.cloudflare.com/ips-v6/ | tee >(sed 's/$/ 0;/' >> /etc/nginx/cloudflare.inc) | sed 's/^/set_real_ip_from /; s/$/;/' >> /etc/nginx/real_ip.inc echo >> /etc/nginx/cloudflare.inc echo >> /etc/nginx/real_ip.inc
Используйте данный скрипт для регулярного обновления файлов
/etc/nginx/cloudflare.inc
и/etc/nginx/real_ip.inc
. -
Восстановление реального IP-пользователя:
Используйте директивуreal_ip_header
и включайте файл с IP-адресами Cloudflare, чтобы Nginx принимал заголовокCF-Connecting-IP
как реальный IP пользователя:server { server_name some-domain.com; listen 443 ssl http2; if ($denied) { return 444; } include real_ip.inc; real_ip_header CF-Connecting-IP; ... }
-
Учет переменной
$realip_remote_addr
:
При использовании восстановления IP важно изменить условиеgeo
, чтобы использовать переменную$realip_remote_addr
вместо$remote_addr
:geo $realip_remote_addr $denied { default 1; include cloudflare.inc; ... }
Заключение: Такой подход обеспечивает защиту сайта от прямого доступа с реальных IP-адресов пользователей, обеспечивая безопасность и приватность. Он также позволяет использовать Cloudflare в качестве эффективного средства защиты от DDoS-атак и других угроз.