python ignore certificate validation urllib2 - python

I want to ignore the certification validation during my request to the server with an internal corporate link.
With python requests library I would do this:
r = requests.get(link, allow_redirects=False,verify=False)
How do I do the same with urllib2 library?

In the meantime urllib2 seems to verify server certificates by default.
The warning, that was shown in the past disappeared for 2.7.9 and I currently ran into this problem in a test environment with a self signed certificate (and Python 2.7.9).
My evil workaround (don't do this in production!):
import urllib2
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
urllib2.urlopen("https://your-test-server.local", context=ctx)
According to docs calling SSLContext constructor directly should work, too. I haven't tried that.

The easiest way:
python 2
import urllib2, ssl
request = urllib2.Request('https://somedomain.co/')
response = urllib2.urlopen(request, context=ssl._create_unverified_context())
python 3
from urllib.request import urlopen
import ssl
response = urlopen('https://somedomain.co', context=ssl._create_unverified_context())

For those who uses an opener, you can achieve the same thing based on Enno Gröper's great answer:
import urllib2, ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ctx), your_first_handler, your_second_handler[...])
opener.addheaders = [('Referer', 'http://example.org/blah.html')]
content = opener.open("https://localhost/").read()
And then use it as before.
According to build_opener and HTTPSHandler, a HTTPSHandler is added if ssl module exists, here we just specify our own instead of the default one.

According to #Enno Gröper 's post, I've tried the SSLContext constructor and it works well on my machine. code as below:
import ssl
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
urllib2.urlopen("https://your-test-server.local", context=ctx)
if you need opener, just added this context like:
opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ctx))
NOTE: all above test environment is python 2.7.12. I use PROTOCOL_SSLv23 here since the doc says so, other protocol might also works but depends on your machine and remote server, please check the doc for detail.

A more explicit example, built on Damien's code (calls a test resource at http://httpbin.org/). For python3. Note that if the server redirects to another URL, uri in add_password has to contain the new root URL (it's possible to pass a list of URLs, also).
import ssl
import urllib.parse
import urllib.request
def get_resource(uri, user, passwd=False):
"""
Get the content of the SSL page.
"""
uri = 'https://httpbin.org/basic-auth/user/passwd'
user = 'user'
passwd = 'passwd'
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, uri, user, passwd)
auth_handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(auth_handler, urllib.request.HTTPSHandler(context=context))
urllib.request.install_opener(opener)
return urllib.request.urlopen(uri).read()

urllib2 does not verify server certificate by default. Check this documentation.
Edit: As pointed out in below comment, this is not true anymore for newer versions (seems like >= 2.7.9) of Python. Refer the below ANSWER

Related

How do I disable verification of the SSL Certificate while using PySocks and Socks5 Proxy?

This seems to get me close:
SOCKS5 proxy using urllib2 and PySocks
But it seems that if I try to add the context to disable the SSL verification it just ignores it.
I am not the greatest at python, but it looks like the inheritance of the class in PySocks takes the same things as HTTPShandler.
https://github.com/Anorov/PySocks/blob/master/sockshandler.py
If so I thought I could just pass the context=context in without and issue.
But it doesn't work.
Here is my method...
def make_http_call(url, socks_hostname=None, socks_port=None, socks_username=None, socks_password=None, params=None):
"""
Make a HTTP GET request to given url.
"""
import ssl
url = add_url_params(url, params)
opener = urllib2.build_opener()
context = ssl._create_unverified_context
if socks_hostname and socks_port and socks_username and socks_password:
# Use proxy instead if params are provided
print "Socks Proxy is being used..."
opener = urllib2.build_opener(
SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, socks_hostname, socks_port, True, socks_username, socks_password, context=context))
else:
print "Socks Proxy not in use..."
request = urllib2.Request(url)
response = opener.open(request).read()
return response
Is this possible?
For the context variable i would do this(untested code):
context = ssl.create_default_context()
context.verify_mode = CERT_NONE
context.check_hostname = False
The last line is not necessary as we are not checking the certificate, but it is just in case. Now i do not recommend this as this will not ensure that you are communicating with who you think you are and i do not recommend using any python version below 3 because they are known to have big security issues, See Here.

How do I disable the ssl check in python 3.x?

I'm using urllib.request.urlretrieve to download a file to local.
urllib.request.urlretrieve(url_string,file_name)
It throws error:
ssl.CertificateError was unhandled by user code
Message: hostname 'foo.net' doesn't match either of 'a248.e.akamai.net', '.akamaihd.net', '.akamaihd-staging.net', '.akamaized.net', '.akamaized-staging.net'
If you copy the url into Chrome, it will show you a notification and you need to say something like "keep going to the url".
Use urllib.request.urlopen with custom ssl context:
import ssl
import urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with urllib.request.urlopen(url_string, context=ctx) as u, \
open(file_name, 'wb') as f:
f.write(u.read())
Alternatively, if you use requests library, it could be simpler:
import requests
with open(file_name, 'wb') as f:
resp = requests.get(url_string, verify=False)
f.write(resp.content)
Function urllib.request.urlretrieve doesn't accept any SSL options but urllib.request.urlopen does.
However instead creating a secure SSL context with ssl.create_default_context() and making it insecure you can create an insecure context with ssl.SSLContext():
This:
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
is equivalent to:
ctx = ssl.SSLContext()
(For Python < 3.5.3 use ssl.SSLContext(ssl.PROTOCOL_TLSv1))
Which makes a nice one-liner:
import ssl
import urllib.request
with urllib.request.urlopen("https://wrong.host.badssl.com/", context=ssl.SSLContext()) as url:
print(url.read())

403 when retrieving a WSDL via Python SUDS

I can't seem to get SUDS to download a WSDL that requires Basic auth credentials. My code is simple:
wsdl_url = 'https://example.com/ChangeRequest.do?WSDL'
self.client = Client(wsdl_url, username=username, password=password)
I've also tried:
from suds.transport.https import HttpAuthenticated
wsdl_url = 'https://example.com/ChangeRequest.do?WSDL'
credentials = dict(username=username, password=password)
t = HttpAuthenticated(**credentials)
self.client = Client(url=wsdl_url, transport=t)
In both cases, the service returns a 403 Forbidden error. I can go down into the SUDS code in http.py and add this line to the call:
u2request.add_header('Authorization','Basic xxxxxxxxxxxxxxxxxxxx')
This works. What am I doing wrong to get SUDS to pass my credentials when downloading the WSDL?
Note: I try to connect to the WSDL directly using both Chrome's Postman plugin and SoapUI, and the service works as well. So I know the credentials are correct.
I encountered a similar issue (suds v0.4, wsdl, 403), and found out that it was because the server I'm trying to access blocks any requests with the header User-Agent set like Python-urllib* (suds is using urllib2, hence the default header). Explicitly change the header solves the issue.
Particular to my solution: I overrode the open method of a transport class, and set client options, like the following code snippet. Note that we need to explicitly set for open and subsequent requests separately. Please advice better ways to circumvent this if you know any. And hope this post could help save someone's time in the future.
import urllib2
import suds
from suds.transport.https import HttpAuthenticated
from suds.transport import TransportError
URL = 'https://example.com/ChangeRequest.do?WSDL'
class HttpHeaderModify(HttpAuthenticated):
def open(self, request):
try:
url = request.url
u2request = urllib2.Request(url, headers={'User-Agent': 'Mozilla'})
self.proxy = self.options.proxy
return self.u2open(u2request)
except urllib2.HTTPError, e:
raise TransportError(str(e), e.code, e.fp)
transport = HttpHeaderModify()
client = Client(URL, transport=transport, timeout=10)
# Subsequent requests' header needs to be set again here. The overridden transport
# class only handles opening of the client.
client.set_options(headers={'User-Agent': 'Mozilla'})
P.S. Though my problem may not be the same, searching for "403 suds" pops up this SO question, so I decide just post my solution here.
reference post that gave me the right direction: https://bitbucket.org/jurko/suds/issues/27/client-request-for-wsdl-does-not-use-given
I used to have this issue before and compare with the soap UI header.
Found that suds missing to include the header (Host).
client.set_options(headers={'Host': 'value'})
And issue fixed.

How to create a HTTP proxy handler with Python 3 HTTP lib

I'm trying define a proxy handler to use http.client behind a proxy company. I know just how to use or define a proxy handler to urllib.:
http_proxy_full_auth_string = "http://"+"%s:%s#%s:%s" % (http_proxy_user,
http_proxy_passwd,
http_proxy_server,
http_proxy_port)
proxy_handler = urllib.request.ProxyHandler({"http": http_proxy_full_auth_string})
opener = urllib.request.build_opener(proxy_handler)
urllib.request.install_opener(opener)
resp = urllib.request.urlopen(uri).read()
And using http.client...?
P.S: sorry for the low english skills...
This might be old thread but folks may stumble upon it like I did and dont know how to authenticate.
import http.client
import base64
auth_hash = base64.b64encode(b"username:password").decode("utf-8")
conn = http.client.HTTPSConnection("proxy-ip or hostname", port="proxy-port")
conn.set_tunnel(
"example.com",
headers={"Proxy-Authorization": f"Basic {auth_hash}"})
conn.request("GET", "/")
This is how you do it with basic authentication.
See the httplib python 3 documentation
import http.client
conn = http.client.HTTPSConnection("proxy_domain", 8080)
conn.set_tunnel("www.python.org")
conn.request("HEAD","/index.html")

Using client certificates with urllib2

I need to create a secure channel between my server and a remote web service. I'll be using HTTPS with a client certificate. I'll also need to validate the certificate presented by the remote service.
How can I use my own client certificate with urllib2?
What will I need to do in my code to ensure that the remote certificate is correct?
Because alex's answer is a link, and the code on that page is poorly formatted, I'm just going to put this here for posterity:
import urllib2, httplib
class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
def __init__(self, key, cert):
urllib2.HTTPSHandler.__init__(self)
self.key = key
self.cert = cert
def https_open(self, req):
# Rather than pass in a reference to a connection class, we pass in
# a reference to a function which, for all intents and purposes,
# will behave as a constructor
return self.do_open(self.getConnection, req)
def getConnection(self, host, timeout=300):
return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert)
opener = urllib2.build_opener(HTTPSClientAuthHandler('/path/to/file.pem', '/path/to/file.pem.') )
response = opener.open("https://example.org")
print response.read()
Here's a bug in the official Python bugtracker that looks relevant, and has a proposed patch.
Per Antoine Pitrou's response to the issue linked in Hank Gay's answer, this can be simplified somewhat (as of 2011) by using the included ssl library:
import ssl
import urllib.request
context = ssl.create_default_context()
context.load_cert_chain('/path/to/file.pem', '/path/to/file.key')
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=context))
response = opener.open('https://example.org')
print(response.read())
(Python 3 code, but the ssl library is also available in Python 2).
The load_cert_chain function also accepts an optional password parameter, allowing the private key to be encrypted.
check http://www.osmonov.com/2009/04/client-certificates-with-urllib2.html

Categories