Welcome, guest | Sign In | My Account | Store | Cart
7

This recipe describes how to set up a simple HTTP server supporting SSL secure communications. It extends the SimpleHTTPServer standard module to support the SSL protocol. With this recipe, only the server is authenticated while the client remains unauthenticated (i.e. the server will not request a client certificate). Thus, the client (typically the browser) will be able to verify the server identity and secure its communications with the server.

This recipe requires you already know the basis of SSL and how to set up OpenSSL. This recipe is mostly derived from the examples provided with the pyOpenSSL package.

In order to apply this recipe, follow these few steps:
  1. Install the OpenSSL package in order to generate key and certificate. Note: you probably already have this package installed if you are under Linux, or *BSD.
  2. Install the pyOpenSSL package, it is an OpenSSL library binding. You'll need to import this module for accessing OpenSSL's components.
  3. Generate a self-signed certificate compounded of a certificate and a private key for your server with the following command (it outputs them both in a single file named server.pem): openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
  4. Assuming you saved this recipe in SimpleSecureHTTPServer.py, start the server (with the appropriate rights): python SimpleSecureHTTPServer.py
  5. Finally, browse to https://localhost, or https://localhost:port if your server listens a different port than 443.
Python, 48 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
'''
SimpleSecureHTTPServer.py - simple HTTP server supporting SSL.

- replace fpem with the location of your .pem server file.
- the default port is 443.

usage: python SimpleSecureHTTPServer.py
'''
import socket, os
from SocketServer import BaseServer
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from OpenSSL import SSL


class SecureHTTPServer(HTTPServer):
    def __init__(self, server_address, HandlerClass):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = SSL.Context(SSL.SSLv23_METHOD)
        #server.pem's location (containing the server private key and
        #the server certificate).
        fpem = '/path/server.pem'
        ctx.use_privatekey_file (fpem)
        ctx.use_certificate_file(fpem)
        self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
                                                        self.socket_type))
        self.server_bind()
        self.server_activate()


class SecureHTTPRequestHandler(SimpleHTTPRequestHandler):
    def setup(self):
        self.connection = self.request
        self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
        self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)


def test(HandlerClass = SecureHTTPRequestHandler,
         ServerClass = SecureHTTPServer):
    server_address = ('', 443) # (address, port)
    httpd = ServerClass(server_address, HandlerClass)
    sa = httpd.socket.getsockname()
    print "Serving HTTPS on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()


if __name__ == '__main__':
    test()

8 comments

Pierre Quentel 7 years, 6 months ago  # | flag

Excellent ! I've always thought setting up a SSL server was only for the experts in cryptography, so finding this short recipe, very well explained, is a very nice surprise. I've followed your explanations and everything worked, except I had to google around to find a Windows binary for OpenSSL for Python 2.4. I found it here : http://webcleaner.sourceforge.net/pyOpenSSL-0.6.win32-py2.4.exe.

Merci beaucoup !

Erik Lat 2 years, 1 month ago  # | flag

Great work man, I've been itching for something like this for ages now. I was just wondering if you had seen this error from your application:

File "/home/erik.lat/Downloads/recipe-442473-1.py", line 44, in test httpd.serve_forever() File "/usr/lib64/python2.7/SocketServer.py", line 227, in serve_forever self._handle_request_noblock() File "/usr/lib64/python2.7/SocketServer.py", line 287, in _handle_request_noblock self.shutdown_request(request) File "/usr/lib64/python2.7/SocketServer.py", line 459, in shutdown_request request.shutdown(socket.SHUT_WR) TypeError: shutdown() takes exactly 0 arguments (1 given)

I'm running this on Fedora 14 with Python 2.7-8.1 on x86_64.

Erik Lat 2 years, 1 month ago  # | flag
Erik Lat 2 years, 1 month ago  # | flag

This bug is irrelevant.

Erik Lat 2 years, 1 month ago  # | flag

To fix the shutdown errors, add the following at line 29:

def shutdown_request(self,request): request.shutdown()

Sam Gleske 10 months, 4 weeks ago  # | flag

@Erik Lat: If a work around to this bug is absolutely then you can modify %PYTHON_PATH%/lib/socket.py:303 and add the following code.

try:
    self._sock.sendall(view.tobytes())
finally:
    del view, data
# try:
    # while write_offset < data_size:
        # self._sock.sendall(view[write_offset:write_offset+buffer_size])
        # write_offset += buffer_size
# finally:
    # if write_offset < data_size:
        # remainder = data[write_offset:]
        # del view, data  # explicit free
        # self._wbuf.append(remainder)
        # self._wbuf_len = len(remainder)
Sam Gleske 10 months, 4 weeks ago  # | flag

@Erik Lat: Even better. I wrote a workaround and posted a comment on the bug.

https://bugs.launchpad.net/pyopenssl/+bug/755852

VIctor 9 months, 1 week ago  # | flag

How would you add threading to the Server?

Add a comment

Sign in to comment