Python wrap_socket()获取了意外的关键字参数';服务器主机名';?
我正在尝试使用Python测试web服务器。我几乎没有Python方面的经验,但我鼓励使用它,因为它很容易学习,而且使用起来也很简单(别人的意见,现在不是我的意见)。我使用的脚本是:Python wrap_socket()获取了意外的关键字参数';服务器主机名';?,python,ssl,sni,Python,Ssl,Sni,我正在尝试使用Python测试web服务器。我几乎没有Python方面的经验,但我鼓励使用它,因为它很容易学习,而且使用起来也很简单(别人的意见,现在不是我的意见)。我使用的脚本是: s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s2 = ssl.wrap_socket(s1, ca_certs="./pki/signing-dss-cert.pem",
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = ssl.wrap_socket(s1,
ca_certs="./pki/signing-dss-cert.pem",
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
server_hostname="localhost")
s2.connect( ("localhost", 8443) )
s2.send("GET / ")
time.sleep(1)
s2.send("HTTP/1.1")
错误是:
Traceback (most recent call last):
File "./fetch.sh", line 10, in <module>
server_hostname="localhost")
TypeError: wrap_socket() got an unexpected keyword argument 'server_hostname'
回溯(最近一次呼叫最后一次):
文件“/fetch.sh”,第10行,在
服务器\u hostname=“localhost”)
TypeError:wrap_socket()获得意外的关键字参数“server_hostname”
我也尝试过使用servername
、name
、hostname
和sni
,但毫无乐趣
Python文档没有提到SNI(和)。但我知道SNI和服务器主机名的补丁是4年前在2010年(,)合并的
我需要访问的等效OpenSSL调用是SSL\u set\u tlsext\u host\u name
如何指定SNI主机名?(最终,我需要将其设置为任意名称,因为我正在测试代理)。首先连接,然后包装套接字
import socket, ssl
sock = socket.create_connection( ('localhost', 443) )
sock = ssl.wrap_socket(sock, ca_certs="./pki/signing-dss-cert.pem", cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1)
在python2的情况下,我有时也会使用以下hack(因为httplib.HTTPSConnection
文档说明它不会对https服务器证书执行任何类型的检查):
请注意,如果您想与服务器通信,那么使用http客户端通常比使用原始套接字容易得多。这是针对Python 3.2的,您使用的是Python 2.7。似乎还表明没有计划支持Python 2.7的SNI端口支持
您可以用pyOpenSSL来包装套接字(它的连接类的版本为0.13(我不确定Debian 7.3附带了哪个版本,如果需要,您可能需要在本地设置virtualenv并升级到新版本)
pyOpenSSL存储库是一个重要的存储库
如果您想让wrap_socket
的使用与技巧更兼容,如果您在httplib
连接中替换sock
的值,您可以看看如何使用。本质上,它从现有套接字创建OpenSSL.SSL.connection
,但由于该连接与so不兼容在cket中,它将其包装到实现所需方法的类中
(顺便说一句,在Python2.7中,urllib
、urllib2
和httpconnection
根本不进行任何证书验证,除非您自己通过包装它们的套接字来实现。)
编辑:
这是一个应该使用Python 3.2的代码版本。不幸的是,server\u name
参数不在普通的ssl.wrap\u socket
中,仅在SSLContext.wrap\u socket
中,但您可以直接使用SSLSocket
import socket
import ssl
CA_BUNDLE_FILE="/etc/ssl/certs/ca-certificates.crt"
HOST = "sni.velox.ch"
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = ssl.SSLSocket(sock=s1, ca_certs=CA_BUNDLE_FILE,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
server_hostname=HOST)
s2.connect((HOST, 443))
s2.send(bytes("GET / HTTP/1.1\n", "UTF-8"))
# This might need to be modified when using another port
s2.send(bytes("Host: %s\n" % (HOST,), "UTF-8"))
s2.send(bytes("\n", "UTF-8"))
# Certainly not the best way to read the response, but it works.
while True:
x = s2.read()
if not x:
break
print(x)
我的环境是:requests==2.7.0,python-2.7.5-34.el7.x86_64,gevent==1.0.2
将python版本更改为python-2.7.5-18.el7_1.1.x86_64,问题就解决了
在CentOS:
sudo rpm -Uvh --oldpackage python-devel-2.7.5-18.el7_1.1.x86_64.rpm python-libs-2.7.5-18.el7_1.1.x86_64.rpm python-2.7.5-18.el7_1.1.x86_64.rpm
pakages可以在google上搜索。@noloader我担心这个简单的ssl实现不会公开这样的选项。谢谢pasztorpisti。代码已经更改,但错误仍然存在。@noloader我在你的帖子中没有看到我的代码,所以我对它不起作用并不感到惊讶。谢谢pasztorpisti。请原谅我的无知……这里出现了代码above没有设置服务器名,这正是我试图实现的。在您的示例中,假设您希望连接到google.com
,但将TLS服务器名扩展名设置为example.com
,以进行测试。顺便说一句,我正在使用Python wiki中的代码。尝试将我的代码与您的代码合并,并尝试使用服务器创建连接时使用名称而不是“localhost”
。您使用的是哪一版本的Python?sys.version\u info(major=2,minor=7,micro=3,releaselevel='final',serial=0)
。Debian 7.3(x64),已完全修补。感谢Bruno。“如果您希望使用wrap\u套接字更兼容…”-我只是想让它工作。我今天在上面浪费了大约4个小时,因为它应该更简单更快。我想我要回到C/C++。C/C++开发对我来说比试图解开你上面所说的一切都要快。我很困惑,最新的Debian使用的是一个旧的、未修补的库。我使用最新的发行版是有原因的,我这并不是因为我喜欢最前沿的bug。我不会以此来评判Python。如果你是Python新手,没有任何2.x遗留代码,你可以试试Python 3.2+解释器。如果你已经安装了包,那么应该可以使用python3.2
调用它。再次感谢Bruno。这在我下载、构建和安装Python之后就起作用了3.4.奇怪的是,你必须获得python3.4并自己构建它。我通过安装python3
包(并使用python3.2
)在Debian系统上实现了这一点(以防你不知道,在Debian/Ubuntu上,Python版本可以一起安装(除了微级别的数字)默认情况下,python
仍然是最新的2.x解释器,但您可以显式调用python3.x
解释器。)
sudo rpm -Uvh --oldpackage python-devel-2.7.5-18.el7_1.1.x86_64.rpm python-libs-2.7.5-18.el7_1.1.x86_64.rpm python-2.7.5-18.el7_1.1.x86_64.rpm