Usar SSL do Python

A versão 2.7 da biblioteca SSL Python foi descontinuada. Em alternativa, use a versão mais recente, atualmente 2.7.11.

O App Engine suporta a biblioteca SSL Python nativa para o tempo de execução do Python 2.7 através da biblioteca SSL, que tem de adicionar à sua app.

Especificar a biblioteca SSL

Se quiser usar o SSL Python nativo, tem de o ativar especificando ssl para a configuração libraries no app.yaml da sua aplicação. Deve usar a versão mais recente da biblioteca, que é atualmente a versão 2.7.11. Esta versão suporta as versões 1.0, 1.1 e 1.2 do TLS e corresponde às versões SSL do Python 2.7.11 e posteriores:

libraries:
- name: ssl
  version: latest

Fornecer certificados de autoridade

Para realizar um handshake SSL, tem de ter um ficheiro que contenha certificados de autoridade de certificação concatenados. Pode carregar o seu próprio ficheiro com a sua aplicação ou usar o ficheiro fornecido pelo App Engine: /etc/ca-certificates.crt.

Realizar um handshake SSL

O método wrap_socket do Python 2.7 usa dois parâmetros de nome de ficheiro que contêm a chave e o certificado do cliente. No ambiente do App Engine, isto é limitativo, uma vez que a aplicação não consegue escrever ficheiros para fornecer dinamicamente diferentes chaves e certificados. Para contornar esta limitação, os parâmetros certfile e keyfile para o método ssl.wrap_socket podem ser objetos "semelhantes a ficheiros" que permitem à aplicação armazenar certificados e chaves de outras formas que não apenas em ficheiros de aplicações carregados. (Um objeto "semelhante a um ficheiro" é um objeto que tem um método "read" que devolve o certificado completo como uma 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)

Não precisa de especificar o parâmetro ssl_version. Se o omitir, a biblioteca 2.7.11 é predefinida como PROTOCOL_SSLv23. Também pode especificar PROTOCOL_TLSv1, PROTOCOL_TLSv1_1 ou PROTOCOL_TLSv1_2.

A implementação do App Engine do método wrap_socket inclui o parâmetro obrigatório ca_certs, que é usado para especificar o ficheiro especial que contém certificados de autoridade de certificação concatenados.

Validar certificados

A sua app deve validar os certificados para evitar determinadas vulnerabilidades de segurança como ataques do tipo "man-in-the-middle".

Para o fazer:

  1. Edite o ficheiro app.yaml, adicionando a variável de ambiente PYTHONHTTPSVERIFY definida como 1:

     env_variables:
       PYTHONHTTPSVERIFY: 1
    
  2. Volte a implementar a sua app.

Em alternativa à especificação da validação de certificados no seu app.yaml, pode chamar explicitamente a biblioteca SSL para fazer a validação, depois de ter realizado uma negociação SSL bem-sucedida, da seguinte forma:

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

O código acima usa a funcionalidade match_hostname, com portabilidade inversa do Python 3.2 para fazer parte do módulo SSL do Python 2.7.11 do App Engine. Esta chamada garante que o certificado fornecido pelo par corresponde a um dos anfitriões designados no certificado do par.

Trabalhar no dev_appserver

Pode emitir pedidos HTTPS através da API urlfetch. O comportamento de validação de certificados do servidor de desenvolvimento através de httplib com urlfetch é idêntico ao do ambiente de produção do App Engine. O dev_appserver não suporta pedidos que usem sockets.