<p>httpie 拒绝信任自签名证书</p>

创建于 2017-04-25  ·  9评论  ·  资料来源: httpie/httpie

我不完全理解问题 #480 的讨论,但我认为这个问题的根本原因可能是相同的。 我需要 httpie 来信任自签名证书。 从技术上讲,它是一个自签名中间证书颁发机构,但我可以使用来自该机构的实际服务器证书之一并获得相同的结果。 该证书满足我的 Mac (OS 10.12) 上的所有其他应用程序,包括 curl。 Httpie 根本不会相信它。 示例输出:

$ 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)

如果我使用--verify=no ,则接受连接。 我已经尝试将证书文件转换为 DER 格式而不是 PEM 而不做任何更改。

Httpie 是通过 Homebrew 安装的,它安装了自己的 Python3 作为依赖项。

最有用的评论

从不鼓励信任自签名证书。 如果程序默认接受它是危险的。 黑客可以简单地注入一个自签名的,让用户感到安全,而事实并非如此。

但是,我建议httpie以更清晰的消息回应使用自签名证书的问题,而不是简单地失败。 建议使用--verify=no禁用测试目的的验证会很棒。

所有9条评论

从不鼓励信任自签名证书。 如果程序默认接受它是危险的。 黑客可以简单地注入一个自签名的,让用户感到安全,而事实并非如此。

但是,我建议httpie以更清晰的消息回应使用自签名证书的问题,而不是简单地失败。 建议使用--verify=no禁用测试目的的验证会很棒。

@giskard22

我不完全理解问题 #480 的讨论,但我认为这个问题的根本原因可能是相同的。 我需要 httpie 来信任自签名证书。 从技术上讲,它是一个自签名中间证书颁发机构,但我可以使用来自该机构的实际服务器证书之一并获得相同的结果。

看看#480,这不是同一个根本原因。 在这种情况下,HTTPie 使用您提供的包。

我怀疑实际上是以下原因:

您的“测试域”不返回完整的证书链,而只返回它的叶子(这对于可以动态检索链的其余部分的浏览器工作正常)但不适用于 httpie 和其他非浏览器客户端。 在这种情况下,您通过--verify提供链的一部分,但仍然不是所有的中介。 如果您将它们全部放在一个包中并提供它,我怀疑您会发现这是有效的。

从不鼓励信任自签名证书。 如果程序默认接受它是危险的。 黑客可以简单地注入一个自签名的,让用户感到安全,而事实并非如此。

@alvis一揽子建议通常是错误的,在这种情况下,这是非常错误的。 自签名证书是解决问题的方法。 我不知道@giskard22在这里使用自签名证书的用例,你也不知道。 在这种情况下,您的建议不仅很可能对@giskard22 毫无用处,而且对于其他收到来自此存储库问题的电子邮件通知的人来说也是一种噪音。

未经验证就信任自签名证书可能很危险,但在这种情况下, @giskard22似乎知道信任链并信任它,从而使这种用法非常安全。 是的,如果您遇到使用 HTTPS 的站点,您可能需要在其中输入敏感信息,则不建议使用自签名证书,但据我所知,这是一种截然不同的情况。

是的,这里的用例是通过公司 Web 代理使用 httpie,该代理执行 HTTPS 中间人,因此它可以检查流量。 它会即时生成特定于域的证书。 废话。

我不明白代理未能提供完整证书链是如何导致此问题的。 也许 OpenSSL 的行为(或者是 Python 的行为?)与 MacOS 的内置机制不同。

通过代理连接的信任链如下所示:

  1. 即时证书颁发给www.testdomain.com
  2. 称为代理名称的中间 CA 证书
  3. 名为 company-name 的自签名根 CA 证书

我一直无法获得证书 3。但是,可以从代理获得证书 2。 我导入到我的钥匙串中,并将其标记为可信任以供 SSL 使用。 这足以满足我 Mac 上除了 httpie 之外的所有内容,包括 curl 等其他命令行工具。 观察到的行为是验证机制遵循链,直到找到受信任的证书,然后停止。 根证书的缺失是无关紧要的。

在我在初始报告中发布的 httpie 调试输出中,我将证书 2 存储在intermediate-authority.pem并使用--verify指定了该文件。 你是说对于httpie,这还不够,我还必须提供证书3?

也许 OpenSSL 的行为(或者是 Python 的行为?)与 MacOS 的内置机制不同。

因此,OpenSSL 将在您提供的包中查找缺少的任何内容。 如果在那里找不到它,则验证失败。 这也是 Python 的传递行为。 SecureTransport(MacOS 的内置机制)的工作方式略有不同,但前提是证书位于 MacOS 的钥匙串中。 此外,在 MacOS 上,默认 Python 有一个使用 Keychain 的 OpenSSL 修改版(由于缺乏更好的术语),因此即使您提供自己的证书包(即,如果您告诉它只信任它)也可以解决这些问题捆绑文件中有什么,它会说“LOL,但我获得了钥匙串访问权限并且信任它,所以YOLO”......或YOVO?(你只验证一次......Idk))。

如果这些动态证书的整个信任链如您所描述的那样,我认为您应该能够摆脱包含链中链接 2 和 3 的捆绑包。

此外,如果您在 MacOS 上从homebrew安装了httpie ,那么它会与OpenSSLPythonvirtualenv的自制版本一起安装这就是为什么它不能利用 Mac 被黑客入侵的 OpenSSL。

我终于能够识别并获得自签名根证书。 将该证书和中间证书放在 .pem 文件中并将该文件与--verify ,我不再收到 SSL 错误。 这很好! 正如所建议的,OpenSSL 需要整个证书链。 与 SecureTransport 不同,即使手动提供,它也不会接受部分链。

对以下额外的并发症有什么想法吗? 代理允许流量进入某些域,而无需插入其自定义证书。 看起来您不能使用多个--verify参数。 最后一位获胜。 有没有办法使用多个证书包?

我有一个解决方法,涉及根据需要连接 OpenSSL 提供的根 CA 包和自定义包,但希望避免这种情况。

所以OpenSSL 支持提供一个充满.pem文件的目录用于验证。 也就是说,在 Python 中对此的支持参差不齐。 老实说,我不认为比 Python 3.5 或 3.6 更旧的任何东西支持标准库中的目录,我不记得 pyOpenSSL 是否会支持它。 简而言之,我认为如果没有一个全能的.pem文件,您就无法完成目标。 这里的另一个问题是 HTTPie 使用的 HTTP 传输库并不完全支持目录,因为跨版本和 TLS 库实现的支持有限。

老邮差来救援。 您可以关闭自签名证书的检测。

SSL 很好,开发人员可能知道这一点。 由于极端情况和语言限制或其他任何问题而禁用 SSL。 我知道人们只是想完成工作。 我只是想知道我们什么时候会说 SSL 很好,并且在说“禁用 SSL 验证”时会有同样的直觉反应。 如果禁用 SSL 验证,则 SSL 处于关闭状态。 但是 SSL 很好。 我们都知道吧? SSL验证确实是整个SSL的事情,这是否令人困惑或常识? 如果邮递员可以选择禁用 SSL 验证,这只是一种表达可能不安全的东西的奇特方式吗? curl 具有与名为--insecure的标志相同的选项。 它只是隐藏了问题所在的奇特方式(它关闭了 SSL)? 我觉得在 Postman 中测试是可以的。 直到邮递员有那个选项。 我要重新打开它吗? 还是我只是为每个当前和未来的项目禁用了 SSL? 我是从咖啡店发送 API 密钥吗? :|

我希望 https 开发机器、自签名证书和企业 CA 有一天会被可编写脚本的自动 Letencrypt 证书所取代。 遗憾的是,python 在信任系统钥匙串 / ssl 存储方面使 http 变得不那么自然。 除了这个区域外,它是一个卷曲替代品。 我猜 golang 对所有这些东西都有操作系统检测。 因此,用 go 编写的现代 curl 替换(如 bat)将具有漂亮的输出、良好的 CLI 体验并处理自定义 CA 或 ssl 终止(负载平衡器)。

SSL 很好,开发人员可能知道这一点。 由于极端情况和语言限制或其他任何问题而禁用 SSL。 我知道人们只是想完成工作。 我只是想知道我们什么时候会说 SSL 很好,并且在说“禁用 SSL 验证”时会有同样的直觉反应。 如果禁用 SSL 验证,则 SSL 处于关闭状态。 但是 SSL 很好。 我们都知道吧? SSL验证确实是整个SSL的事情,这是否令人困惑或常识? 如果邮递员可以选择禁用 SSL 验证,这只是一种表达可能不安全的东西的奇特方式吗? curl 具有与名为--insecure的标志相同的选项。 它只是隐藏了问题所在的奇特方式(它关闭了 SSL)? 我觉得在 Postman 中测试是可以的。 直到邮递员有那个选项。 我要重新打开它吗? 还是我只是为每个当前和未来的项目禁用了 SSL? 我是从咖啡店发送 API 密钥吗? :|

我希望 https 开发机器、自签名证书和企业 CA 有一天会被可编写脚本的自动 Letencrypt 证书所取代。 遗憾的是,python 在信任系统钥匙串 / ssl 存储方面使 http 变得不那么自然。 除了这个区域外,它是一个卷曲替代品。 我猜 golang 对所有这些东西都有操作系统检测。 因此,用 go 编写的现代 curl 替换(如 bat)将具有漂亮的输出、良好的 CLI 体验并处理自定义 CA 或 ssl 终止(负载平衡器)。

不行,不好。 即使临时开发人员证书也需要能够卷曲。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

loretoparisi picture loretoparisi  ·  6评论

chuma picture chuma  ·  3评论

hrj picture hrj  ·  5评论

eliangcs picture eliangcs  ·  5评论

rshurts picture rshurts  ·  5评论