Using Python SSL

Version 2.7 of the Python SSL library has been deprecated. Instead, use the latest version, currently 2.7.11.

App Engine supports the native Python SSL library for the Python 2.7 runtime via the SSL library, which you must add to your app.

Specifying the SSL library

If you want to use native Python SSL, you must enable it by specifying ssl for the libraries configuration in your application's app.yaml. You should use the latest library version, which is currently version 2.7.11. This version supports TLS versions 1.0, 1.1, and 1.2 and corresponds to the SSL versions from Python 2.7.11 and onwards:

libraries:
- name: ssl
  version: latest

Providing authority certificates

In order to perform an SSL handshake, you must have file that contains concatenated certificate authority certificates. You can upload your own file with your application, or you can use the file provided by App Engine: /etc/ca-certificates.crt.

Performing an SSL handshake

The Python 2.7 wrap_socket method takes two file name parameters that contain the client's key and certificate. In the App Engine environment, this is limiting since the application is not able to write files to dynamically provide different keys and certificates. To get around this limitation, the certfile and keyfile parameters for the ssl.wrap_socket method can be "file-like" objects that allow the application to store certificates and keys in other ways than in just uploaded application files. (A "file-like" object is one that has a "read" method returning the entire certificate as a string.)

  # Example of a dynamic key and cert.
  datastore_record_k = ndb.Key('Employee', 'asalieri', 'Address', 1)
  datastore_record = datastore_record_k.get()
  key_str = datastore_record.key_str
  cert_str = datastore_record.cert
  ssl_server = ssl.wrap_socket(server_sock,
                              server_side=False,
                              keyfile=StringIO.StringIO(key_str),
                              certfile=StringIO.StringIO(cert_str),
                              cert_reqs=ssl.CERT_REQUIRED,
                              ssl_version=ssl.PROTOCOL_SSLv23,
                              ca_certs=CERTIFICATE_FILE)

You don't need to specify the ssl_version parameter. If you omit it, the 2.7.11 library defaults to PROTOCOL_SSLv23. You can also specify PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, or PROTOCOL_TLSv1_2.

The App Engine implementation of the wrap_socket method includes the required parameter ca_certs, which is used to specify the special file containing concatenated certificate authority certificates.

Validating certificates

Your app should validate certificates to prevent certain security vulnerabilities such as "man in the middle" attacks.

To do this:

  1. Edit your app.yaml file, adding the environment variable PYTHONHTTPSVERIFY set to 1:

     env_variables:
       PYTHONHTTPSVERIFY: 1
    
  2. Redeploy your app.

Alternatively to specifying cert validation in your app.yaml, you could explicitly call the SSL library to do the validation, after you've performed a successful SSL handshake, as follows:

    ssl.match_hostname(ssl_server.getpeercert(), 'a.hostname.com')

The above code uses the match_hostname feature, backported from Python 3.2 to be part of the App Engine Python 2.7.11 SSL module. This call makes sure the certificate supplied by the peer matches one of the designated hosts in the peer's certificate.

Working on dev_appserver

You can issue HTTPS requests using the urlfetch API, Dev_server's certificate validation behaviour using httplib using urlfetch is identical to the production App Engine environment. Dev_appserver does not support requests using sockets.