使用urllib发布数据而不进行SSL证书验证

时间:2017-11-10 05:36:39

标签: python python-3.x ssl urllib urlopen

我需要将数据发布到REST接口,但是接收主机使用的是自签名证书(这不会改变)所以我需要忽略我收到的明显的证书验证错误。

我的初始脚本看起来像这样:

from urllib.request import Request, urlopen
from urllib.parse import urlencode

post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}

omi_post = Request(url=post_url, data=post_payload, headers=post_headers)

urlopen(omi_post)

如上所述,这会生成以下堆栈跟踪:

  

Traceback(最近一次调用最后一次):文件   " C:\ Users \用户名为myUsername \应用程序数据\本地\程序\的Python \ Python36 \ lib中\的urllib \ request.py&#34 ;,   第1318行,在do_open中       encode_chunked = req.has_header(' Transfer-encoding'))文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ http \ client.py" ,   第1239行,请求       self._send_request(method,url,body,headers,encode_chunked)文件   " C:\ Users \用户名为myUsername \应用程序数据\本地\程序\的Python \ Python36 \ lib中\ HTTP \ client.py&#34 ;,   第1285行,在_send_request中       self.endheaders(body,encode_chunked = encode_chunked)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ _ http \ client.py",   第1234行,在终结者中       self._send_output(message_body,encode_chunked = encode_chunked)文件   " C:\ Users \用户名为myUsername \应用程序数据\本地\程序\的Python \ Python36 \ lib中\ HTTP \ client.py&#34 ;,   第1026行,在_send_output中       self.send(msg)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ http \ client.py",   第964行,发送       self.connect()文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ http \ client.py",   第1400行,在连接中       server_hostname = server_hostname)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ ssl.py",   第407行,在wrap_socket中       _context = self,_session = session)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ ssl.py",   第814行,在 init 中       self.do_handshake()文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ ssl.py",   第1068行,在do_handshake中       self._sslobj.do_handshake()文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ ssl.py",   第689行,在do_handshake中       self._sslobj.do_handshake()ssl.SSLError:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败(_ssl.c:777)

     

在处理上述异常期间,发生了另一个异常:

     

回溯(最近一次呼叫最后一次):文件" send_data.py",第16行,          urlopen(post_it_already)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第223行,在urlopen中       return opener.open(url,data,timeout)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第526行,公开       response = self._open(req,data)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第544行,在_open       ' _open',req)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第504行,在_call_chain中       result = func(* args)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第1361行,在https_open中       context = self._context,check_hostname = self._check_hostname)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第1320行,在do_open中       提出URLError(错误)urllib.error.URLError:

所以我发现了另一篇关于添加SSL上下文的帖子,我做了如下:

from urllib.request import Request, urlopen
from urllib.parse import urlencode
import ssl

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}

post_it_already = Request(url=post_url, data=post_payload, headers=post_headers)

urlopen(post_it_already, context=ctx)

然而,这会产生以下的堆栈跟踪(无论我多少握拳):

  

回溯(最近一次呼叫最后一次):文件" send_data.py",第15行,          urlopen(post_it_already,context = ctx)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第223行,在urlopen中       return opener.open(url,data,timeout)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第526行,公开       response = self._open(req,data)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第544行,在_open       ' _open',req)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第504行,在_call_chain中       result = func(* args)File" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第1361行,在https_open中       context = self._context,check_hostname = self._check_hostname)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ urllib \ request.py",   第1318行,在do_open中       encode_chunked = req.has_header(' Transfer-encoding'))文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ http \ client.py" ,   第1239行,请求       self._send_request(method,url,body,headers,encode_chunked)文件   " C:\ Users \用户名为myUsername \应用程序数据\本地\程序\的Python \ Python36 \ lib中\ HTTP \ client.py&#34 ;,   第1285行,在_send_request中       self.endheaders(body,encode_chunked = encode_chunked)文件" C:\ Users \ myusername \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ _ http \ client.py",   第1234行,在终结者中       self._send_output(message_body,encode_chunked = encode_chunked)文件   " C:\ Users \用户名为myUsername \应用程序数据\本地\程序\的Python \ Python36 \ lib中\ HTTP \ client.py&#34 ;,   第1064行,在_send_output中       + b' \ r \ n' TypeError:不能将str连接到字节

我不知道为什么它抱怨将字符串与字节对象连接起来。我认为它不像我的字符串类型URL和我的数据类型有效负载和标题?但是,我不确定下一步该做什么。

或者,这是一个经典案例,有人采用2个单独的样本代码,并希望它们在花生和泡泡糖的情况下一起工作?

2 个答案:

答案 0 :(得分:0)

您的post_payload应该是'字节'而不是' str'。

来自Python docs

  

class urllib.request.Request ...

     

...

     

对于HTTP POST请求方法,数据应该是标准application / x-www-form-urlencoded格式的缓冲区。 urllib.parse.urlencode()函数采用2元组的映射或序列,并以此格式返回ASCII字符串。它应该在用作数据参数之前编码为字节。

     

...

您可以使用post_payload方法将.encode()转换为字节,详见this Python urllib howto

这与SSL验证问题是分开的,但可能是因为它试图POST数据,因此成功建立了HTTPS连接。

答案 1 :(得分:0)

您可以将@ contextlib.contextmanager装饰器与请求模块一起使用。这是一种更简单的方法。

以下代码可以正常使用

@contextlib.contextmanager
def no_ssl_verification():
    old_request = requests.Session.request
    requests.Session.request = partialmethod(old_request,verify=False)

    warnings.filterwarnings('ignore', 'Unverified HTTPS request')
    yield

    warnings.resetwarnings()
    requests.Session.request = old_request

以上代码的作用是为request.session.request生成一个部分方法,其中包含“verify=False”,并过滤所有显示“Unverified Https request”的警告。

with no_ssl_verification:
   request = requests.post( 
                           url,
                           json={
                                    'name' : some_name
                                },auth(username,password)
                           )

希望它有所帮助,如果您找到更好的解决方案,请告诉我。