Подтвердить что ты не робот

Apache не будет запрашивать сертификат моего SSL-клиента

Прежде всего, обратите внимание, что я новичок в настройке SSL. Раньше мне всегда повезло, что ИТ-отдел настроил это заранее. Поэтому будьте готовы к тому, что мне могут потребоваться разъяснения по некоторым вашим ответам. =)

Что я пытаюсь сделать

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

У меня будет настройка базы данных MySQL для связывания учетных записей "user" с SSL_CLIENT_M_SERIAL и SSL_CLIENT_I_DN, которые, как я предполагаю, будут уникальными для каждого сертификата клиента (?). Я получил эту идею из этой статьи: http://cweiske.de/tagebuch/ssl-client-certificates.htm

В первый раз, когда пользователь переходит на внутренний веб-сайт, у них не будет сертификата (я НЕ хочу генерировать их вручную для клиентов!), и в этом случае $_SERVER [ "SSL_CLIENT_VERIFY" ] == "NONE". В этом случае он перейдет на страницу настройки учетной записи пользователя, которая будет включать шаг, на котором PHP генерирует сертификат клиента SSL и отправляет его в браузер для установки пользователем. Ницца и просто. Затем пользователь устанавливает сертификат, создается ассоциация и после перезапуска браузера (для хорошей оценки) пользователь возвращается на внутренний веб-сайт.

В этот момент Apache должен запросить сертификат клиента, который затем отправляет браузер. PHP script затем анализирует необходимые переменные $_SERVER, сравнивает их с базой данных MySQL, и хорошие времена выполняются всеми. Опять же, приятно и просто.

Что работает до сих пор

У меня установлены серверные сертификаты. И да, они самоподписаны (по понятным причинам). У Apache установлен mod_ssl, и все это работает нормально. Я создал PHP script, который просто сбрасывает массив $_SERVER, и все значения ключа SSL_SERVER_ * соответствуют сертификату, который я создал для него.

Проблема

Я не могу заставить клиентские сертификаты работать! В том же PHP script, независимо от того, что я делаю, отсутствуют SSL_CLIENT_VERIFY == "NONE" и другие ключи SSL_CLIENT_ *. Это то, что произойдет, если у меня SSLVerifyClient установлен на необязательный в ssl.conf. Согласно каждому учебнику, которое я прочитал, все говорят, что веб-сервер должен запросить браузер для сертификата клиента. Дело в том, что я не могу это сделать! Он просто переходит на PHP скрипт и предполагает, что у меня нет клиентских сертификатов. Это происходит в Firefox, Chrome и IE.

Поэтому я попробовал настроить SSLVerifyClient и перезапустить веб-сервер. С этой опцией я даже не могу установить SSL-соединение. Firefox просто говорит, что соединение было reset (в других браузерах также отображаются собственные версии этой ошибки). Что странно, что журналы не показывают ЛЮБОЙ активности при этих попытках подключения! То есть access_log, error_log, ssl_access_log, ssl_error_log, AND ssl_request_log все не показывают НИЧЕГО; это как будто попытка никогда не возникала. Это разочаровывает, потому что это означает, что у меня даже нет сообщения об ошибке для работы. Просто веб-сервер пассивно-агрессивно сказал мне идти в ад.

Я попытался создать/установить собственный сертификат клиента вручную, используя расширение PHP OpenSSL. Сертификат установлен просто отлично, хотя я не могу найти никакой информации о том, как связать этот сертификат с сервером (при условии, что мне даже нужно?). Кроме того, это все равно не имеет значения, потому что Apache по-прежнему даже не запрашивает сертификат клиента, если установлен дополнительный параметр. И если требуется, он просто взрывается без объяснения причин. Мне нужно, чтобы она была настроена на факультативный, чтобы эта схема работала.

Среда

ОС: CentOS 5.7 64-разрядная (VirtualBox)

Apache: 2.2.3

PHP: 5.3.10

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

Подводя итог, мне нужно знать, как заставить Apache запрашивать сертификат клиента SSL с учетом условий, описанных выше. Кроме того, если есть специальное подписание /etc, которое должно быть сделано, чтобы сделать сертификат клиента "совместимым" с сертификатом сервера (опять же, БЕЗ делать это вручную через оболочку для каждого сертификата клиента!), Мне нужно знать, что в качестве хорошо.

Я на 100% застрял на этом. Невозможно найти что-либо даже отдаленно полезным в Google. Любая помощь, которую вы можете предоставить по этому поводу, будет TREMENDOUSLY оценена! Благодарю! =)

4b9b3361

Ответ 1

Сначала вам нужно настроить Apache Httpd для запроса сертификата клиента. Для этого вам нужно, по крайней мере, использовать SSLVerifyClient optional в каталоге location/, которому вы хотите пройти аутентификацию с помощью этого метода.

Во-вторых, сертификаты, отправленные клиентом, также должны быть доверены Apache Httpd. (Вы могли бы в принципе использовать SSLVerifyClient optional_no_ca, пусть любой клиент сертифицируется через стек Apache Httpd SSL/TLS и только затем проверяет сертификат в PHP, но это довольно много работы, для чего вам нужно быть немного более осторожным поскольку это не обязательно легкий код, что более важно, это было бы совершенно бесполезно в этом контексте, поскольку вы находитесь в сценарии, где вы контролируете свой ЦС.)

Насколько я понимаю, SSL_CLIENT_VERIFY (переменная, которую я сам не использовал много) кажется очень полезной с SSLVerifyClient optional_no_ca. Он может работать с SSLVerifyClient optional, но я сомневаюсь. SSLVerifyClient require будет отклонять соединения с использованием сертификата клиента, которому не доверяют (одним из центров сертификации в SSLCACertificateFile/SSLCACertificatePath), или если нет сертификата. Насколько мне известно, SSLVerifyClient optional позволит клиенту пройти без сертификата или с доверенным сертификатом, но также отклонит соединение, если сертификат не доверен.

Здесь, отклоняя соединение, я подразумеваю закрытие соединения SSL/TLS внезапно с помощью предупреждения. Нет возможности создать страницу с ошибкой HTTP (S). Все, что вы получите в стандартной ошибке браузера, что-то вроде строк ssl_error_unknown_certificate_.... (Вы должны учитывать это с точки зрения удобства использования.)

С этого момента вам нужно настроить свой собственный ЦС, возможно, с помощью веб-браузера с ключом и на одном веб-сайте. Вы бы не хотели SSLVerifyClient require для этого, потому что вам нужно было позволить пользователям, у которых еще нет сертификата (вместо этого используйте optional). При этом эти директивы не должны применяться ко всему хосту, но могут быть конкретными для определенных местоположений/каталогов.

Интеграция собственного веб-центра сертификации (или, в более общем смысле, создание собственного ЦС) не всегда легко, если вы новичок в этом. Готовые инструменты существуют (например, OpenCA), или вы можете создавать свои собственные, используя различные биты JavaScript/ActiveX, и вам понадобится серверный код для обработки запросов SPKAC или PKCS # 10 (и для выдачи фактического сертификата). (Для того, чтобы такой CA был полезен, вы хотели бы, чтобы пользователи, которые подавали заявку на получение нового сертификата, предоставили некоторые доказательства ID на момент подачи заявки, возможно, пароль.)

Когда это настроено, вы должны настроить SSLCACertificateFile (или ...Path), чтобы указать на сертификат ЦС вашего внутреннего ЦС (независимо от того, является ли он веб-центром или нет на том же сайте или нет). (Разумеется, сохраните личный ключ вашего CA приватным, возможно, настроенным в вашем веб-приложении CA, но сам Apache Httpd не должен знать об этом.) Браузеры будут предлагать только сертификаты, выданные этими CA или промежуточными (за исключением вы также настроили SSLCADNRequestFile, который будет использоваться для отправки списка принятых ЦС).

Обратите внимание, что эти два шага (настройка вашего центра сертификации и настройка вашего сайта для использования клиентских сертификатов) действительно независимы. Тот факт, что оба могут быть частью одного и того же сайта, может быть удобным, но не является необходимым. Вы можете попробовать настроить Apache Httpd без развертывания всего ЦС на сайте в первую очередь (я бы рекомендовал это, даже если это просто посмотреть, что вы получаете). Существует несколько инструментов для создания собственного небольшого ЦС, которые можно управлять с помощью нескольких сертификатов: OpenSSL CA.pl или TinyCA, например. Вы также можете использовать эти сертификаты (localhost и testclient, testclient_r отменяется, если вы хотите использовать CRL, возможно, не необходимо сначала): все пароли testtest.

Как вы уже ожидали (с вашим MySQL DB), вам нужно будет управлять выдаваемыми вами сертификатами и сопоставлять их с пользователями. SSL_CLIENT_M_SERIAL и SSL_CLIENT_I_DN не являются правильными переменными. SSL_CLIENT_I_DN - DN эмитента (т.е. DN субъекта ЦС). То, что вы ищете, - SSL_CLIENT_S_DN: имя сертификата клиента Subject DN. SSL_CLIENT_M_SERIAL - это серийный номер сертификата: не используйте его, поскольку он уникален для каждого сертификата: один пользователь может иметь несколько сертификатов с одним и тем же DN субъекта (например, если он истекает или отменяется).


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

  • Во-первых, пользователь должен в любом случае защищать свои сертификаты паролем. Я думаю, что на самом деле вы на самом деле являетесь одной из форм единого входа (SSO).

  • Во-вторых, в зависимости от степени компьютерной грамотности ваших пользователей сертификаты на самом деле могут быть довольно сложными.

    Тот факт, что слово "сертификат", строго говоря, вообще не включает закрытый ключ, но иногда подразумевает, что использование частного ключа может смутить для некоторых. С одной стороны, вы иногда слышите "Импортируйте свой сертификат в свой браузер" и "Используйте свой сертификат для входа"; с другой стороны, вы также можете услышать "пошлите мне свой сертификат". Первое подразумевает использование и доступность закрытого ключа ( "сертификат" может означать только .p12 в этих выражениях). Последний определенно не должен включать закрытый ключ.

    Пользовательские интерфейсы браузера имеют тенденцию быть довольно плохими или запутанными для управления сертификатами или выхода из системы. Опять же, если сертификат не распознан, соединение SSL/TLS не будет установлено, поэтому веб-сервер не получит возможность отображать страницу ошибок HTML любого типа.

Возможно, вы могли бы также рассмотреть другие формы SSO (например, CAS, что-то на основе SAML или Kerberos/SPNEGO.)

Ответ 2

Вы можете взглянуть на apache doc, если это уже не сделано.

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

Тогда похоже, что клиент подключается к вашему сайту интрасети через http. Оттуда существует множество способов переключения на https с помощью вашего сертификата ssl. Самый простой способ - использовать модуль перезаписи apache. Но в вашем случае, когда вы выполняете проверки php/mysql, вы можете перенаправить свой клиент с http на https, что не так просто.

В любом из обоих случаев (автоматическое перенаправление apache через mod_rewrite или перенаправление с помощью каскадных тестов (php/javascript/html) вам необходимо настроить ваши 2 vhosts (один для http и один для https) соответствующим образом, но это предполагает некоторую гипотезу.

Например, (debian - apache 2.2), это автоматическая переадресация, выполняемая Apache (например, 1-й случай, описанный выше):

cat/etc/apache2/sites-available/test

# VHOST test

<VirtualHost *:80>

    DocumentRoot /home/www/test
    ServerName www.test.dev

    # ######################
    # Redirect commons
    # ######################
    RewriteEngine on
    # Case of vhosts
    RewriteOptions Inherit

    # ######################
    # Redirect (empty index)
    # ######################

    # Condition 1 to redirect : request matching with the server
    RewriteCond %{HTTP_HOST}   ^www\.test\.dev [NC]

    # Condition 2 to redirect : non empty HOST
    RewriteCond %{HTTP_HOST}   !^$

    # Automatic Empty requests Redirect
    RewriteRule ^(.*)/$ /index.php


    # ######################
    # Redirect to SSL
    # ######################
    RewriteCond %{HTTP_HOST}   ^www\.test\.dev [NC]
    RewriteCond %{HTTP_HOST}   !^$
    RewriteCond %{SERVER_PORT} ^80$
    RewriteCond %{REQUEST_URI} /

    # Redirection
    RewriteRule ^/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

</VirtualHost>

Второй виртуальный хост для SSL: cat/etc/apache2/sites-available/test-ssl

# VHOST for ssl

  

DocumentRoot "/home/www/test"
ServerName www.test.dev

    # SSL
    SSLEngine on
    SSLCACertificateFile /etc/apache2/ssl/cur_cert/ca.pem
    SSLCertificateFile /etc/apache2/ssl/cur_cert/serveur.pem
    SSLCertificateKeyFile /etc/apache2/ssl/cur_cert/serveur.key


    <Directory "/home/www/test">
        Options FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from 127.0.0.1 192.168.0.0/16
    </Directory>


    <Directory "/home/www/test/cgi-bin">
        Options FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from 127.0.0.1 192.168.0.0/16
        Options +ExecCGI
        AddHandler cgi-script .cgi
    </Directory>

</VirtualHost>

Ваше дело может немного отложить от этого, например, у вас не будет части переадресации в первом vhost, но только простой vhost и второй для https (ssl). Перенаправление будет выполнено php/javascript, как только вы достигнете своих проверок mysql.

Вот пример абстракции из php-класса для каскадного переключения с http на https, используя php, затем javascript, затем html:

public function Redirect($url){

    if (TRUE !== Validator::isValidURL($url))
        die ("FATAL ERR: url not valid");

    // PHP ABSOLUTE URL REDIRECT (HTTP1.1)
    if (!headers_sent()) {

        header("Status: 200");
        header("Cache-Control: no-cache, must-revalidate"); // required for HTTP/1.1
        header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // past Date
        header("Pragma: no-cache");
        header('Location: '.$url); // note: 302 code return by default with "Location"
        flush();
        exit();

        // if headers are already sent... do javascript redirect... if javascript is disabled, do html redirect.
    } else {

        // Js redirect
        echo '<script type="text/javascript">';
        //echo "<!--";
        echo 'document.location="'. $url .'";';
        //echo "//-->";
        echo '</script>';

        // HTML redirect if js disabled
        echo '<noscript>';
        echo '<meta http-equiv="refresh" content="0;url="'.$url.'" />';
        echo '</noscript>';

        exit();
    }

    return FALSE;

} /* end of method (redirect) */

Надеюсь, что это поможет вам лучше понять, как действовать и адаптировать этот подход к вашему конкретному случаю.

Ответ 3

У меня есть аналогичная проблема с:

  • CentOS 6.3
  • Apache 2.2.15

После некоторых попыток я узнаю свою проблему.

Если я устанавливаю SSLVerifyClient optional или SSLVerifyClient optional_no_ca, и я также указываю SSLCACertificateFile или SSLCACertificatePath, Apache получает сертификат клиента только в том случае, если он освобожден из CA, найденного в файле/пути ссылки CA, указанном в конфигурации.