Squid, https и проблемы CDN

Везде достаточно информации о том как запустить squid с ssl_bump, но в реальности всё иначе.

Моей целью было запустить squid с ssl_bump в прозрачном (intercept) режиме на Centos 7.1. Есть простое решение — добавить репозиторий и просто установить squid-3.5. Это работает, но это было бы слишком просто. Через некоторое время пользователи стали жаловаться на бан в google и недоступность некоторых крупных ресурсов.

Как оказалось, проблема известная и все варианты решения сводятся к прописыванию адреса прокси у пользователя. Всё началось еще в далеком 2009м с уязвимости CVE-2009-0801, а именно — пользователь прозрачно настроенного squid мог обойти правила подделав HTTP заголовок, именно туда (ну а куда же еще?) смотрит squid. В squid-3.2.11 появилась внутренняя функция hostHeaderIpVerify, которая проверяла — действительно ли http.host может быть доступен по указанному ip адресу. Прогресс, тем временем, не стоял на месте и количество ip для домена росло, набрал популярность Round-robin DNS. В таких условиях совсем не удивительно, что на одном хосте что-то резолвится в один IP, на соседнем (с таким же подключением) — иногда в другой, т.к. существует кеш DNS и обновляется он не синхронно. В момент таких «рассинхронизаций» squid не находит соответствия ip-домен в своём кеше (потому что обновил свой кеш немного раньше или позже) и squid прерывает соединение.

В cache.log это выглядит так:

SECURITY ALERT: Host header forgery detected on ... (local IP does not match any domain IP)
SECURITY ALERT: By user agent: ...
SECURITY ALERT: on URL: ...

Выбор был не велик — прописать всем адрес прокси или модифицировать squid. Первый вариант не подходил, т.к. в компании много мобильных пользователей с разными броузерами/устройствами. Пришлось лезть немытыми руками в код. Да, это плохо, очень плохо. В первую очередь потому что ломается вся полезность функции hostHeaderIpVerify со всеми последствиями. За дело.

Сначала добавляем всё тот же репозиторий для установки нужной версии libecap. Устанавливаем всё что потребуется, скачиваем и разворачиваем src.rpm с последней версией squid:

sudo yum install libecap openldap-devel pam-devel openssl-devel krb5-devel db4-devel expat-devel libxml2-devel libcap-devel libtool libtool-ltdl-devel libecap-devel gcc-c++ rpm-build
wget http://www1.ngtech.co.il/repo/centos/7/SRPMS/squid-3.5.12-1.el7.centos.src.rpm
rpm -i squid-3.5.12-1.el7.centos.src.rpm
cd rpmbuild/SOURCES
tar -xf squid-3.5.12.tar.xz

Редактируем код в файле «squid-3.5.12/src/client_side_request.cc».

Ищем функцию hostHeaderIpVerify и вставляем этот кусок сразу за циклом 'for':

debugs(85, DBG_IMPORTANT, "SECURITY ALERT: Workaruond for " << urlCanonical(http->request) << " CONN: " << http->getConn()->clientConnection );
http->request->flags.hostVerified = true;
http->doCallouts();
return;

Меняем поле Release в ~/rpmbuild/SPECS/squid35.spec, чтобы отличать собранные rpm. Запаковываем, собираем.

mv squid-3.5.12.tar.xz{,_old}
tar -cJf squid-3.5.12.tar.xz squid-3.5.12
cd ~/rpmbuild
rpmbuild -bb SPECS/squid35.spec


Собранные rpm в rpmbuild/RPMS готовы к установке.

P.S.: Понимаю, что это очень плохая идея и большой риск по безопасности, но выбора нет. Сотрудникам нужен google и прочие работающие cdn, компании нужен squid.
Tags:
squid, ssl

Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.