Анонимизировать IP вход в nginx?
Чтобы уважать конфиденциальность моих пользователей, я пытаюсь анонимизировать их IP-адреса в лог-файлах nginx.
Одним из способов сделать это было бы определение пользовательского формата журнала, например так:
log_format noip '127.0.0.1 - [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $request_time';
У этого метода есть два недостатка: я не могу отличить двух пользователей и не могу использовать инструменты геолокации.
Лучше всего было бы "сократить" IP-адрес (87.12.23.55
станет 87.12.23.1
).
Есть ли возможность добиться этого с помощью скриптов конфигурации nginx?
Благодарю.
5 ответов
Даже если уже принят принятый ответ, решение кажется недействительным.
У nginx есть директива log_format, которая имеет контекст http. Это означает, что log_format может быть (допустимо) установлен только в секции http {} файла конфигурации, а НЕ в секциях сервера!
С другой стороны, у нас есть директива if, которая имеет контекст сервера и местоположения.
Поэтому мы НЕ можем использовать "if" и "log_format" в разделе сервера (что делается в рамках принятого решения)
Так что если здесь не полезно, также если это зло ( http://wiki.nginx.org/IfIsEvil)! Нам нужно что-то, что работает в контексте http, потому что только там log_format может быть определен корректным образом, и это единственное место вне контекста сервера, где определены наши виртуальные хосты…
К счастью, в nginx есть особенность карты! map переопределяет некоторые значения в новые значения (доступны в переменных, которые могут использоваться в директиве log_format). И хорошее сообщение: это также работает с регулярными выражениями.
Итак, давайте сопоставим наши адреса IPv4 и IPv6 в анонимные адреса. Это должно быть сделано в 3 шага, так как карта не может накапливать возвращаемые значения, она может только возвращать строки или переменные, а не комбинацию обоих.
Итак, сначала мы берем часть IP, которую мы хотим иметь в лог-файлах, вторая карта возвращает часть, которая символизирует анонимизированную часть, а третье правило карты отображает их снова вместе.
Вот правила, которые входят в контекст http {}:
map $remote_addr $ip_anonym1 {
default 0.0.0;
"~(?P<ip>(\d+)\.(\d+)\.(\d+))\.\d+" $ip;
"~(?P<ip>[^:]+:[^:]+):" $ip;
}
map $remote_addr $ip_anonym2 {
default .0;
"~(?P<ip>(\d+)\.(\d+)\.(\d+))\.\d+" .0;
"~(?P<ip>[^:]+:[^:]+):" ::;
}
map $ip_anonym1$ip_anonym2 $ip_anonymized {
default 0.0.0.0;
"~(?P<ip>.*)" $ip;
}
log_format anonymized '$ip_anonymized - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log anonymized;
После добавления этого в файл конфигурации nginx.conf не забудьте перезагрузить nginx. Ваши файлы журнала теперь должны содержать анонимные IP-адреса, если вы используете "анонимный" формат журнала (это параметр формата директивы access_log).
Принятый ответ кажется немного раздутым. Начиная с nginx версии 1.11, это можно сделать так:
map $remote_addr $remote_addr_anon {
~(?P<ip>\d+\.\d+\.\d+)\. $ip.0;
~(?P<ip>[^:]+:[^:]+): $ip::;
default 0.0.0.0;
}
Вот модуль nginx, который в основном делает это (анонимизирует IP-адреса в ваших журналах): https://github.com/masonicboom/ipscrub. Он генерирует хеш IP-адреса как $remote_addr_ipscrub. Время от времени циклы хэшированной соли (настраиваемые) позволяют связывать запросы, не регистрируя IP-адреса пользователей.
Я думаю, что хорошим и практичным решением является анонимизация IP-адреса перед ротацией файлов журналов (что вы должны делать ежедневно). Существует множество сценариев для этой задачи, доступных для Apache, и, поскольку формат журнала, по крайней мере, очень похож, они должны работать "из коробки" или быть легко настраиваемыми. Конечно, вы сохраняете полный IP-адрес 24 часа или меньше, но это лучше, чем хранить их годами.
Вы можете использовать оператор if с регулярными выражениями внутри блока сервера, чтобы анонимизировать IP без каких-либо дополнительных модулей perl или lua.
внутри nginx.conf
server {
if ($remote_addr ~ (\d+).(\d+).(\d+).(\d+)) {
set $ip_anym $1.$2.0.1;
}
log_format main '[$time_local] $ip_anym "$request" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent"';
access_log /var/log/access.log main;
....
}
Мы анонимизируем ip и назначаем его новой переменной с именем $ip_anym, которую затем можем использовать внутри формата журнала вместо исходного $remote_addr. В приведенном выше примере мы сохраняем первую и вторую часть IP-адреса, вы также можете использовать $1.$2.$3.1, если вы предпочитаете заменять только последнюю часть ip.