php - validar - Error de SSL SSL3_GET_SERVER_CERTIFICATE: no se pudo verificar el certificado
verificar certificado ssl (8)
Después de actualizar a PHP 5.6 me sale un error al intentar conectarme a un servidor a través de fsockopen()
..
El certificado en el servidor (host) está auto-firmado
Advertencia de PHP: fsockopen (): la operación SSL falló con el código 1. Mensajes de error de OpenSSL: error: 14090086: rutinas SSL: SSL3_GET_SERVER_CERTIFICATE: verificación de certificado fallido
código
if($fp = fsockopen($host, $port, $errno, $errstr, 20)){
$this->request = ''POST ''.substr($this->url, strlen($this->host)).'' HTTP/1.1''.$crlf
.''Host: ''.$this->host.$crlf
.''Content-Length: ''.$content_length.$crlf
.''Connection: Close''.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while($line = fgets($fp)){
if($line !== false){
$this->response .= $line;
}
}
fclose($fp);
}
He intentado
# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem
php.ini
openssl.cafile = "/etc/ssl/certs/cacert.pem"
Pero el script aún no funciona
actualizar
Esto funciona
echo file_get_contents("/etc/ssl/certs/cacert.pem");
actualización 2
$contextOptions = array(
''ssl'' => array(
''verify_peer'' => true, // You could skip all of the trouble by changing this to false, but it''s WAY uncool for security reasons.
''cafile'' => ''/etc/ssl/certs/cacert.pem'',
//''CN_match'' => ''example.com'', // Change this to your certificates Common Name (or just comment this line out if not needed)
''ciphers'' => ''HIGH:!SSLv2:!SSLv3'',
''disable_compression'' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
error
Advertencia de PHP: stream_socket_client (): la operación SSL falló con el código 1. Mensajes de error de OpenSSL: error: 14090086: rutinas SSL: SSL3_GET_SERVER_CERTIFICATE: verificación de certificado fallida
¿Has intentado utilizar el método stream_context_set_option()
?
$context = stream_context_create();
$result = stream_context_set_option($context, ''ssl'', ''local_cert'', ''/etc/ssl/certs/cacert.pem'');
$fp = fsockopen($host, $port, $errno, $errstr, 20, $context);
Además, pruebe file_get_contents()
para el archivo pem, para asegurarse de tener permisos para acceder a él, y asegúrese de que el nombre de host coincida con el certificado.
Añadir
$mail->SMTPOptions = array(
''ssl'' => array(
''verify_peer'' => false,
''verify_peer_name'' => false,
''allow_self_signed'' => true
));
antes de
mail->send()
y reemplazar
require "mailer/class.phpmailer.php";
con
require "mailer/PHPMailerAutoload.php";
El archivo que descargó ( http://curl.haxx.se/ca/cacert.pem ) es un conjunto de certificados raíz de las principales autoridades de certificación confiables. Usted dijo que el host remoto tiene un certificado SSL autofirmado, por lo que no usó un certificado de confianza. La configuración openssl.cafile
debe apuntar al certificado CA que se utilizó para firmar el certificado SSL en el host remoto. PHP 5.6 se ha mejorado con respecto a versiones anteriores de PHP para verificar ahora los certificados de pares y los nombres de host de forma predeterminada ( http://php.net/manual/en/migration56.openssl.php )
Deberá localizar el certificado de CA que se generó en el servidor que firmó el certificado SSL y copiarlo en este servidor. La única otra opción es deshabilitar la verificación del par, pero eso anula la seguridad SSL. Si DESEA intentar deshabilitar la verificación, pruebe esta matriz con el código de mi respuesta anterior:
$contextOptions = array(
''ssl'' => array(
''verify_peer'' => false,
''verify_peer_name'' => false
)
);
De cualquier manera, si usa certificados autofirmados, deberá agregar el certificado de CA que se utilizó para firmar el certificado SSL del host remoto al almacén de confianza en el servidor al que se está conectando O usar contextos de flujo para usar ese certificado para cada solicitud individual. Agregarlo a los certificados de confianza es la solución más simple. Simplemente agregue los contenidos del certificado de CA del host remoto al final del archivo cacert.pem que descargó.
Anterior:
fsockopen no admite contextos de flujo, por lo tanto, use stream_socket_client en su lugar. Devuelve un recurso que se puede usar con todos los comandos que fsockopen los recursos pueden.
Esto debería ser una gota en reemplazo del fragmento que tienes en tu pregunta:
<?php
$contextOptions = array(
''ssl'' => array(
''verify_peer'' => true, // You could skip all of the trouble by changing this to false, but it''s WAY uncool for security reasons.
''cafile'' => ''/etc/ssl/certs/cacert.pem'',
''CN_match'' => ''example.com'', // Change this to your certificates Common Name (or just comment this line out if not needed)
''ciphers'' => ''HIGH:!SSLv2:!SSLv3'',
''disable_compression'' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
if (!$fp) {
echo "$errstr ({$errno})<br />/n";
}else{
$this->request = ''POST ''.substr($this->url, strlen($this->host)).'' HTTP/1.1''.$crlf
.''Host: ''.$this->host.$crlf
.''Content-Length: ''.$content_length.$crlf
.''Connection: Close''.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while (!feof($fp)) {
$this->response .= fgets($fp);
}
fclose($fp);
}
El problema está en la nueva versión de PHP en macOS Sierra
Por favor añadir
stream_context_set_option($ctx, ''ssl'', ''verify_peer'', false);
En mi caso, estaba en CentOS 7 y mi instalación de php apuntaba a un certificado que se generaba a través de update-ca-trust
. El enlace simbólico fue /etc/pki/tls/cert.pem
apuntando a /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
. Este era solo un servidor de prueba y quería que mi certificado autofirmado funcionara correctamente. Entonces en mi caso ...
# My root ca-trust folder was here. I coped the .crt file to this location
# and renamed it to a .pem
/etc/pki/ca-trust/source/anchors/self-signed-cert.pem
# Then run this command and it will regenerate the certs for you and
# include your self signed cert file.
update-ca-trust
Luego, algunas de mis llamadas de API comenzaron a funcionar ya que ahora se confiaba en mi certificado. Además, si su ca-trust se actualiza a través de yum o algo así, esto reconstruirá sus certificados raíz y aún incluirá su certificado autofirmado. Ejecute man update-ca-trust
para obtener más información sobre qué hacer y cómo hacerlo. :)
Me enfrenté a un problema similar durante el trabajo con Ubuntu 16.04 al usar Docker. En mi caso, eso era un problema con Composer, pero el mensaje de error (y por lo tanto el problema) era el mismo.
Debido a la imagen base minimalista orientada a Docker, me faltaba el paquete de ca-certificates
y los simples ca-certificates
apt-get install ca-certificates
me ayudaron.
Si está utilizando macOS sierra, hay una actualización en la versión de PHP. necesita tener el archivo de la Autoridad de certificación de Entrust.net (2048) agregado al código PHP. más información check aceptado respuesta aquí Push Notification in PHP using PEM file
Usted menciona que el certificado es autofirmado (por usted)? Entonces tienes dos opciones:
- agregue el certificado a su tienda de confianza (ir a buscar
cacert.pem
desde el sitio web de cURL no hará nada, ya que está auto-firmado) - no te molestes en verificar el certificado: confías en ti mismo, ¿verdad?
Aquí hay una lista de opciones de contexto SSL en PHP: https://secure.php.net/manual/en/context.ssl.php
Establezca allow_self_signed
si importa su certificado en su tienda de confianza o establezca verify_peer
en false para omitir la verificación.
La razón por la que confiamos en un certificado específico es porque confiamos en su emisor . Como su certificado está autofirmado, ningún cliente confiará en el certificado ya que el firmante (usted) no es de confianza. Si creó su propia CA al firmar el certificado, puede agregarla a su depósito de confianza. Si su certificado no contiene ninguna CA, entonces no puede esperar que nadie se conecte a su servidor.