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

nginx proxy_pass с сервером, запрашивающим сертификаты клиентов

Мы проксируем бэкэнд, который мы не контролируем, и бэкэнд запрашивает сертификат клиента при подключении по https.

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

Конфигурация Nginx:

server {
        listen 443 ssl;

        ssl on;
        ssl_certificate /etc/nginx/ssl/webserver.pem;
        ssl_certificate_key /etc/nginx/ssl/webserver.key;

        location / {
                 proxy_pass https://www.backendsite.com;
                 proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        }
}

Я не уверен, понимаете ли вы это или нет, но то, что вы делаете, это атака Man-In-The-Middle на www.backendsite.com.

Чтобы понять, почему это не работает в вашем сценарии, нам нужно будет объяснить фактическую роль сертификатов и ключей в TLS. Итак, поехали.

Прежде всего, нам нужно установить ключ в открытом виде. У нас нет и по соображениям эффективности не может быть защищенного канала, поэтому мы используем протокол Diffie Hellman в качестве протокола обмена ключами. Ранее мы могли установить параметры, которые используем. Современное мышление говорит, что это плохая идея, давайте придумываем что-нибудь в процессе. Это называется DHE (эфемерный Диффи Хеллман). Если вам действительно нравится, вы можете сделать это через EC (EC-DHE).

Теперь вопрос в том, откуда вы знаете я отправил вам параметры, которые я сделал, используя DH? Чтобы проверить это, нам нужен алгоритм цифровой подписи, чтобы вы могли иметь некоторую общедоступную информацию обо мне, чтобы убедиться, что подпись, сделанная с помощью моего закрытого ключа, может быть сделана только мной.

Материал ключа сервера предоставляет это для серверной части - закрытый ключ и открытый ключ (содержащийся в сертификате вместе с подписями CA, говорящими «да», мы тоже этому доверяем).

ОБЫЧНО, клиент может просто сгенерировать пару открытого / закрытого ключей для анонимных подключений по своему усмотрению. Итак, при обычных обстоятельствах:

  • У клиента есть старая пара ключей.
  • Она устанавливает рабочее соединение с вашим прокси. По этому туннелю происходит шифрование / дешифрование трафика.
  • Прокси-сервер имеет собственную «любую старую пару ключей», с помощью которой он устанавливает соединение с сервером.
  • Сервер не очень заботится о том, кто является клиентом, он устанавливает соединение практически с кем угодно, поэтому использует открытый ключ вашего прокси.
  • Сессия установлена.

Однако теперь клиент предоставляет определенную пару ключей. Эта пара ключей используется для защиты параметров протокола, поэтому происходит следующее:

  • У клиента есть определенная пара ключей, он запрашивает TLS и отправляет свои параметры и открытый ключ.
  • Прокси-сервер расшифровывает и может повторно упаковать это одним из двух способов (я не знаю, какой из них действительно произойдет - зависит от реализации - я просто объясняю, почему это не может работать):
    • Он предоставляет публичный сертификат клиента вместо своего собственного. Не имея закрытого ключа, он не может расшифровать ни один из ответов сеанса.
    • Итак, дурак (опять же, это не совсем то, что происходит, просто иллюстрация) и генерирует свои собственные сертификаты. Однако сервер не будет разговаривать с сертификатами, кроме тех, которые соответствуют заданным критериям (например, подписаны каким-то известным сертификатом), и поэтому отказывается согласовывать соединение.

Причина, по которой это не совсем работает, заключается в том, что nginx пытается действовать как http-прокси, снимая и повторно применяя https по мере необходимости, и с доверенными сертификатами, установленными на обоих концах, TLS предотвращает MITM по дизайну.

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