我尝试使用Python来测试Web服务器。我几乎没有使用Python的经验,但我鼓励使用它,因为它易学易用(别人的意见,而不是我的意见)。我使用的脚本是:
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'
我也尝试过使用servername
,name
,hostname
和sni
而不感到高兴。
Python文档不提及SNI(TLS/SSL wrapper for socket objects和SSL wiki page)。但是我知道SNI和server_hostname
的补丁是在4年前的2010年(Add a *server_hostname* argument to SSLContext.wrap_socket
,changeset 65593:846c0e1342d0)合并而来的。
我需要访问的等效OpenSSL调用是SSL_set_tlsext_host_name
。
如何指定SNI主机名? (最后,我需要将其设置为任意名称,因为我正在测试代理)。
答案 0 :(得分:2)
patch you're mentioning适用于Python 3.2,您使用的是Python 2.7。 Issue 5639似乎也表明没有计划为Python 2.7支持SNI支持。
您可以使用pyOpenSSL包装套接字(其Connection
类自版本0.13开始有set_tlsext_host_name
。(我不确定Debian 7.3附带哪个版本,您可能需要设置一个virtualenv并在必要时在本地升级到更新版本。)
SNI example是pyOpenSSL存储库。
如果您希望wrap_socket
的使用与该技巧更加兼容,那么您可以在sock
连接中替换httplib
的值,那么您可以查看一下{{ 3}}。本质上,它从现有套接字创建OpenSSL.SSL.Connection
,但由于该连接与套接字不兼容,因此它将其包装到实现所需方法的类中。
(顺便说一下,在Python 2.7中,urllib
,urllib2
和httpconnection
根本不进行任何证书验证,除非您自己通过包装套接字来实现它。)
编辑:
以下是适用于Python 3.2的代码版本。很遗憾,server_name
参数不在普通ssl.wrap_socket
中,仅在SSLContext.wrap_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)
答案 1 :(得分:1)
首先连接,然后包装套接字。
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服务器证书执行任何类型的检查):
import urllib, httplib, ssl
PATH = urllib.quote(u'/'.encode('utf-8'))
conn = httplib.HTTPConnection('www.google.com', 443)
conn.connect()
try:
conn.sock = ssl.wrap_socket(conn.sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=CA_BUNDLE_FILE, ssl_version=VERSION)
conn.request('GET', PATH)
resp = conn.getresponse()
print resp.status
print resp.read()
finally:
conn.close()
请注意,如果您想与服务器通信,那么使用http客户端通常比使用原始套接字要容易得多。
答案 2 :(得分:0)
我的环境是: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上:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cout << "CONVERSION\n\n";
cout << "Base 11 to Decimal\n";
cout << "Base 11: ";
getline(std::cin, str);
const auto bad_loc = str.find_first_not_of("0123456789aA");
if (bad_loc != std::string::npos)
{
throw "bad input"; // or whatever handling
}
unsigned long ul = std::stoul(str, nullptr, 11);
cout << "Decimal: " << ul << '\n';
return 0;
}
pakages可以在谷歌搜索。