使用 Python SSL

Python SSL 库的 2.7 版本已被弃用。请使用最新版本,目前为 2.7.11

App Engine 通过 SSL 库支持适用于 Python 2.7 运行时的原生 Python SSL 库,您必须将 SSL 库添加到应用中。

指定 SSL 库

如果要使用原生 Python SSL,必须通过在应用的 app.yaml 中为 libraries 配置指定 ssl 来将其启用。您应该使用最新的库版本,目前为版本 2.7.11。此版本支持 TLS 版本 1.0、1.1 和 1.2,并且对应于 Python 2.7.11 及更高版本的 SSL 版本:

libraries:
- name: ssl
  version: latest

提供颁发机构证书

要执行 SSL 握手,您必须具有包含连接的证书颁发机构证书的文件。您可以使用应用上传自己的文件,也可以使用 App Engine 提供的文件:/etc/ca-certificates.crt

执行 SSL 握手

Python 2.7 wrap_socket 方法接受两个包含客户端密钥和证书的文件名参数。在 App Engine 环境中,这会造成一定的限制,因为应用无法写入文件来动态地提供不同的密钥和证书。为了消除这个限制,ssl.wrap_socket 方法的 certfilekeyfile 参数可以是“类文件”对象,允许应用以其他方式存储证书和密钥,而不仅仅是存储在上传的应用文件中。(“类文件”对象是具有“读取”方法可将整个证书作为字符串返回的对象。)

  # 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)

您无需指定 ssl_version 参数。如果省略这个参数,则 2.7.11 库默认为 PROTOCOL_SSLv23。您还可以指定 PROTOCOL_TLSv1PROTOCOL_TLSv1_1PROTOCOL_TLSv1_2

wrap_socket 方法的 App Engine 实现包含必需参数 ca_certs,该参数用于指定包含连接的证书颁发机构证书的特殊文件。

验证证书

您的应用应该验证证书,以防止某些安全漏洞,如“中间人”攻击。

为此,请执行以下操作:

  1. 修改 app.yaml 文件,添加环境变量 PYTHONHTTPSVERIFY 并将其设置为 1

     env_variables:
       PYTHONHTTPSVERIFY: 1
    
  2. 重新部署您的应用。

若不在 app.yaml 中指定证书,您可以在成功执行 SSL 握手后使用以下代码明确调用 SSL 库来进行验证:

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

上述代码使用 match_hostname 功能,该功能从 Python 3.2 向后移植至 App Engine Python 2.7.11 SSL 模块。此调用可确保对等方提供的证书与对等方证书中的一个指定主机相匹配。

在 dev_appserver 上运行

您可以使用 urlfetch API 发出 HTTPS 请求;使用 urlfetch 时,使用 httplib 的 Dev_server 证书验证行为与 App Engine 生产环境相同。Dev_appserver 不支持使用套接字的请求。