Изменения OpenSSL в PHP 5.6.x

Обёртки потоков теперь по умолчанию проверяют сертификаты узлов и имена хостов при использовании SSL/TLS

Все шифруемые клиентские потоки теперь по умолчанию включают проверку пиров. По умолчанию сертификат пира проверяется пакетом OpenSSL CA. Обычно не нужно ничего делать для соединения с серверами с правильным SSL-сертификатом, так как OpenSSL настроен так, что уже работает с хорошими CA-пакетами.

Стандартный CA пакет может быть переопределён глобально с помощью установки или openssl.cafile или openssl.capath строк конфигурации, или же на уровне каждого запроса используя опции контекста cafile или capath.

Хотя это и не рекомендуется, но можно отключить проверку сертификата пира для запроса, установив verify_peer опцию контекста в false, и можно отключить проверку имени пира, установив verify_peer_name в false.

Сигнатура сертификата

Была добавлена поддержка извлечения и проверки сигнатуры сертификата. Для извлечения сигнатур сертификатов X.509 добавлена функция openssl_x509_fingerprint(). Также были добавлены две опции контекста потока SSL: capture_peer_cert для захвата узлового сертификата X.509, и peer_fingerprint для проверки сертификата на соответствие заданной сигнатуре.

Обновлены шифры по умолчанию

Список шифров по умолчанию, используемых PHP, был обновлён на более безопасный в соответствии с »  рекомендациями по шифрам от Mozilla, с двумя дополнительными исключениями: анонимные шифры Диффи-Хеллмана и RC4.

Этот список доступен через новую константу OPENSSL_DEFAULT_STREAM_CIPHERS, и может быть переопределён (как и в предыдущих версиях PHP) установкой опцией контекста ciphers.

Сжатие запрещено по умолчанию

Сжатие SSL/TLS было запрещено по умолчанию для compression уменьшения вероятности атаки типа CRIME. В PHP 5.4.13 была добавлена опция контекста disable_compression для возможности запретить компрессию и теперь она по умолчанию установлена как true (то есть компрессия запрещена).

Разрешение серверу определять свой собственный порядок шифров

Была добавлена опция контекста honor_cipher_order, которая позволяет серверу обслуживающему зашифрованный поток самому определять шифры, которыми будет пользоваться клиент. Это позволить снизить риск атаки типа BEAST.

Доступ к согласованному протоколу и шифру

Протокол и шифр, согласованные для шифрованного потока, доступны с помощью функций stream_get_meta_data() или stream_context_get_options(), если опция контекста SSL capture_session_meta установлена как true.

<?php
$ctx
= stream_context_create(['ssl' => [
'capture_session_meta' => TRUE
]]);

$html = file_get_contents('https://google.com/', FALSE, $ctx);
$meta = stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta);
?>

Результат выполнения приведённого примера:

array(4) {
  ["protocol"]=>
  string(5) "TLSv1"
  ["cipher_name"]=>
  string(20) "ECDHE-RSA-AES128-SHA"
  ["cipher_bits"]=>
  int(128)
  ["cipher_version"]=>
  string(11) "TLSv1/SSLv3"
}

Новые возможности для совершенной прямой секретности (PFS) для серверов, обслуживающих шифрованные потоки

Шифрованные потоки клиента уже поддерживают совершенную прямую секретность, поскольку она, как правило, контролируется сервером. Серверы PHP, обслуживающие шифрованные потоки, использующие сертификаты поддерживающие совершенную прямую секретность не нуждаются в каких либо дополнительных действиях для включения PFS; однако, было добавлено некоторое количество новых опций контекста SSL для более точного контроля над PFS и для решения возможных проблем.

ecdh_curve

Эта опция позволяет выбрать кривую для использования в шифрах ECDH. Если не задано, то будет использоваться prime256v1.

dh_param

Путь к файлу, содержащему параметры для обмена ключами Диффи-Хеллмана, созданного, например, с помощью такой команды:

openssl dhparam -out /path/to/my/certs/dh-2048.pem 2048
single_dh_use

Если установлено как true, новая пара ключей будет создана, используя параметры Диффи-Хеллмана, тем самым улучшая прямую секретность.

single_ecdh_use

Если установлено как true, новая пара ключей будет генерироваться всегда, при согласовании шифра ECDH. Это улучшает прямую секретность.

Выбор версии SSL/TLS

Теперь возможно выбирать конкретную версию SSL и TLS с помощью опции контекста crypto_method или указывая конкретный транспорт при создании обёртки потока (например с помощью вызова stream_socket_client() или stream_socket_server()).

Опция контекста SSL crypto_method принимает битовую маску, перечисляющую допустимые протоколы, также как это задаётся в параметре crypto_type функции stream_socket_enable_crypto().

Выбранная версия протокола и соответствующие опции
Протокол Флаг клиента Флаг сервера Транспорт
Любые версии TLS или SSL STREAM_CRYPTO_METHOD_ANY_CLIENT STREAM_CRYPTO_METHOD_ANY_SERVER ssl://
Любая версия TLS STREAM_CRYPTO_METHOD_TLS_CLIENT STREAM_CRYPTO_METHOD_TLS_SERVER tls://
TLS 1.0 STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT STREAM_CRYPTO_METHOD_TLSv1_0_SERVER tlsv1.0://
TLS 1.1 STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT STREAM_CRYPTO_METHOD_TLSv1_1_SERVER tlsv1.1://
TLS 1.2 STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT STREAM_CRYPTO_METHOD_TLSv1_2_SERVER tlsv1.2://
SSL 3 STREAM_CRYPTO_METHOD_SSLv3_CLIENT STREAM_CRYPTO_METHOD_SSLv3_SERVER sslv3://
<?php

// Требуется TLS 1.0 или выше для использования file_get_contents():
$ctx = stream_context_create([
'ssl' => [
'crypto_method' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
],
]);
$html = file_get_contents('https://google.com/', false, $ctx);

// Требуется TLS 1.1 или 1.2:
$ctx = stream_context_create([
'ssl' => [
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT |
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
],
]);
$html = file_get_contents('https://google.com/', false, $ctx);

// Соединяемся с использованием транспорта потокового сокета tlsv1.2://
$sock = stream_socket_client('tlsv1.2://google.com:443/');

?>

Добавлена функция openssl_get_cert_locations()

Была добавлена функция openssl_get_cert_locations(): она возвращает расположения, в которых PHP будет искать пакеты CA по умолчанию.

<?php
var_dump
(openssl_get_cert_locations());
?>

Результат выполнения приведённого примера:

array(8) {
  ["default_cert_file"]=>
  string(21) "/etc/pki/tls/cert.pem"
  ["default_cert_file_env"]=>
  string(13) "SSL_CERT_FILE"
  ["default_cert_dir"]=>
  string(18) "/etc/pki/tls/certs"
  ["default_cert_dir_env"]=>
  string(12) "SSL_CERT_DIR"
  ["default_private_dir"]=>
  string(20) "/etc/pki/tls/private"
  ["default_default_cert_area"]=>
  string(12) "/etc/pki/tls"
  ["ini_cafile"]=>
  string(0) ""
  ["ini_capath"]=>
  string(0) ""
}

Поддержка SPKI

Была добавлена поддержка для создания, извлечения и проверки подписанных публичных ключей и опознавательных строк (SPKAC). Были добавлены функции openssl_spki_new(), openssl_spki_verify(), openssl_spki_export_challenge() и openssl_spki_export() для создания, проверки экспорта PEM публичных ключей и соответствующих опознавательных строк из SPKAC, созданных из элементов HTML5 KeyGen.

openssl_spki_new

Генерация нового SPKAC с использованием приватного ключа, опознавательной строки и алгоритма хеширования.

<?php
$pkey
= openssl_pkey_new();
openssl_pkey_export($pkey, 'secret passphrase');

$spkac = openssl_spki_new($pkey, 'challenge string');
?>

Результат выполнения приведённого примера:

SPKAC=MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYjViMzYxMTktNjY5YS00ZDljLWEyYzctMGZjNGFhMjVlMmE2MA0GCSqGSIb3DQEBAwUAA4GBAF7hu0ifzmjonhAak2FhhBRsKFDzXdKIkrWxVNe8e0bZzMrWOxFM/rqBgeH3/gtOUDRS5Fnzyq425UsTYbjfiKzxGeCYCQJb1KJ2V5Ij/mIJHZr53WYEXHQTNMGR8RPm7IxwVXVSHIgAfXsXZ9IXNbFbcaLRiSTr9/N4U+MXUWL7
openssl_spki_verify

Проверка предоставленного SPKAC.

<?php
$pkey
= openssl_pkey_new();
openssl_pkey_export($pkey, 'secret passphrase');

$spkac = openssl_spki_new($pkey, 'challenge string');
var_dump(openssl_spki_verify($spkac));
?>
openssl_spki_export_challenge

Экспорт связанной опознавательной строки из предоставленного SPKAC.

<?php
$pkey
= openssl_pkey_new();
openssl_pkey_export($pkey, 'secret passphrase');

$spkac = openssl_spki_new($pkey, 'challenge string');
$challenge = openssl_spki_export_challenge($spkac);
echo
$challenge;
?>

Результат выполнения приведённого примера:

challenge string
openssl_spki_export

Экспорт публичного ключа (PEM) RSA в формате из SPKAC.

<?php
$pkey
= openssl_pkey_new();
openssl_pkey_export($pkey, 'secret passphrase');

$spkac = openssl_spki_new($pkey, 'challenge string');
echo
openssl_spki_export($spkac);
?>

Результат выполнения приведённого примера:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcvQh9SKOPv4DwI8LwSaFx02h7
l9QCiDs6sF2GfsSTEUG61SnjQ/v4uJiLKBgbVOagj9rkSCwtTez23ATPeGaBj2Zg
ipv+tv5IXyqUP8ropXJQ5ELtbXPUN/gvw7cO5EbPHr/7eMhbpw8Gl+AfWxW5hLW8
MGw/+AwwjHBOwong/QIDAQAB
-----END PUBLIC KEY-----
add a note add a note

User Contributed Notes 1 note

up
14
Victor
9 years ago
To get back to the "old behavior" with self-signed ("snakeoil") certificates to possibly incorrect name, you need to set both options.

<?php
            $streamContext
= stream_context_create([
               
'ssl' => [
                   
'verify_peer'      => false,
                   
'verify_peer_name' => false
               
]
            ]);
           
$contents = file_get_contents('https://url', false, $streamContext);
?>
To Top