- PVSM.RU - https://www.pvsm.ru -
Всем добрый день.
Команда Русоникса решила проблемы с электричеством и написала прекрасный пост с красивыми картинками [1] про «Распределенную брутфорс-атаку на CMS с точки зрения хостера».
Впрочем, там не хватает одного — собственно реализации.
Итак, цели этого поста:
Если интересно, прошу под хабракат.
Повторим на всякий случай цели борьбы:
Логика:
0. Nginx работает как самый обычный front. Апач и всё остальное сзади.
1. При превышении некоторого лимита показываем пользователю формочку, где нужно что-либо сделать (в моём случае — просто нажать на кнопку), тем самым доказав, что он человек.
2. В дальнейшем пропускать человека без проволочек.
Решение оказалось несложным, все комментарии по ходу.
# описание т.н зоны
limit_req_zone $binary_remote_addr zone=one:10m rate=5r/m;
server {
# ...
root /var/wl-web;
recursive_error_pages on; #мы два раз проходим по error_page в случае @limit -> @wlgui;
location / {
#... тут самое обычное проксирование на бэкэнд
}
# именованый локейшн для нашего ифейса авторизатора.
location @wlgui { # у меня fpm, но можно проксировать и на апач.
internal;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/wlgui.php;
fastcgi_intercept_errors on;
include fastcgi_params;
}
# защищаемые файлы. именно тут можно перечислить "сигнатуры" админок движков
location ~* /(i|i2).html$ {
# Срабатыване лимита реализуется в "возврате" 503 (c 1.3.15 этот код можно поменять строчкой ниже)
#limit_req_status 516;
error_page 503 = @limit;
# включаем ограничитель. При срабатывании запрос уйдет на @limit
limit_req zone=one nodelay;
# Это сработает, если в лимит не упёрлись.
# Важно. Нам нужен именно изначальный URI, поэтому собираем руками.
proxy_pass http://127.0.0.1:8080$request_uri;
proxy_set_header Host $host;
#и другие директивы проксирования на бэкэнд
}
# Если сработал лимит
location @limit {
internal;
#проверяем что в куке нет ничего, что может плохо сработать при подстановке в путь файловой системы.
if ($cookie_wlsid ~* [^a-fd]) { return 503; }
# так не получилось, но было бы очень красиво =(
#error_page 516 @backend;
#try_files /wl/$cookie_wlsid.cookie /wl/$remote_addr.ip /wl/$remote_addr-$host.iph @wlgui;
#if ($uri ~* /wl/[a-zd]+.cookie ) {return 516;}
# именованый локейшн для заворота запроса на страничку подтверждения хм.. "человечности".
# Если кука не авторизована(т.е нет файла с её значением), заворачиваем туда. If is Evil, i know....
error_page 516 = @wlgui;
if ( !-f $document_root/wl/$cookie_wlsid.cookie) {return 516;}
# Кука авторизована! На бэкэнд.
proxy_pass http://127.0.0.1:8080$request_uri;
proxy_set_header Host $host;
#и другие директивы проксирования на бэкэнд
}
}
и очень простой wlgui.php, который производит «авторизацию» куки путём создания пустого файла с именем, равным значению куки.
(важно не забыть создать папку wl в /var/wl-web и поставить на неё соответствующий права)
<?php
if (!empty($_POST['wlsec'])){ # если форма сабминится, отдаём куку в браузер и авторизовываем её.
$cookie=md5(uniqid());
setcookie('wlsid',$cookie,time()+3600*24*90/*90d*/);
touch ('/var/wl-web/wl/'.$cookie.'.cookie');
echo "Done! Please, refresh the page! (setting {$cookie})";
} else {
?>
<form method="POST">
<input name="wlsec" value="GetAccess" type="submit">
</form>
<?php
echo "<br> Your cookie:".(isset($_COOKIE['wlsid'])?htmlspecialchars($_COOKIE['wlsid']):'(not set)');
}
Возможные улучшения:
Ну и как обычно: опечатки в личку, вопросы/дополнения/улучшения в комментарии.
Ссылки: Nginx limit_req_module [3], базовые вещи по ядру [4] и прокси [5].
Спасибо, что дочитали до конца!
PS
По роду деятельности я не очень плотно занимаюсь настройкой серверного ПО и прочим сисадминством, поэтому я считаю это решение эскизным, хотя оно и отработало в продакшене какое-то время(затем у меня просто дошли руки переименовать админки).
Автор: la0
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/nginx/40979
Ссылки в тексте:
[1] прекрасный пост с красивыми картинками: http://habrahabr.ru/company/rusonyx/blog/190020/#first_unread
[2] ifIsEvil: http://wiki.nginx.org/IfIsEvil
[3] Nginx limit_req_module: http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html
[4] ядру: http://nginx.org/ru/docs/http/ngx_http_core_module.html#recursive_error_pages
[5] прокси: http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_pass
[6] Источник: http://habrahabr.ru/post/190112/
Нажмите здесь для печати.