你有没有想过为什么你可以通过互联网发送你的信用卡信息?你可能已经注意到了浏览器地址栏中的https:// ,但它是什么?它如何保证你的信息安全?或者你可能想要创建一个Python HTTPS应用程序,但你并不完全确定这意味着什么。如何确保你的web应用是安全的?

你可能会惊讶地发现,不用成为安全专家,也能能回答这些问题!在本文中,你就能得到相关的知识,这些知识组合在一起,可确保网络通信安全。你将看到一些具体示例,这些示例展示了Python HTTPS如何保证信息安全。

译者注:HTTPS是以安全为目标的HTTP通道,已被广泛用于大多数网络应用。本系列分三部分发布《通俗易懂的HTTPS》,并以Python语言实现HTTPS方案。

在本文中,你将学到:

  • 监视和分析网络流量
  • 应用加密技术保证数据安全
  • 描述公钥(PKI)的核心概念
  • 创建你自己的证书颁发机构
  • 构建Python HTTPS应用程序
  • 识别常见的Python HTTPS警告和错误

什么是HTTP?

在深入了解HTTPS及其在Python中的使用之前,了解它的上一代HTTP是很重要的。HTTP是HyperText Transfer Protocol(超文本传输协议)的缩写,它支持浏览网站时的通信。更具体地说,HTTP是用户端(如web浏览器)与web服务器(如itdiffer.com)通信的方式。下面是HTTP通信的简化图:

image-30

这个图表显示了计算机与服务器通信的流程,下面对每一步给予分解说明:

  1. 告诉浏览器访问http://qiwsir.github.io/。
  2. 你的设备和服务器建立了TCP连接。
  3. 浏览器向服务器发送HTTP请求。
  4. 服务器接收HTTP请求并对其进行解析。
  5. 服务器借助HTTP响应产生反应。
  6. 计算机接收、解析并显示响应。

这个分解说明包含了HTTP的基本知识,向服务器发出请求,服务器返回响应。虽然HTTP不需要TCP,但它确实需要可靠的低级协议。在实践中,几乎总是基于IP实现TCP(尽管谷歌试图创建一个替代品)。

就协议而言,HTTP是最简单的协议之一。它的设计目的是通过互联网发送内容,如HTML、视频、图像等,这都是通过HTTP请求和响应完成的。HTTP请求包含以下元素:

  • 请求方法:描述客户端要执行操作的方法,静态内容的方法通常是GET,此外还有其他可用的方法,如POST、HEAD和DELETE。
  • 路径:向服务器指示要请求的网页。例如,此页面的路径是/python-https。
  • 版本:HTTP的版本,如1.0、1.1或2.0。最常见的可能是1.1。
  • headers:描述服务器的其他信息。
  • body:向服务器提供来自客户端的信息。虽然这个字段不是必需的,但是某些方法要求有提交的内容,比如POST。

这些是浏览器用于与服务器通信的内容,服务器借助HTTP响应产生反应,并返回如下信息:

  • HTTP版本,该版本通常与请求的版本相同。
  • 状态代码:指示是否已成功完成了请求。状态代码有很多。
  • 状态消息:提供有助于描述状态代码的可读消息。
  • headers:允许服务器使用关于请求的附加元数据进行响应。
  • body:承载着内容。从技术上讲,这是可选的,但它通常包含一个有用的资源。

这些是HTTP的组成。

什么是HTTPS?

现在你对HTTP有了详细了解,那么,什么是HTTPS?好消息是,你已经知道了!HTTPS,即Hyper Text Transfer Protocol over SecureSocket Layer,超文本传输安全协议。从根本上说,HTTPS与HTTP是相同的协议,但它也意味着通信是安全的。

HTTPS不会重写它所构建的任何HTTP基础,相反,HTTPS由通过加密连接发送的常规HTTP组成。通常,这种加密连接由TLS或SSL提供,它们是在信息通过网络发送之前对其进行加密的协议。

注意:TLS和SSL是非常相似的协议,尽管SSL正在退出,TLS将取代它。这些协议中的差异不在本文的范围内。只要知道TLS是SSL的更新、更好的版本就足够了。

那么,为什么要有HTTP和HTTPS两种呢?为什么不把加密引入HTTP协议本身呢?答案是可移植性。保护通信安全是一个重要而困难的问题,但HTTP只是许多需要安全性的协议之一。在网络上,除了网页访问之外,还有其他的许多应用:

  • E-mail
  • 即时通讯
  • VoIP

每项应用都有专门的协议,如果每个协议都必须创建自己的安全机制,那么这个世界就会变得更加不安全,也会更加混乱。TLS是上述协议中常用的一种安全通信方法。

在下文中,你将学习到的几乎所有内容都不仅仅适用于Python HTTPS应用,此外,还将学习安全通信的基础知识,以及它如何具体应用于HTTPS。

为什么HTTPS很重要?

通信安全对于提供安全的在线环境至关重要。随着包括银行和医疗站点在内的越来越多的网络应用,对于开发人员来说,创建Python HTTPS应用变得越来越重要。同样,HTTPS只是TLS或SSL上的HTTP,TLS的设计是为了保护隐私不被窃听,它还可以提供客户端和服务器的身份验证。

在本文中,你将通过执行以下操作深入探讨这些概念:

  • 创建Python HTTPS服务器
  • 与Python HTTPS服务器通信
  • 捕获这些通信
  • 分析这些消息

我们开始吧!

创建示例

假设你是一个叫做秘密松鼠的酷Python俱乐部的领导,松鼠,作为机密,需要以加密信息的方式发布给会议。作为领导,你要选择发布的加密信息,每次会议都会更改这个信息。不过,有时候,你很难在会前和所有会员见面,告诉他们此信息!你决定设置一个秘密服务器,成员可以在其中只能看到发给他们的加密信息。

You’ve followed some tutorials on Real Python and decide to use some dependencies you know:

你已经学习了一些关于真正Python的知识(如果还没有学习,推荐《Python大学实用教程》(电子工业出版社)),并安装如下模块:

  • 用于构建web应用程序的Flask
  • 作为生产服务器的uWSGI
  • 向服务器发起请求的requests

要安装所有这些,可以使用pip

$ pip install flask uwsgi requests

安装后,就可以开始编写应用程序了。创建名为server.py的文件,并在其中编写Flask应用:

# server.py
from flask import Flask

SECRET_MESSAGE = "fluffy tail"
app = Flask(__name__)

@app.route("/")
def get_secret_message():
    return SECRET_MESSAGE

每当有人访问服务器的/路径时,这个Flask应用程序将显示SECRET_MESSAGE的内容。这样一来,就可以在秘密服务器上部署应用程序并运行它:

$ uwsgi --http-socket 127.0.0.1:5683 --mount /=server:app

此命令旨在启动的服务器上使用上面的Flask应用,所使用的端口有点奇怪(5683),因为你不希望别人能找到它,为自己的“鬼鬼祟祟”感到庆幸!可以通过访问浏览器访问http://localhost:5683来确认它是否正常工作。

因为秘密松鼠俱乐部中的每个人都认识Python,所以你决定帮助他们编写一个名为client.py的脚本,以便让他们获取加密信息:

# client.py
import os
import requests

def get_secret_message():
    url = os.environ["SECRET_URL"]
    response = requests.get(url)
    print(f"The secret message is: {response.text}")

if __name__ == "__main__":
    get_secret_message()
image-31

只要设置了SECRET_URL环境变量,此代码就会打印出秘密消息。在本例中,SECRET_URL127.0.0.1:5683。所以,你的计划是给每个俱乐部成员一个秘密的网址,告诉他们要保密和安全。

虽然这可能看起来不错,但这样做还不够!事实上,即使你在这个网站上输入用户名和密码,它仍然是不安全的。甚至你的团队设法保证了URL的安全,你的秘密消息也还不安全。为了说明为什么你需要了解一些有关监视网络流量的信息,你需要使用一个名为Wireshark的工具。

Setting Up Wireshark

设置Wireshark

Wireshark是一个应用广泛的网络和协议分析工具,这它可以帮助你了解网络连接上发生的事情。安装和设置Wireshark对于本文是可选的,但是如果你想继续学习,请安装和使用它。下载页提供了几个安装程序:

  • macOS 10.12及更高版本
  • 64位Windows安装程序
  • 32位Windows安装程序

如果你使用的是Windows或Mac,应该能够下载适当的安装程序并按照提示进行操作。最后,你应该有一个正在运行的Wireshark。

如果你是在一个基于Debian的Linux环境中,安装就会有点困难,但仍然是可能的。可以使用以下命令安装Wireshark:

$ sudo add-apt-repository ppa:wireshark-dev/stable
$ sudo apt-get update
$ sudo apt-get install wireshark
$ sudo wireshark

启动Wireshark之后,可以看到如下界面:

image-32

随着Wireshark的运行,是时候分析一些流量了!

看呀,你的数据多么不安全

当前客户端和服务器的运行方式是非常不安全的。HTTP发送的所有东西,任何人都可以清楚地看到。这意味着,即使某人没有你的SECRET_URL,他仍然可以看到你所做的一切,只要他可以监视你和服务器之间的任何设备上的流量。

这对你来说应该比较可怕。毕竟,你不想别人出现在你的秘密松鼠会议上!下面证明这种情况是真实发生的。首先,如果服务器尚未运行,请启动它:

$ uwsgi --http-socket 127.0.0.1:5683 --mount /=server:app

这将在端口5683上启动Flask应用。接下来,你将在Wireshark中开始数据包捕获。此数据包捕获将帮助你查看进出服务器的所有流量。首先在Wireshark上选择Loopback:lo接口:

image-33

你可以看到Loopback:lo部分突出显示,这指示Wireshark监视此端口的流量。你可以做得更好,并指定要捕获的端口和协议,可以在捕获筛选器中键入port 5683,在显示筛选器中键入http

image-34

绿色框表示Wireshark对你键入的筛选器感到满意。现在你可以单击左上角的按钮开始捕获:

image-35

单击此按钮将在Wireshark中生成一个新窗口:

image-36

这个新窗口相当简单,但底部的消息显示<live capture in progress>,这表明它正在工作。别担心什么都没显示出来,这很正常。为了让Wireshark报告任何事情,服务器上必须有一些活动。要获取一些数据,请尝试运行客户端:

$ SECRET_URL="http://127.0.0.1:5683" python client.py
The secret message is: fluffy tail

在执行上面的client.py代码之后,你现在应该可以在Wireshark中看到一些条目。如果一切顺利,那么你将看到两个类似于以下内容的条目:

image-37

这两个记录表示发生通信的两个部分。第一个是客户机对服务器的请求。当你单击第一个条目时,你将看到大量信息:

image-38

很多信息!在顶部,仍然有HTTP请求和响应。选择其中一个条目后,你将看到中间和底部的行填充了信息。

中间一行提供了协议的详细信息,Wireshark能够为所选的请求标识这些信息。这个详细信息允许你探索HTTP请求中实际发生的事情。Wireshark在中间一行从上到下描述了一些信息,下面是这些信息的快速摘要:

  • 物理层:描述用于发送请求的物理接口。
  • 以太网信息:向用户显示的第2层协议,其中包括源和目标MAC地址。
  • IPv4:显示源和目标IP地址(127.0.0.1)。
  • TCP:包括所需的TCP握手,以便创建可靠的数据管道。
  • HTTP:显示关于HTTP请求本身的信息。

当你展开超文本传输协议层时,可以看到构成HTTP请求的所有信息:

此图显示脚本的HTTP请求:

  • Method: GET
  • Path: /
  • Version: 1.1
  • Headers: Host: 127.0.0.1:5683, Connection: keep-alive, and others
  • Body: No body

你看到的最后一行是十六进制的数据转储。在这个十六进制转储中,你可能会注意到:你实际上可以看到HTTP请求的各个部分。那是因为你的HTTP请求是公开发送的。但是回复呢?如果单击HTTP响应,则会看到一个类似的视图:

image-39

同样,也有那三个部分。如果你仔细看这个十六进制转储文件,会看到明文的秘密消息!这对秘密松鼠来说是个大问题。这意味着,如果有兴趣的话,任何有专门技术知识的人都可以很容易地看到这个数据流。那么,你怎么解决这个问题呢?答案是密码学。