【问题标题】:Python STDOUT to file with openssl subprocessPython STDOUT 到带有 openssl 子进程的文件
【发布时间】:2011-10-06 08:05:35
【问题描述】:

我正在尝试编写一个 python 脚本来自动执行通过 openSSL 检查 SSL 重新协商的过程并将结果输出到文件中。我遇到了 2 个问题。

我的第一个问题是初始握手的输出被写入文件,但实际的重新协商部分没有。而是显示在控制台上。

subprocess.call("echo \"R\" | openssl s_client -connect example.com:443", 
        shell=True, stdout=FILE)

我的另一个问题(尽管这可能是错误的地方)是我无法让 openSSL 命令用于发送 GET 命令。

subprocess.call("echo -e \"GET / HTTP/1.1\r\n\r\n\" | openssl s_client -connect
        example.com:443", shell=True)   

同样,初始连接已建立,但 openSSL 存在,它不处理 GET 请求。

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 有什么理由不使用 python ssl 包装器?也许您可以使用它获得更好的调试信息。只是一个想法。

标签: python ssl openssl subprocess stdout


【解决方案1】:

没有理由将shell=True 用于输入。相反,请使用stdin=subprocess.PIPE。另外,请注意您的请求无效,因为 HTTP 1.1 需要 Host 标头。此外,我想不出使用命令行 openssl 代替 ssl module 的理由。

话虽如此,下面是一个工作示例:

import subprocess

f = open('http_answer', 'w')
_,log = subprocess.Popen(
    ['openssl', 's_client', '-quiet', '-connect', 'twitter.com:443'],
    stdout=f, stderr=subprocess.PIPE, stdin=subprocess.PIPE
).communicate('GET / HTTP/1.0\r\n\r\n')
print('Output of SSL:\n' + log)

【讨论】:

  • SSL 模块没有给你足够的控制来在发送请求的过程中强制重新协商,或者至少我上次调查它时找不到方法。
  • 我确实尝试过使用 http 1.0 和 1.1,它似乎给了我和以前一样的结果。获取请求仍未得到处理。编辑:我没有使用 ssl 模块,因为我们在这里使用 openSSL 进行很多不同的测试,我想保持一致。
  • @Drew 如果您执行答案中发布的确切代码,您会得到一个文件http_answer吗?
  • 是的,它会输出 s_client 命令的结果,但它实际上并不处理 GET 请求。它只是在握手时停止。
  • @Drew 你怎么知道它不处理 GET 请求?但是,如果上面的代码不起作用,则说明您的 openssl 安装或证书存储有问题。在未受影响的虚拟机或 chroot 中尝试。
【解决方案2】:

请记住,openssl s_client 对于某些输出也使用 stderr。您需要检查重新协商是否会转到 stderr,我相信确实如此,尽管我的记忆可能正在消退。

我以不同的方式实现了这一点,尽管不是在 python 中。我创建了一个进程并将标准输入、标准输出、标准错误文件描述符连接到我可以读/写的文件描述符上,我实际上驱动输入并读取输出。这需要更多的工作,但您可以完全控制正在发生的事情并与流程进行交互。我已经在 php 中完成了这项工作,并且可以通过 http://netsekure.org/2009/11/tls-renegotiation-test/ 在线获得测试。

或者,您可以尝试使用 python 来编写 openssl 本身,而不是使用 s_client,但这是更多的工作,我使用了以前的方法。

您可以检查两件事情,但您没有明确说明您对哪一件感兴趣:

  • 检查远程服务器是否支持客户端发起的重新协商
  • 检查远程服务器是否支持安全重新协商扩展

这两种情况都可以通过对适用于这两种情况的关键字执行 s_client 和 grep 来简单地推断出来。这完全取决于您需要多少控制/复杂性。

【讨论】:

  • 我正在尝试测试服务器是否允许客户端启动重新协商。你对stderr是对的。谢谢!
【解决方案3】:

@phihag 我对你的脚本做了些微改动,对我来说效果很好。

import subprocess

f = open('http_answer', 'w')
_,log = subprocess.Popen(
    ['openssl', 's_client', '-quiet', '-connect', 'twitter.com:443','-sess_out', 'session.txt'],
    stdout=f, stderr=subprocess.PIPE, stdin=subprocess.PIPE ).communicate('GET / HTTP/1.0\r\nHOST: twitter.com\r\n\r\n') print('Output of SSL:\n' + log)

列出更改 1. 添加了 'sess_out' 'session.txt' 参数,保留所有 SSL 会话参数,可以使用以下 openssl 命令查看

$openssl sess_id -in test.txt -text -cert -noout
  1. 在 GET 命令中添加了主机信息,因为较新的部分仅使用 HOST 选项响应良好。

    'GET / HTTP/1.0\r\nHOST: twitter.com\r\n\r\n'

@Drew,为时已晚,但我希望这有点帮助。谢谢。

【讨论】:

    猜你喜欢
    • 2021-06-02
    • 1970-01-01
    • 2018-01-11
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2011-07-07
    相关资源
    最近更新 更多