OCSP stapling in Nginx >=1.3.7
Gena Makhomed
gmm на csdoc.com
Сб Сен 15 11:35:35 UTC 2018
On 12.09.2018 17:36, Maxim Dounin wrote:
>>>>>>> Лучше всего - сделать так, чтобы OpenSSL научился проверять
>>>>>>> OCSP-ответы не полной цепочкой сертификатов вплоть до доверенного
>>>>>>> root'а, а ровно так, как и должно быть по стандарту - с помощью
>>>>>>> одного только сертификата issuer'а. Тогда проблема исчезнет.
Задал вопрос по этому поводу в списке рассылки openssl-users:
https://mta.openssl.org/pipermail/openssl-users/2018-September/008795.html
- пока что мне там никто ничего так и не ответил.
>>> В зависимости от того, каким сертификатом подписан OCSP-ответ -
>>> этого может быть достаточно или нет. RFC 6960 допускает два
>>> варианта подписи в OCSP-ответах:
>>> - issuer подписывает OCSP-ответ сам; или
>>> - issuer выпускает сертификат, которым подписываются OCSP-ответы
>>> (и этот сертификат включается в OCSP-ответ).
>>> В обоих случаях для проверки OCSP-ответа достаточно знать
>>> issuer'а, однако второй случай в OpenSSL не работает (впрочем, я
>>> давно не порверял; но если верить "документации", в этом месте
>>> ничего не зименилось). При этом по понятным причинам мало кто
>>> использует собственно CA для подписи OCSP-ответов, соответственно
>>> не работает это приблизительно всегда.
Проверил второй случай, openssl-1.0.2k из CentOS 7.5 все работает:
1. Получаю сертификат сервера (0) и сертификат issuer'а (1):
openssl s_client -showcerts -connect www.godaddy.com:443 < /dev/null | less
Сертификат сервера сохраняю в файл www.godaddy.com-cert.pem
а сертификат issuer'а - в файл www.godaddy.com-issuer.pem
2. Узнаю OCSP URI, это http://ocsp.godaddy.com/
openssl x509 -text -noout -in www.godaddy.com-cert.pem | less
3. Делаю запрос на получение OCSP ответа от этого сервера:
openssl ocsp -verify_other www.godaddy.com-issuer.pem -issuer
www.godaddy.com-issuer.pem -cert www.godaddy.com-cert.pem -text -url
http://ocsp.godaddy.com/ -header "Host" "ocsp.godaddy.com" | less
Из ответа видно, что для подписи используется отдельный сертификат
Go Daddy Validation Authority - G2, при этом "Response verify OK",
то есть OpenSSL может проверить ответ сервера и в этом случае.
Если убрать параметр '-verify_other www.godaddy.com-issuer.pem'
тогда возвращается сообщение про ошибку:
Response Verify Failure
140345419933584:error:27069065:OCSP
routines:OCSP_basic_verify:certificate verify
error:ocsp_vfy.c:138:Verify error:unable to get local issuer certificate
Получается, что OpenSSL уже очень давно умеет проверять
OCSP-ответ с помощью одного только сертификата issuer'а?
>>>> Насколько я понял из предыдущего обсуждения, нет разумных причин,
>>>> чтобы выключать использование OCSP stapling и ocsp_stapling_verify.
>>>>
>>>> И вместе с тем, есть причины, чтобы их включать:
>>>> OCSP stapling - сайт у клиентов будет открываться быстрее.
>>>> ocsp_stapling_verify - не будет проблем с неразумными браузерами.
>>
>>> Про "быстрее" - есть нюансы. В частности, OCSP-ответ отправляется
>>> клиенту, пытающемуся использовать OCSP stapling, в каждом
>>> SSL handshake'е (а это местами может быть больно с точки зрения latency, не
>>> говоря уже про трафик), в то время как в значительной части
>>> случаев он клиенту на самом деле не нужен (например, уже есть в
>>> кэше).
Почему это может быть больно с точки зрения latency? Ведь nginx держит
OCSP-ответ в своей памяти и отдает его клиенту практически мгновенно.
Этот ответ как правило валиден от 24 часов до 7 или даже 14 дней.
Трафик - это дополнительный килобайт, максимум два килобайта.
Разве это много? Страница сайта весит от сотен килобайт
до нескольких мегабайт, и 1-2 килобайта роли не играют.
Если OCSP-статус сертификата клиенту не нужен,
зачем же в таком случае клиент его постоянно запрашивает?
Это же клиент решает, получать ему OCSP-статус сертификата или нет.
Вот ответ сервера, если OCSP-статус не запрашивать:
openssl s_client -showcerts -connect www.godaddy.com:443 < /dev/null | less
А вот ответ сервера, если OCSP-статус запрашивать:
openssl s_client -showcerts -status -connect www.godaddy.com:443 <
/dev/null | less
Если глупый клиент постоянно запрашивает OCSP-статус сертификата,
даже в том случае если ему этот статус уже известен и не нужен
- это наверное не проблемы сервера, а проблемы самого клиента.
(И исправлять эту проблему надо на клиенте а не на сервере)
>> Открытие сайта по HTTPS без OCSP Stapling подразумевает,
>> что браузер сам будет проверять не отозван ли сертификат сервера.
>> Клиент в это время будет сидеть перед монитором и ждать открытия сайта.
> Или не будет - см. пример в скобках.
Обычно веб-мастера стараются максимально ускорить первое открытие сайта
клиентом. Потому что если сайт будет открываться долго, например, 5 или
10 секунд - пользователь этого может просто не дождаться и уйти.
При первом открытии сайта - OCSP-ответа точно нет в кэше клиента.
>>> Про verify - тоже есть нюансы. Дискуссия, если я её правильно
>>> понял, как раз о том, что включать verify обходится дороже с
>>> административной точки зрения, чем хотелось бы. При этом плюсы -
>>> призрачны, ибо защищают от атак, которых на практике не бывает
>>> (а если бы они были - браузеры бы давно исправились).
>>
>> В начале дискуссии вопрос был о том, почему для того чтобы директива
>> ssl_stapling_verify on; нормально работала необходимо также прописывать
>> ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
>> если содержимое файла chain.pem можно получить из файла fullchain.pem
>> выбросив оттуда первый сертификат, который является сертификатом сайта?
>
> И ответ на этот вопрос - потому что интерфейс проверки сертификатов
> кривой, и требует массы дополнительных приседаний, чтобы работать.
> Именно поэтому по умолчанию используется ssl_stapling_verify off.
Передать библиотеке OpenSSL сертификат issuer'а два раза,
в параметрах -issuer и -verify_other - это не выглядит очень сложным.
> Кроме того, если у вас в ssl_certificate указана полная цепочка,
> включая сертификат root CA, то это неправильно. Root-сертификат у
> клиентов и так есть, отправлять клиентам его - бессмысленная трата
> ресурсов, соответственно и включать его в цепочку в
> ssl_certificate - не надо.
У меня сертификат получен с помощью certbot,
"Let’s Encrypt Authority X3" - это промежуточный сертификат.
Он подписан с помощью "DST Root CA X3", подробности здесь:
https://letsencrypt.org/certificates/
В конфиге nginx прописано
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1;
ssl_certificate /etc/letsencrypt/live/.../fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/.../privkey.pem;
Директива ssl_trusted_certificate вообще нигде в конфиге не указана,
при этом - nginx не пишет в лог никаких ошибок верификации сертификата.
> Если же root-сертификата в цепочке нет, то получить из
> ssl_certificate полную цепочку, включая root, по очевидным
> причинам не получится, и ssl_stapling_verify работать не будет.
Почему же в таком случае nginx не пишет в лог никаких ошибок?
Версия 1.15.3, пакет из официального репозитория nginx.org
>>> Единственное несомненное преимущество OCSP stapling'а
>>> - это меньшая нагрузка на инфраструктуру CA
Let’s Encrypt дает мне SSL-сертификаты полностью бесплатно,
с моей стороны нормально будет в ответ уменьшить нагрузку
на их сервера, включив OCSP stapling для всех сайтов.
Если же я выключу OCSP stapling, тогда я буду в чем-то
похож на персонажа басни Крылова "Свинья под дубом".
Кроме того, например, Майкрософт включает OCSP stapling
в своем веб-сервере IIS по-умолчанию уже очень давно.
Они же это делают не для того, чтобы навредить своим клиентам,
а наоборот, чтобы сайты их клиентов открывались еще быстрее?
P.S.
Кстати, пользователи жалуются, что есть BUG в nginx,
связанный с сертификатами с флагом "OCSP Must Staple":
https://blog.crashed.org/nginx-stapling-busted/
--
Best regards,
Gena
Подробная информация о списке рассылки nginx-ru