модуль nginx geoip, защита от ddos

Собственно зачем вообще запрещать доступ к сайту по географическому признаку ? Да просто 80% IP адресов участвующих в ddos атаке, как правило принадлежат странам, жители которых никогда не зайдут на данный сайт, естественно это сугубо индивидуально для каждого ресурса и если вы знаете что часть ваших посетителей приходит из Эфиопии или Чили, блокировать их, вы вряд-ли захотите. У большинства-же моих клиентов, географическое расположение посетителей, как правило ограничивается Европой и бывшим СССР, остальных можно смело игнорировать.

Описываемый способ блокировки неугодных стран с помощью веб сервера nginx и geoip модуля, в одиночку, и тем более целиком, проблему никак не решит, это лишь одна, из целого ряда всевозможных мер ( настройка ядра, фаервола, штатных сервисов, дополнительного софта ), по минимизации вреда, наносимого данным видом атаки серверу и сайтам, на нем расположенным.

Проекты, часто нуждающиеся в подобного рода защите, я по возможности стараюсь изначально поднимать без участия веб сервера apache, то есть на связке nginx - fastcgi.

Итак, ставить и настраивать все это хозяйство будем на сервере под управлением операционной системы FreeBSD 8.2 and64.

Что-бы модуль geoip заработал, потребуется дополнительная библиотека, ставим:

freebsd82 /usr/ports# make -C net/GeoIP install clean

Далее ставим nginx:

freebsd82 /usr/ports# make -C www/nginx install clean

в опциях сборки нужно включить geoip модуль nginx, поставив галку напротив пункта Enable http_geoip module.

Далее идем на страницу ]]>http://www.maxmind.com/app/geolitecountry]]> и скачиваем latest GeoLite Country Binary Format, это бесплатный вариант базы стран и соответствующих им блоков IP адресов. Распаковываем архив и кидаем файл GeIP.dat в папку /usr/local/etc/nginx/conf/geo. Осталось отредактировать конфиги nginx.

Открываем nginx.conf, дописываем в секцию http следующий блок директив:

geoip_country /usr/local/etc/nginx/conf/geo/GeoIP.dat; # подключаем GeIP базу
map $geoip_country_code $bad_country { # модуль map создает переменные, значения которых зависят от других переменных, очень полезная штука
	default 1; # значение по умолчанию
	include geo/good_countries; # инклудим файл, к нему вернемся чуть позже
}

Этот блок map, означает, что все страны находящиеся в базе данных, являются запрещенными по умолчанию, а в файле good_countries, будут перечислены разрешенные страны. Если у вас например ситуация, когда разрешенных стран больше чем запрещенных, можно легко инвертировать данную логику и создать файл bad_countries со списком запрещенных стран, разрешив все остальные.

Теперь настройки хоста. Я предпочитаю держать хосты в отдельной папке, например hosts, каждый в своем файле.

server {
	listen       IP:80;
	server_name  testhost.com;

	if ($bad_country){ # если данная переменная установлена, то есть если страна не перечислена в файле good_countries
		return 444; # выдаем клиенту пустой ответ ( незачем отдавать 403 ошибку или еще какую-либо )
	}
.................
.................
}

Теперь вернемся к файлу good_countries. Тут все предельно просто, страны, которым разрешен доступ на сайт, перечислены в следующем формате:

TM 0;
UA 0;
UZ 0;
RU 0;
.......
.......
и т.д.

То есть, что-бы разрешить какую-либо страну, достаточно добавить ее двухбуквенный код и 0, после чего перезагрузить конфиг nginx:

freebsd82 /# nginx -s reload

Сами коды стран, на раз два, находятся через гугл.

Проверить, работает geoip модуль или нет, можно, удалив из списка разрешенных стран свою, и попробовав зайти на сайт.

Собственно такова общая схема использования geoip модуля nginx для защиты от ddos атак.

Естественно можно придумать массу других вариантов применения данного модуля для решения различных задач связанных с географическим расположением посетителя сайта.

Комментарии

Хорошая статья, но вот "FreeBSD 8.2 and64" порадовала :-)

ой, да, забавно получилось )))))

А если ДДОСят из России и сайт рассчитан, что основная масса пользователей из России, что тогда? Или обычно ддосят из за бугра?

тогда этот метод конечно не катит, но преимущественно лупят как раз с IP какого нить Катара. Филлипин и т.д.
ну во всяком случае на моей практике, это так
в этом плане способ не универсален, применительно именно к ддосу

ддос из России обойдется дороже чем заграничный, с большой вероятностью метод поможет

Спасибо! Хорошая статья! Очень помогло в решении некоторых вопросов :)

пожалуйста)

А не получится так что nginx занятый отдаванием ответа 444 на блокированные адреса (в случае ддоса) будет перегружен. Ведь на ответ сервера все равно требуются ресурсы системы. И сайт будет "лагать".

444 No Response (Nginx)
Used in Nginx logs to indicate that the server has returned no information to the client and closed the connection (useful as a deterrent for malware).

то есть, это пустышка, никаких данных клиенту не передается, соединение просто закрывается
во всяком случае я никогда не сталкивался с лагами nginx'а, связанными с отдачей ошибок

ааа, все понял. Просто я только начинаю осваивать nginx и поэтому таких тонкостей не знаю. Еще раз спасибо!

Супер вещь, попробовал, работает, только вопрос. Я оставил страну только RU , но в логах вижу айпишник гугл бота US и ещё несколько IP с US Как можно проверить эту реализацию на конкретный IP адрес ?

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

locaion /test {
  if ($bad_country){
     return 403; # для наглядности
  }
}

Да, я так и сделал. Работает. Но в логах httpd access log вижу, что некоторые с IP из USA заходят. В частности Googlebot, хотя разрешения на US нет. Если я правильно понимаю, он должен был его сбросить и не пустить. Вопрос почему пропустил?

может БД не совсем актуальна ?

файл Geoip.dat скачал вчера новый. Может в бесплатной версии этого файла не вся база присутствует?

стоп, так запрос и должен светиться в акцесс логе, другой вопрос, что nginx отдает в ответ, например
DENY_IP_ADDR - - [09/Feb/2014:14:12:38 +0400] "GET /test HTTP/1.1" 444 .......
то есть сам запрос пришел, но ответ на него, 444-я ошибка

Да, точно... недосмотрел

66.249.78.96 - - [09/Feb/2014:04:55:17 +0400] "GET /node/3668/edit HTTP/1.0" 403 34490 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

Тогда следующий вопрос:
1) В настройках стоит показывать ошибку 444, а в access логе показывает 403 ошибку, так и должно быть?
2) Можно ли как то реализовать, чтобы google ботам было разрешение на доступ, при этом всей стране где он находится, нет. ?

1. не знаю, проверьте конфиг )
2. можно следующим макаром:

map $geoip_country_code $bad_country {  # основной блок, где вычисляется легитимность страны
  default 0;
  include /etc/nginx/geo/bad_countries;
}

map $remote_addr $legal_ip {     # создаем дополнительный блок map, где вычисляем легитимность конкретного ip
  default 0;
  1.1.1.1 1;      # тут можно инклудить список IP по аналогии с bad_countries
  2.2.2.2 1;
}

далее, перед проверкой переменной $bad_country, ставим проверку переменной $legal_ip

if ($legal_ip){
    set $bad_country 0;    # то есть если переменная $legal_ip имеет не нулевое значение, обнуляем переменную $bad_country
}

if ($bad_country){     # ну а тут уже основная проверка
    return 444;
}

если инкрудить легальные ip из файла, файл должен иметь такой вид:

1.1.1.1 1;
2.2.2.2 1;
и т.д.

Ок. Сейчас попробую, отпишусь как получится.

я проверял на рабочей машине, так что должно все работать )

Да, отлично работает. Спасибо. А ещё вопрос, как сделать ограничение средствами nginx на количество одновременных соединений с одного ip адреса?

ну, и отлично)
почитайте тут
http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html
думаю поможет

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
Регистр имеет значение
   .o     .oooo.                 ooooo     ooo  ooooo   o8o  
o888 .dP""Y88b `888' `8' `888' `"'
888 ]8P' oooo ooo 888 8 888 oooo
888 <88b. `88. .8' 888 8 888 `888
888 `88b. `88..8' 888 8 888 888
888 o. .88P `888' `88. .8' 888 888
o888o `8bd88P' .8' `YbodP' o888o o888o
.o..P'
`Y8P'
Введите код, изображенный в стиле ASCII-арт.