Была у меня на работе задачка — сделать авторизацию пользователей на сайте через сертификаты X.509. Вроде бы, всё просто – погуглил, почитал, оказалось, десятки разных статей и все противоречат друг другу.
Создание сертификатов
Первое, что сделаем, это создадим серверный и клиентские сертификаты. Нужна програмка openssl.exe (у меня установлен xampp, в нём есть всё, что нужно – вам его тоже советую). Итак, в папке /сервер/apache/bin находим openssl.exe и создаём файлы ca.config и openssl.cnf. Также, создадим папку db, а в ней папки certs, newcerts, пустые текстовые файлы index.txt и serial (внутри этого файла написать “01” без ковычек.)
Содержимое файла ca.config
[ ca ]
default_ca = CA_CLIENT # При подписи сертификатов
# использовать секцию CA_CLIENT
[ CA_CLIENT ]
dir = ./db # Каталог для служебных файлов
certs = $dir/certs # Каталог для сертификатов
new_certs_dir = $dir/newcerts # Каталог для новых сертификатов
database = $dir/index.txt # Файл с базой данных
# подписанных сертификатов
serial = $dir/serial # Файл содержащий серийный номер
# сертификата
# (в шестнадцатиричном формате)
certificate = ./ca.crt # Файл сертификата CA
private_key = ./ca.key # Файл закрытого ключа CA
default_days = 365 # Срок действия подписываемого
# сертификата
default_crl_days = 7 # Срок действия CRL (см. $4)
default_md = md5 # Алгоритм подписи
policy = policy_anything # Название секции с описанием
# политики в отношении данных
# сертификата
[ policy_anything ]
countryName = optional # Код страны – не обязателен
stateOrProvinceName = optional # ……
localityName = optional # ……
organizationName = optional # ……
organizationalUnitName = optional # ……
commonName = supplied # …… – обязателен
emailAddress = optional # …… |
Содержимое файла openssl.cnf
# =================================================
# OpenSSL configuration file
# =================================================
RANDFILE = .rnd
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir
new_certs_dir = $dir
crl_dir = $dir
database = $dir/db/index.txt
private_key = $dir/ca.key
certificate = $dir/ca.crt
serial = $dir/db/serial
crl = $dir/crl.pem
RANDFILE = $dir/db/private/.rand
default_days = 365
default_crl_days = 30
default_md = sha1
preserve = no
policy = policy_anything
name_opt = ca_default
cert_opt = ca_default
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024
default_md = sha1
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
string_mask = nombstr
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ usr_cert ]
basicConstraints = CA:FALSE
# nsCaRevocationUrl = https://url-to-exposed-clr-list/crl.pem
[ ssl_server ]
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, nsSGC, msSGC
nsComment = «OpenSSL Certificate for SSL Web Server»
[ ssl_client ]
basicConstraints = CA:FALSE
nsCertType = client
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
nsComment = «OpenSSL Certificate for SSL Client»
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
basicConstraints = critical, CA:true, pathlen:0
nsCertType = sslCA
keyUsage = cRLSign, keyCertSign
extendedKeyUsage = serverAuth, clientAuth
nsComment = «OpenSSL CA Certificate»
[ crl_ext ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
nsComment = «OpenSSL generated CRL» |
открываем cmd.exe (Пуск –> Выполнить –> cmd –> enter), далее запускаем через cmd программу openssl.exe и приступаем непосредственно к созданию наших сертификатов.
1) создаём серверный ключ и сертификат
req -new -x509 -days 365 -sha1 -newkey rsa:1024 -nodes -keyout server.key -out server.crt -subj ‘/O=НазваниеКомпании/OU=Подразделение/CN=localhost’
Укажите здесь название вашей компании, подразделения, а также доменное имя.
2) создаём CA сертификат для авторизации пользователей
req -config openssl.cnf -new -x509 -days 3652 -sha1 -newkey rsa:1024 -keyout ca.key -out ca.crt -subj ‘/O=Организация/OU=Подразделение’
Укажите здесь название вашей компании, подразделения.
3) создаём пользовательские сертификаты
- req -new -sha1 -newkey rsa:1024 -nodes -keyout server.key -out request.pem -subj ‘/O=Skif Grid/OU=PSI RAS/CN=localhost’
- ca -config openssl.cnf -policy policy_anything -extensions ssl_server -out signed.pem -infiles request.pem
- x509 -in signed.pem -out server.crt
- openssl pkcs12 -export –in signed.pem –inkey server.key -certfile ca.crt -name «Имя\Отчество» -out user.p12
Получившееся ca.crt и user.p12 импортируем в браузер. С сертификатами покончено, теперь пришло время Apach’a.
Настройка Apache
Открываем файл /сервер/apache/conf/extra/httpd-ssl.conf, стираем всё, что там есть и копируем туда следующее:
ErrorLog D:/www/apache/logs/ssl_error.log
LogLevel warn
Listen 443
AddType application/x-x509-ca-cert .crt .pem
AddType application/x-pkcs7-crl .crl
AddType application/x-pkcs12-cert .p12
SSLPassPhraseDialog builtin
SSLSessionCache dbm:logs/ssl.scache
SSLSessionCacheTimeout 300
SSLMutex default
SSLOptions +StdEnvVars +ExportCertData +StrictRequire
NameVirtualHost *:443
<VirtualHost _default_:443>
AddDefaultCharset utf-8
AddCharset utf-8 *
DocumentRoot «D:/www/htdocs»
ServerName http://www.youhost.ru:443
ServerAdmin admin@nocrash.ru.ru
ErrorLog D:/www/apache/logs/ssl_error1.log
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLProtocol all -SSLv2
SSLOptions +StdEnvVars +ExportCertData
SSLCertificateFile conf/ssl/server.crt
SSLCertificateKeyFile conf/ssl/server.key
SSLCACertificateFile conf/ssl/ca/ca.crt
SSLVerifyClient require
SSLVerifyDepth 1
SSLProxyEngine off
<Location />
</Location>
SetEnvIf User-Agent ..*MSIE.*. nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
</VirtualHost> |
Если мы хотим сделать авторизацию не обязательной (скажем, чтобы, если у пользователя не будет сертификата, то показать ему красивую страничку с надписью, скажем – получите сначала сертификат), то SSLVerifyClient поставьте как optional.
В папке /сервер/apache/conf/ создадим папку ssl. В неё скопируем созданные нами чуть раньше файлы server.crt, server.key, ca.crt
Проверяем
Если сервер был запущен – перезапустите его. Создадим простенькую страничку на php со следующем кодом:
<?
echo “<pre>”;
print_r($_SERVER);
echo “</pre>”;
?> |
Сохраним, и зайдём на неё через https, т.е, скажем так: https://localhost/ssl_try.php
Браузер должен показать вам окно выбора сертификата. Если SSLVerifyClient установлен как require, то при неправильном сертификате браузер выдаст вам страницу с ошибкой.
Если же всё прошло хорошо, то мы увидим нашу страницу со всеми серверными переменными, включая SSL_CLIENT_CERT, в котором хранится клиентский сертификат (из неё же можно будет вытащить, при необходимости, нужные нам данные – имя, организация, email и т.д.)
Полезные ссылки
- OpenSSL Functions
- X.509 PKI LOGIN WITH PHP AND APACHE
- Client certificates with apache
- Авторизация с помощью клиентских SSL сертификатов.
-0.296630
0.071411