Como usar o Python SSL

A versão 2.7 da biblioteca do Python SSL se tornou obsoleta. Em vez disso, use a versão mais recente, atualmente 2.7.11.

O App Engine aceita a biblioteca do Python SSL nativa para o tempo de execução do Python 2.7 por meio da biblioteca SSL, que você precisa adicionar ao app.

Como especificar a biblioteca SSL

Se você quiser usar o SSL nativo do Python, ative-o especificando ssl para a configuração libraries no app.yaml do aplicativo. Você precisa usar a versão da biblioteca mais recente, atualmente a versão 2.7.11. Essa versão aceita as versões TLS 1.0, 1.1 e 1.2 e corresponde às versões SSL do Python 2.7.11 e posteriores:

libraries:
- name: ssl
  version: latest

Como fornecer certificados de autoridade

Para executar um handshake SSL, você precisa ter um arquivo que contenha certificados de autoridade de certificação concatenados. Você pode fazer upload de seu próprio arquivo com seu aplicativo ou usar o arquivo fornecido pelo App Engine: /etc/ca-certificates.crt.

Como executar um handshake SSL

O método wrap_socket do Python 2.7 usa dois parâmetros de nome de arquivo que contêm a chave e o certificado do cliente. No ambiente do App Engine, isso é limitante, porque o aplicativo não pode gravar arquivos para fornecer dinamicamente chaves e certificados diferentes. Para contornar essa limitação, os parâmetros certfile e keyfile do método ssl.wrap_socket podem ser objetos "tipo arquivo" que permitem que o aplicativo armazene certificados e chaves de outras maneiras que não apenas arquivos de aplicativo enviados. Um objeto "semelhante a um arquivo" é aquele que tem um método de "leitura" que retorna todo o certificado 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 é necessário especificar o parâmetro ssl_version. Se você omiti-lo, o padrão da biblioteca 2.7.11 será PROTOCOL_SSLv23. Você 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 arquivo especial que contém certificados de autoridade de certificação concatenados.

Como validar certificados

O aplicativo precisa validar certificados para evitar determinadas vulnerabilidades de segurança, como ataques "man in the middle".

Para fazer isso:

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

     env_variables:
       PYTHONHTTPSVERIFY: 1
    
  2. Implante o aplicativo novamente.

Como alternativa para especificar a validação do certificado em app.yaml, você pode chamar explicitamente a biblioteca SSL para fazer a validação, depois de realizar um handshake SSL bem-sucedido, da seguinte maneira:

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

O código acima usa o recurso match_hostname, portado em retorno a partir do Python 3.2 para fazer parte do módulo SSL do Python 2.7.11 do App Engine. Essa chamada verifica se o certificado fornecido pelo peering corresponde a um dos hosts designados no certificado.

Como trabalhar em dev_appserver

É possível emitir solicitações HTTPS usando a API urlfetch. O comportamento de validação de certificado do Dev_server com httplib usando a urlfetch é idêntico ao ambiente de produção do App Engine. O Dev_appserver não é compatível com solicitações que usam soquetes.