<p>httpie se niega a confiar en un certificado autofirmado</p>

Creado en 25 abr. 2017  ·  9Comentarios  ·  Fuente: httpie/httpie

No entiendo completamente la discusión sobre el problema # 480, pero creo que la causa raíz puede ser la misma para este problema. Necesito httpie para confiar en un certificado autofirmado. Técnicamente, es una autoridad certificadora intermedia autofirmada, pero puedo usar uno de los certificados de servidor reales de esa autoridad y obtener el mismo resultado. Este certificado cumple con todas las demás aplicaciones de mi Mac (OS 10.12), incluido curl. Httpie simplemente no se fiará de él. Salida de muestra:

$ http --debug -j --verify=/usr/local/etc/openssl/certs/intermediate-authority.pem https://www.testdomain.com/robots.txt
HTTPie 0.9.9
Requests 2.12.3
Pygments 2.1.3
Python 3.6.1 (default, Mar 24 2017, 17:14:46)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
/usr/local/Cellar/httpie/0.9.9/libexec/bin/python3.6
Darwin 16.5.0

<Environment {
    "colors": 256,
    "config": {
        "__meta__": {
            "about": "HTTPie configuration file",
            "help": "https://github.com/jkbrzt/httpie#config",
            "httpie": "0.9.4"
        },
        "default_options": "[]"
    },
    "config_dir": "/Users/username/.httpie",
    "is_windows": false,
    "stderr": "<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>",
    "stderr_isatty": true,
    "stdin": "<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>",
    "stdin_encoding": "UTF-8",
    "stdin_isatty": true,
    "stdout": "<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>",
    "stdout_encoding": "UTF-8",
    "stdout_isatty": true
}>

>>> requests.request(**{
    "allow_redirects": false,
    "auth": "None",
    "cert": "None",
    "data": "",
    "files": {},
    "headers": {
        "Accept": "application/json, */*",
        "Content-Type": "application/json",
        "User-Agent": "HTTPie/0.9.9"
    },
    "method": "get",
    "params": {},
    "proxies": {},
    "stream": true,
    "timeout": 30,
    "url": "https://www.testdomain.com/robots.txt",
    "verify": "/usr/local/etc/openssl/certs/intermediate-authority.pem"
})


http: error: SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749) while doing GET request to URL: https://www.testdomain.com/robots.txt
Traceback (most recent call last):
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/packages/urllib3/connectionpool.py", line 588, in urlopen
    self._prepare_proxy(conn)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/packages/urllib3/connectionpool.py", line 801, in _prepare_proxy
    conn.connect()
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/packages/urllib3/connection.py", line 323, in connect
    ssl_context=context)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/packages/urllib3/util/ssl_.py", line 324, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 401, in wrap_socket
    _context=self, _session=session)
  File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 808, in __init__
    self.do_handshake()
  File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 1061, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 683, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/adapters.py", line 423, in send
    timeout=timeout
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/packages/urllib3/connectionpool.py", line 624, in urlopen
    raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/http", line 11, in <module>
    load_entry_point('httpie==0.9.9', 'console_scripts', 'http')()
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/httpie/__main__.py", line 11, in main
    sys.exit(main())
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/httpie/core.py", line 227, in main
    log_error=log_error,
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/httpie/core.py", line 99, in program
    final_response = get_response(args, config_dir=env.config.directory)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/httpie/client.py", line 70, in get_response
    response = requests_session.request(**kwargs)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/Cellar/httpie/0.9.9/libexec/lib/python3.6/site-packages/requests/adapters.py", line 497, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)

Si utilizo --verify=no , se acepta la conexión. Intenté convertir el archivo de certificado a formato DER en lugar de PEM sin cambios.

Httpie se instaló a través de Homebrew, que instaló su propio Python3 como dependencia.

Comentario más útil

Nunca se recomienda confiar en un certificado autofirmado. Es peligroso si un programa lo acepta por defecto. Un pirata informático puede simplemente inyectar uno autofirmado para que los usuarios se sientan seguros mientras no sea el caso.

Sin embargo, sugeriría httpie para responder al problema de usar un certificado autofirmado con un mensaje más claro en lugar de simplemente fallar. Una sugerencia de usar --verify=no para deshabilitar la verificación con fines de prueba sería excelente.

Todos 9 comentarios

Nunca se recomienda confiar en un certificado autofirmado. Es peligroso si un programa lo acepta por defecto. Un pirata informático puede simplemente inyectar uno autofirmado para que los usuarios se sientan seguros mientras no sea el caso.

Sin embargo, sugeriría httpie para responder al problema de usar un certificado autofirmado con un mensaje más claro en lugar de simplemente fallar. Una sugerencia de usar --verify=no para deshabilitar la verificación con fines de prueba sería excelente.

@ giskard22

No entiendo completamente la discusión sobre el problema # 480, pero creo que la causa raíz puede ser la misma para este problema. Necesito httpie para confiar en un certificado autofirmado. Técnicamente, es una autoridad certificadora intermedia autofirmada, pero puedo usar uno de los certificados de servidor reales de esa autoridad y obtener el mismo resultado.

Mirando el # 480, esta no es la misma causa raíz. HTTPie está, en este caso, usando el paquete que le proporcionaste.

Lo que sospecho que es en realidad la causa es la siguiente:

Su "dominio de prueba" no está devolviendo la cadena de certificados completa, sino solo su hoja (que funciona bien para los navegadores que pueden recuperar dinámicamente el resto de la cadena) pero no para httpie y otros clientes que no sean navegadores. En este caso, está proporcionando parte de la cadena a través de --verify pero aún no todos los intermediarios. Si los coloca todos en un paquete y lo proporciona en su lugar, sospecho que encontrará que esto funciona.

Nunca se recomienda confiar en un certificado autofirmado. Es peligroso si un programa lo acepta por defecto. Un pirata informático puede simplemente inyectar uno autofirmado para que los usuarios se sientan seguros mientras no sea el caso.

El consejo general de @ giskard22 para usar un certificado autofirmado aquí y usted tampoco. En ese caso, su consejo no solo es inútil para @ giskard22 , también es un ruido para el resto de las personas que reciben notificaciones por correo electrónico sobre problemas en este repositorio.

Puede ser peligroso confiar en los certificados autofirmados sin verificación, pero en este caso parece que @ giskard22 conoce la cadena de confianza y confía en ella, lo que hace que este uso sea perfectamente seguro. Sí, si por casualidad con un sitio mediante HTTPS que es posible que tenga que introducir la información sensible en, no es recomendable utilizar un certificado autofirmado, pero esta es una situación muy diferentes como lo entiendo.

Sí, el caso de uso aquí es el uso de httpie a través de un proxy web corporativo que hace HTTPS man-in-the-middle para que pueda inspeccionar el tráfico. Genera un certificado específico de dominio sobre la marcha. Paja.

No entiendo cómo el hecho de que el proxy no proporcione una cadena de certificados completa causa este problema. Quizás el comportamiento de OpenSSL (¿o es el comportamiento de Python?) Es diferente al mecanismo integrado de MacOS.

La cadena de confianza para las conexiones a través del proxy se ve así:

  1. Certificado sobre la marcha emitido a www.testdomain.com
  2. Certificado de CA intermedio llamado nombre-proxy
  3. Certificado de CA raíz autofirmado llamado nombre de la empresa

No he podido obtener el certificado 3. Sin embargo, el certificado 2 está disponible en el proxy. Lo importé a mi llavero y lo marqué de confianza para el uso de SSL. Eso fue suficiente para satisfacer todos los aspectos de mi Mac, excepto httpie, incluidas otras herramientas de línea de comandos como curl. El comportamiento observado es que el mecanismo de validación sigue la cadena hasta que encuentra un certificado confiable y luego se detiene. La ausencia del certificado raíz es irrelevante.

En la salida de depuración de httpie que publiqué en mi informe inicial, había almacenado el certificado 2 en intermediate-authority.pem y especificaba ese archivo con --verify . ¿Estás diciendo que para httpie, eso no es suficiente y también debo proporcionar el certificado 3?

Quizás el comportamiento de OpenSSL (¿o es el comportamiento de Python?) Es diferente al mecanismo integrado de MacOS.

Por lo tanto, OpenSSL buscará en el paquete que le proporcione lo que falte. Si no puede encontrarlo allí, no pasa la verificación. Esto también es transitivamente el comportamiento de Python. SecureTransport (el mecanismo integrado de MacOS) funciona de manera ligeramente diferente, pero solo si los certificados están en el llavero de MacOS. Además, en MacOS, el Python predeterminado tiene una versión pirateada (a falta de un término mejor) de OpenSSL que usa Keychain y, por lo tanto, puede resolverlos incluso si le proporciona su propio paquete de certificados (es decir, si solo le dice que confíe lo que hay en un archivo de paquete, dirá "LOL, pero tengo acceso a Llavero y eso confía tanto en YOLO" ... o YOVO? (Solo verifica una vez ... Idk)).

Si la cadena de confianza completa para estos certificados sobre la marcha es lo que describió, creo que debería poder salirse con la suya con un paquete que solo incluye los eslabones 2 y 3 de la cadena.

Además, si instaló httpie desde homebrew en MacOS, entonces se instaló con las versiones caseras de OpenSSL , Python y virtualenv por eso no puede aprovechar el OpenSSL pirateado de Mac.

Finalmente pude identificar y obtener el certificado raíz autofirmado. Al poner tanto ese certificado como el certificado intermedio en un archivo .pem y usar ese archivo con --verify , ya no recibí el error SSL. ¡Esto es bueno! Como se sugiere, OpenSSL requiere toda la cadena de certificados. A diferencia de SecureTransport, no aceptará una cadena parcial incluso si se suministra manualmente.

¿Alguna idea sobre la siguiente complicación adicional? El proxy permite que el tráfico vaya a ciertos dominios sin insertar su certificado personalizado. Parece que no puede utilizar varios argumentos --verify . El último gana. ¿Hay alguna forma de utilizar varios paquetes de certificados?

Tengo una solución que implica concatenar el paquete de CA raíz proporcionado por OpenSSL y el paquete personalizado a pedido, pero con la esperanza de evitarlo.

Por lo tanto, OpenSSL admite proporcionar un directorio lleno de archivos .pem para verificación. Dicho esto, el soporte para eso en Python es irregular. Honestamente, no creo que nada más antiguo que Python 3.5 o 3.6 admita directorios en la biblioteca estándar y no recuerdo si pyOpenSSL lo admitirá. En resumidas cuentas, no creo que puedas lograr tus fines sin tener un archivo .pem sirva para todos. El otro inconveniente aquí es que la biblioteca de transporte HTTP que usa HTTPie no es compatible con directorios, dado el soporte limitado entre las versiones y las implementaciones de la biblioteca TLS.

viejo cartero al rescate. Puede desactivar la detección de certificado autofirmado.

SSL es bueno, probablemente los desarrolladores lo sepan. Deshabilitar SSL debido a casos de esquina y limitaciones de idioma o lo que sea que apesta. Sé que la gente solo quiere trabajar. Me pregunto cuándo diremos que SSL es bueno y tendremos la misma reacción instintiva al decir "deshabilitar la verificación SSL". Si desactiva la verificación SSL, SSL está desactivado. Pero SSL es bueno. Todos lo sabemos, ¿verdad? ¿Es confuso o de conocimiento común que la verificación SSL es realmente lo que es SSL? Si el cartero tiene una opción para deshabilitar la verificación SSL, ¿es solo una forma elegante de decir algo que es potencialmente inseguro? curl tiene la misma opción que una bandera llamada --insecure . ¿Es solo una forma elegante que oculta exactamente cuál es el problema (desactiva SSL)? Creo que está bien probar en Postman. HASTA que Postman tiene esa opción. ¿Voy a volver a encenderlo? ¿O simplemente desactivé SSL para cada proyecto actual y futuro? ¿Estoy enviando claves API desde una cafetería? : |

Espero que las máquinas de desarrollo https, los certificados autofirmados y las CA corporativas sean suplantados algún día por los certificados letsencrypt automáticos programables. Es una pena que python haga que http sea menos orgánico al confiar en la tienda keychain / ssl del sistema. Es un reemplazo de rizos excepto en esta área. Supongo que Golang tiene detección de sistema operativo para todas estas cosas. Por lo tanto, un reemplazo de curl moderno (como bat) escrito en go tendría un resultado agradable, una experiencia CLI agradable y manejaría CA personalizadas o terminación ssl (balanceadores de carga).

SSL es bueno, probablemente los desarrolladores lo sepan. Deshabilitar SSL debido a casos de esquina y limitaciones de idioma o lo que sea que apesta. Sé que la gente solo quiere trabajar. Me pregunto cuándo diremos que SSL es bueno y tendremos la misma reacción instintiva al decir "deshabilitar la verificación SSL". Si desactiva la verificación SSL, SSL está desactivado. Pero SSL es bueno. Todos lo sabemos, ¿verdad? ¿Es confuso o de conocimiento común que la verificación SSL es realmente lo que es SSL? Si el cartero tiene una opción para deshabilitar la verificación SSL, ¿es solo una forma elegante de decir algo que es potencialmente inseguro? curl tiene la misma opción que una bandera llamada --insecure . ¿Es solo una forma elegante que oculta exactamente cuál es el problema (desactiva SSL)? Creo que está bien probar en Postman. HASTA que Postman tiene esa opción. ¿Voy a volver a encenderlo? ¿O simplemente desactivé SSL para cada proyecto actual y futuro? ¿Estoy enviando claves API desde una cafetería? : |

Espero que las máquinas de desarrollo https, los certificados autofirmados y las CA corporativas sean suplantados algún día por los certificados letsencrypt automáticos programables. Es una pena que python haga que http sea menos orgánico al confiar en la tienda keychain / ssl del sistema. Es un reemplazo de rizos excepto en esta área. Supongo que Golang tiene detección de sistema operativo para todas estas cosas. Por lo tanto, un reemplazo de curl moderno (como bat) escrito en go tendría un resultado agradable, una experiencia CLI agradable y manejaría CA personalizadas o terminación ssl (balanceadores de carga).

No, no es bueno. Necesita poder curvar incluso si tiene un certificado de desarrollador ad hoc.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

aventurella picture aventurella  ·  13Comentarios

luv picture luv  ·  20Comentarios

whodidthis picture whodidthis  ·  24Comentarios

drgomesp picture drgomesp  ·  10Comentarios

winneon picture winneon  ·  9Comentarios