Usar SSL de Python

La versión 2.7 2.7 de la biblioteca SSL de Python es obsoleta. En cambio, usa la versión más reciente, que actualmente es la 2.7.11.

App Engine es compatible con la biblioteca de SSL nativo de Python para el entorno de ejecución Python 2.7 a través de la biblioteca de SSL, la cual debes agregar a la aplicación.

Especificar las bibliotecas de SSL

Si deseas usar el SSL nativo de Python, debes habilitarlo especificando ssl para la configuración libraries en el app.yaml de tu aplicación. Debes usar la versión más reciente de la biblioteca, que en este momento es la 2.7.11. Esta es compatible con las versiones 1.0, 1.1 y 1.2 de TLS, y corresponde a las versiones de SSL de Python 2.7.11 y superiores:

libraries:
- name: ssl
  version: latest

Proporcionar certificados de autorización

Para realizar un protocolo de enlace SSL, debes tener un archivo que contenga certificados concatenados de autoridad certificada. Puedes subir tu propio archivo con la aplicación o puedes usar el archivo que proporciona App Engine: /etc/ca-certificates.crt.

Realizar un protocolo de enlace SSL

El método wrap_socket de Python 2.7 toma dos parámetros de nombres de archivo que contienen la clave y el certificado del cliente. En el entorno de App Engine, este método es limitado, ya que la aplicación no está habilitada para escribir archivos a fin de proporcionar de manera dinámica diferentes claves y certificados. A fin de evitar esta limitación, los parámetros certfile y keyfile para el método ssl.wrap_socket pueden ser objetos “similares a archivos” que permitan a la aplicación almacenar certificados y claves de otras formas que cuando solo se suben archivos de aplicación. (Un objeto “similar a un archivo” es un objeto que tiene un método de “lectura” que muestra todo el certificado como una 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)

No necesitas especificar el parámetro ssl_version. Si lo omites, la biblioteca 2.7.11 cambia de manera predeterminada a PROTOCOL_SSLv23. También puedes especificar PROTOCOL_TLSv1, PROTOCOL_TLSv1_1 o PROTOCOL_TLSv1_2.

La implementación de App Engine del método wrap_socket incluye el parámetro obligatorio ca_certs, que se usa para especificar el archivo especial que contiene los certificados concatenados de autoridad certificada.

Validar los certificados

La aplicación debe validar los certificados para evitar ciertas vulnerabilidades de seguridad, como ataques intermediarios.

Para ello, sigue estos pasos:

  1. Edita el archivo app.yaml y agrega la variable de entorno PYTHONHTTPSVERIFY configurada como 1:

     env_variables:
       PYTHONHTTPSVERIFY: 1
    
  2. Vuelve a implementar la app.

Como alternativa a la especificación de la validación del certificado en app.yaml, puedes llamar explícitamente a la biblioteca SSL para realizar la validación, después de realizar un protocolo de enlace SSL exitoso, de la siguiente manera:

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

El código anterior usa la característica match_hostname, compatible con Python 3.2 como parte del módulo SSL de Python 2.7.11 de App Engine. Esta llamada se asegura de que el certificado provisto por el par coincida con uno de los hosts en el certificado del par.

Trabajar en dev_appserver

Puedes emitir solicitudes HTTPS con la API de urlfetch. El comportamiento de validación del certificado de Dev_server con httplib mediante urlfetch es idéntico al entorno de producción de App Engine. Dev_appserver no es compatible con solicitudes que usan sockets.