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