Аутентификация SSL-сертификата NGinx, подписанная промежуточным ЦС (цепочка) - PullRequest
36 голосов
/ 08 декабря 2011

Я пытаюсь включить аутентификацию сертификата клиента в nginx, где сертификаты были подписаны промежуточным центром сертификации.Я могу заставить это работать нормально при использовании сертификата, подписанного самозаверяющим корневым CA;однако, это не работает, когда подписывающий CA является промежуточным CA.

Мой простой раздел сервера выглядит так:

server {
    listen       443;
    server_name  _;

    ssl                  on;
    ssl_certificate      cert.pem;
    ssl_certificate_key  cert.key;

    ssl_session_timeout  5m;

    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;

    ssl_client_certificate ca.pem;
    ssl_verify_client on;
    ssl_verify_depth 1;

    location / {
        root   html;
        index  index.html index.htm;
    }
}

Для содержимого ca.pem я попытался использовать только промежуточный ЦС, а также объединение промежуточного ЦС-сертификата и корневого ЦС-сертификата, то есть что-то вроде:

cp intermediate.crt ca.pem
cat root.crt >> ca.pem

Я также подтвердил, что сертификат действителен с точки зрения openssl при использованиита же самая цепочка CA:

openssl verify -CAfile /etc/nginx/ca.pem certs/client.crt 
certs/client.crt: OK

Я экспериментировал с явным заданием ssl_verify_depth равным 1 (как выше), а затем даже 0 (не уверен, что именно означает это число), но все равно получаю ту же ошибку.

Ошибка, которую я получаю во всех вариантах промежуточного ЦС, - «400 неверных запросов» и, в частности, «Ошибка сертификата SSL» (не уверен, что именно это означает).

Может быть, nginx просто не делаетподдержка цепочек сертификатов для промежуточных сертификатов?Любая помощь с благодарностью!

Ответы [ 6 ]

46 голосов
/ 15 февраля 2013

Редактировать: у меня была также эта "проблема", решение и объяснение которой находится внизу текста .

Казалось, что nginx не поддерживает промежуточные сертификаты.Мои сертификаты созданы самостоятельно: (RootCA самоподписан, IntrermediateCA1 подписан RootCA и т. Д.)

RootCA -> IntermediateCA1 -> Client1 
RootCA -> IntermediateCA2 -> Client2

Я хочу использовать в nginx «IntermediateCA1», чтобы разрешить доступ к сайту только владельцу «Client1»«Certificate.

Когда я помещаю в файл« ssl_client_certificate »с IntermediateCA1 и RootCA и устанавливаю« ssl_verify_depth 2 »(или более), клиенты могут войти на сайт, используя сертификат Клиент1 и Клиент2 (должен только Клиент1).Тот же результат получается, когда я помещаю в файл "ssl_client_certificate" только RootCA - оба клиента могут войти в систему.

Когда я помещаю в файл "ssl_client_certificate" только IntermediateCA1 и установите "ssl_verify_depth 1" (или "2" или более - неважно), невозможно войти в систему, я получаю ошибку 400. И в режиме отладки я вижу журналы:

verify:0, error:20, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com"
verify:0, error:27, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com"
verify:1, error:27, depth:0, subject:"/C=PL/CN=Client1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com"
(..)
client SSL certificate verify error: (27:certificate not trusted) while reading client request headers, (..)

Я вещьэто ошибкаПротестировано на Ubuntu, nginx 1.1.19 и 1.2.7-1 ~ dotdeb.1, openssl 1.0.1.Я вижу, что в nginx 1.3 есть еще несколько вариантов использования клиентских сертификатов, но я не вижу решения этой проблемы.

В настоящее время единственный способ разделить клиентов 1 и 2 - создать два самоподписанных RootCA,но это только обходной путь ..

Редактировать 1: Я сообщил об этой проблеме здесь: http://trac.nginx.org/nginx/ticket/301

Редактировать 2 " * Хорошо, это не ошибка, это особенность;) *

Я получаю ответ здесь: http://trac.nginx.org/nginx/ticket/301 Это работает , вы должны только проверить, чтоВаш ssl_client_i_dn - это (. Вместо эмитента вы можете использовать также тему сертификата или то, что вы хотите от http://wiki.nginx.org/HttpSslModule#Built-in_variables

. Так работает проверка сертификата: сертификат должен быть проверен до доверенного корня.Если цепочка не может быть построена для доверенного корня (не промежуточного) - проверка не пройдена. Если вы доверяете корню - все сертификаты, подписанные им, прямо или косвенно, будут успешно проверены.

Ограничение глубины проверки может бытьиспользуется, если вы хотите ограничить клиента• Сертификаты только для непосредственно выданных сертификатов, но это больше о предотвращении DoS, и, очевидно, его нельзя использовать для ограничения проверки только промежуточным1 (но не промежуточным2).

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

[Отредактируйте мной, он корректно работает в моей конфигурации]

server {
    listen 443 ssl;

    ssl_certificate ...
    ssl_certificate_key ...

    ssl_client_certificate /path/to/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    if ($ssl_client_i_dn != "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com") {
        return 403;
    }
}
11 голосов
/ 23 июня 2012

Вы пытались увеличить директиву ssl_verify_depth? Документы говорят:

(it) sets a verification depth in the client certificates chain.

Но ваша глубина проверки равна 1. Вы говорите:

Я экспериментировал с явной настройкой ssl_verify_depth в 1 (как указано выше)и затем даже 0 (не уверен, что именно это число означает точно), но все равно получаю ту же ошибку.

Итак, попробуйте 2 или 3 ..

PS: Везде, где я нахожу эту проблему упомянутой, сказано объединять промежуточные сертификаты CA с вашим сертификатом сервера.в один файл (как и @ vikas-nalwar предложил , и вы это сделали) в порядке проверки (но я не уверен, что порядок имеет значение) и, грубо говоря, установите ssl_verify_depth для количества сертификатов в комплекте..

2 голосов
/ 26 января 2016

, когда я боролся с nginx и cloudflare,
эти строки помогли мне:

ssl_client_certificate    /etc/nginx/ssl/ca-bundle-client.crt;  
ssl_verify_client optional_no_ca;  
ssl_verify_depth 2;

вторая строка с option_no_ca важная часть

2 голосов
/ 08 декабря 2011

Я считаю, что вы хотите включить проверку клиента на стороне вашего сервера. Если это так, то я не вижу, что у вас есть сертификат клиента в цепочке. Попробуйте следующее в точно таком же порядке. Используйте certchain.pem.

  cat client.crt > certchain.pem
  cat intermediate.crt >> certchain.pem
  cat root.crt >> certchain.pem
1 голос
/ 18 июля 2017

Я должен сказать, что он работает нормально для меня с nginx/1.13.2, т.е.

  • У меня есть один корневой CA, который подписал два промежуточных CA
  • оба посредника каждый подписал клиента
  • Я согласен с сертификатами как cat client-intermediate1.crt ca-client.crt > ca.chained1.crt и cat client-intermediate2.crt ca-client.crt > ca.chained2.crt и cat ca.chained1.crt ca.chained2.crt > ca.multiple.intermediate.crt

  • если я только поставлю ca.chained1.crt как ssl_client_certificate, тогда только client1.crt может подключиться, аналогично для ca.chained2.crt / client2.crt

  • когда я использую ca.multiple.intermediate.crt, тогда оба клиента могут подключиться

для отзыва промежуточного звена, просто удалите цепочку сертификатов из ca.multiple.intermediate.crt

вот соответствующий конфиг. он также имеет высокие настройки безопасности

# minimum settings for ssl client auth 
ssl_client_certificate /etc/ssl/ca.multiple.intermediate.crt;
ssl_verify_client on;
ssl_verify_depth 2;

# ssl high security settings (as of writing this post)
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

если вы хотите разобрать CN сертификатов и передать его бэкэнду, то добавьте это ВНЕ блока server {..

# parse out CN
map $ssl_client_s_dn $ssl_client_s_dn_cn {
    default "should_not_happen";
    ~CN=(?<CN>[^,]+) $CN;
}

и ВНУТРИ блока вы можете использовать его тогда

# add headers for backend containing SSL DN/CN
add_header X-SSL-client-s-dn $ssl_client_s_dn;
add_header X-SSL-client-s-dn_cn $ssl_client_s_dn_cn;
0 голосов
/ 15 июня 2015

Другой простой способ - объединить сертификаты (включая сертификат домена) в один файл и использовать его на своих серверах и в файле nginx conf

cat www.example.com.crt bundle.crt> www.example.com.chained.crt

Всегда не забывайте сначала использовать сертификат сервера, а затем только сертификаты сервера CA

Вы можете узнать больше о http://nginx.org/en/docs/http/configuring_https_servers.html#chains

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...