Назад | Перейти на главную страницу

Проверяйте Varnish ACL через X-Forwarded-For, когда за одним или несколькими (!) Обратными прокси

У меня Varnish работает за обратным прокси (работает на локальном хосте для разгрузки SSL). Прокси устанавливает заголовок X-Forwarded-For или добавляет себя к нему, если заголовок уже существует.

Когда я провожу проверки ACL, я, конечно, хочу проверить исходный IP-адрес клиента, а не IP-адрес моего прокси, поэтому я не могу использовать client.ip поле. С std vmod я могу сделать следующее:

vcl 4.0;
import std;
sub vcl_recv {
    if (std.ip(regsub(req.http.X-Forwarded-For, ", 127.0.0.1$", ""), "0.0.0.0") ~ my_acl) {
        ...do stuff...
    }
}

Другими словами, я удаляю IP-адрес прокси (127.0.0.1) из заголовка, прежде чем запускать его через std.ip и сравнивая его с моим ACL. Это нормально работает, кроме ...

Это не удается, если заголовок X-Forwarded-For уже установлен до того, как он достигнет моего прокси. В этом случае заголовок XFF содержит три или более IP-адресов. Обрезка последнего по-прежнему оставляет более одного и std.ip задыхается от этого, задерживая запрос на несколько секунд и, конечно, не проверяя ACL.

Мне нужно убедиться, что заголовок XFF содержит только один IP (IPv4 или IPv6) после того, как я отключил прокси. Это должен быть IP-адрес клиента.

Например:

X-Forwarded-For: 10.10.1.1, 10.10.2.2, 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1

должен стать

X-Forwarded-For: 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1

Поскольку я не могу доверять никаким заголовкам XFF, которые приходят извне, я бы хотел отказаться от всего, кроме ip-адреса клиента, который видел мой прокси. Мой прокси не поддерживает изменение заголовка XFF, поэтому мне нужно сделать это в Varnish.

Первая точка в потоке Varnish, когда я могу взаимодействовать с заголовками, находится в vcl_recv() и к этому моменту Varnish уже добавил client.ip в конец списка.

Я надеялся использовать регулярное выражение для захвата двух последних элементов (IPv4 или IPv6) в пронумерованную группу захвата ($ 1) и просто заменить заголовок группой захвата. Как это:

vcl 4.0;
import std;
sub vcl_recv {
    set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, "([a-f0-9:.]+, [a-f0-9:.]+)$", "\1");
}

Третий аргумент (строка, заменяющая символы, соответствующие регулярному выражению) не работает. Результирующий заголовок точно такой же, как и раньше, хотя регулярное выражение захватывает только два последних IP-адреса.

Как я могу выбросить что-либо, кроме двух последних IP-адресов из заголовка XFF?

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

Он должен работать, если вы добавите ^(.*) в начале вашего регулярного выражения и замените второй аргумент на \2

set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, "^(.*)([a-f0-9:.]+, [a-f0-9:.]+)$", "\2");

}

При этом я не думаю, что менять заголовок XFF - хорошая идея. Более стандартным должно быть добавление заголовка, а не изменение удаления информации, переданной промежуточными прокси.