Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Urllib and validation of server certificate

I use python 2.6 and request Facebook API (https). I guess my service could be target of Man In The Middle attacks. I discovered this morning reading again urllib module documentation that : Citation:

Warning : When opening HTTPS URLs, it is not attempted to validate the server certificate. Use at your own risk!

Do you have hints / url / examples to complete a full certificate validation ?

Thanks for your help

like image 949
kheraud Avatar asked Jul 11 '11 10:07

kheraud


People also ask

What is Urllib used for?

Urllib package is the URL handling module for python. It is used to fetch URLs (Uniform Resource Locators). It uses the urlopen function and is able to fetch URLs using a variety of different protocols.

How do I disable SSL certificate verification in Python?

To disable certificate verification, at the client side, one can use verify attribute.

What does Urllib Urlopen return?

The data returned by urlopen() or urlretrieve() is the raw data returned by the server. This may be binary data (such as an image), plain text or (for example) HTML. The HTTP protocol provides type information in the reply header, which can be inspected by looking at the Content-Type header.


1 Answers

You could create a urllib2 opener which can do the validation for you using a custom handler. The following code is an example that works with Python 2.7.3 . It assumes you have downloaded http://curl.haxx.se/ca/cacert.pem to the same folder where the script is saved.

#!/usr/bin/env python
import urllib2
import httplib
import ssl
import socket
import os

CERT_FILE = os.path.join(os.path.dirname(__file__), 'cacert.pem')


class ValidHTTPSConnection(httplib.HTTPConnection):
        "This class allows communication via SSL."

        default_port = httplib.HTTPS_PORT

        def __init__(self, *args, **kwargs):
            httplib.HTTPConnection.__init__(self, *args, **kwargs)

        def connect(self):
            "Connect to a host on a given (SSL) port."

            sock = socket.create_connection((self.host, self.port),
                                            self.timeout, self.source_address)
            if self._tunnel_host:
                self.sock = sock
                self._tunnel()
            self.sock = ssl.wrap_socket(sock,
                                        ca_certs=CERT_FILE,
                                        cert_reqs=ssl.CERT_REQUIRED)


class ValidHTTPSHandler(urllib2.HTTPSHandler):

    def https_open(self, req):
            return self.do_open(ValidHTTPSConnection, req)

opener = urllib2.build_opener(ValidHTTPSHandler)


def test_access(url):
    print "Acessing", url
    page = opener.open(url)
    print page.info()
    data = page.read()
    print "First 100 bytes:", data[0:100]
    print "Done accesing", url
    print ""

# This should work
test_access("https://www.google.com")

# Accessing a page with a self signed certificate should not work
# At the time of writing, the following page uses a self signed certificate
test_access("https://tidia.ita.br/")

Running this script you should see something a output like this:

Acessing https://www.google.com
Date: Mon, 14 Jan 2013 14:19:03 GMT
Expires: -1
...

First 100 bytes: <!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta itemprop
Done accesing https://www.google.com

Acessing https://tidia.ita.br/
Traceback (most recent call last):
  File "https_validation.py", line 54, in <module>
    test_access("https://tidia.ita.br/")
  File "https_validation.py", line 42, in test_access
    page = opener.open(url)
  ...
  File "/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1177, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed>
like image 64
Walter Cacau Avatar answered Oct 23 '22 09:10

Walter Cacau