Section outline

  • 在本实验中,我们使用三台计算机,一台用于客户端,一台用于服务器,另一台用于代理。我们将使用容器表示这些计算机。它们的 IP 地址在下面列出:
    client: 10.9.0.5
    server: 10.9.0.43
    proxy:  10.9.0.143
  • 在此任务中,我们将逐步构建一个简单的 TLS 客户端程序。通过该过程,学生将了解 TLS 编程中的基本要素和安全注意事项。我们将在 client 容器上运行此客户端程序。
  • 在执行此任务之前,学生需要创建一个证书颁发机构(CA),并使用此CA的私钥为该任务创建服务器证书。另一个 SEED 实验《PKI 实验》已经介绍了如何执行这些操作,这是该实验的先决条件。
    在此任务中,我们假定已经创建了所有必需的证书,包括 CA 的公钥证书和私钥(ca.crt 和 ca.key),以及服务器的公钥证书和私钥(server.crt 和 server.key)。应该注意的是,服务器证书中使用的通用名称必须包含学生的姓氏(拼音)和当前年份。

    我们将使用 server 容器来运行此 TLS 服务器程序。确保你设置了正确的 DNS 映射,使 TLS 服务器的域名指向 server 容器的 IP 地址。
  • TLS 可以抵御中间人攻击,但前提是必须保证公钥基础设施是安全的。在此任务中,我们将演示如果 PKI 受到破坏(即某些受信任的 CA 被攻破或服务器的私钥被盗),如何对 TLS 服务器进行中间人攻击。

    我们将实现一个名为 mHTTPSproxy 的简单的 HTTPS 代理(m 代表 mini)。代理程序仅将任务 1 和 2 中的客户端和服务器程序集成在一起。下图说明了它的工作方式。我们将在 proxy 容器上运行代理。
     

    代理实际上是 TLS 客户端和服务器程序的组合。对于浏览器, TLS 代理只是一个服务器程序,它从浏览器(客户端)获取 HTTP 请求,并向其返回 HTTP 响应。代理本身不会生成任何 HTTP 响应,而是将 HTTP 请求转发到实际的 Web 服务器,然后从 Web 服务器获取 HTTP 响应。对于实际的 Web 服务器, TLS 代理只是一个客户端程序。收到响应后,代理将响应转发给浏览器,即真正的客户端。因此,通过集成在前两个任务中实现的客户端和服务器程序,学生应该能够实现基本的代理工作。

    应该注意的是,此任务的目的是使用简单的代理来了解当 PKI 基础设施被攻陷后,中间人攻击如何工作。我们实现的并不是一个很完善的 HTTPS 代理,因为要使代理在每个 Web 服务器上都工作并不容易,需要考虑 HTTP 协议的许多方面。由于本实验的重点是 TLS ,因此学生可以选择两个不同的服务器,并演示其代理服务器可用于这些服务器。对完善的 HTTPS 代理感兴趣的学生可以从网络上寻找其他资料,例如开源的 mitmproxy 。

    处理多个 HTTP 请求。浏览器可能会同时向服务器发送多个 HTTP 请求,因此在从浏览器接收到 HTTP 请求之后,最好生成一个线程来处理该请求,以便代理程序可以同时处理多个请求。以下代码段显示了如何创建一个新的线程来处理每个 TLS 连接。
    import threading
    
    while True:
        sock_for_browser, fromaddr = sock_listen.accept()
        ssock_for_browser = context_srv.wrap_socket(sock_for_browser,
                                                    server_side=True)
        x = threading.Thread(target=process_request, args=(ssock_for_browser,))
        x.start()

    该线程将执行 process_request 函数中的代码,该函数将 HTTP 请求从浏览器转发到服务器,然后将 HTTP 响应从服务器转发到浏览器。以下提供了代码框架:
    def process_request(ssock_for_browser):
        hostname = 'www.example.com'
    
        # Make a connection to the real server
        sock_for_server  = socket.create_connection((hostname, 443))
        ssock_for_server = ... # [Code omitted]: Wrap the socket using TLS
    
        request = ssock_for_browser.recv(2048)
    
        if request:
            # Forward request to server
            ssock_for_server.sendall(request)
    
            # Get response from server, and forward it to browser
            response = ssock_for_server.recv(2048)
            while response:
                ssock_for_browser.sendall(response) # Forward to browser
                response = ssock_for_server.recv(2048)
    
        ssock_for_browser.shutdown(socket.SHUT_RDWR)
        ssock_for_browser.close()

    客户端设置。对于此任务,由于我们将使用浏览器,因此将使用虚拟机作为客户端(受害者),而不是使用 client 容器。在实际攻击中,当受害者访问 Web 服务器(例如 www.example.com)时,我们将发起攻击将受害者重定向到我们的代理。这通常通过 DNS 攻击、BGP 攻击或其他重定向攻击来完成。为了简化,我们不会进行此类攻击,我们只需将以下条目添加到主机 VM 上的  /etc/hosts 文件中(10.9.0.143 是 mitm-proxy 容器的 IP 地址)。
    10.9.0.143   www.example.com
    通过执行上述操作,我们模拟了重定向攻击的结果:受害者到 www.example.com 的流量将被重定向到攻击者机器上,你的 mHTTPSproxy 在那里等待 HTTP 请求。

    任务。学生应该实现简单的 mHTTPSproxy,并在代理容器上运行它。在此 MITM 攻击中,我们假设攻击者已经攻陷了受信任的 CA ,能够使用 CA 的私钥为任何域名生成伪造但有效的证书。在本实验中,浏览器已信任任务 2 中生成的 CA 证书,并且我们假定此 CA 的私钥已被攻击者盗取,因此你(攻击者)可以使用它为任何 Web 服务器伪造证书。请在以下情况下展示您的 MITM 攻击:
    •  针对你自己的服务器发起中间人攻击。
    •  在真实的 HTTPS 网站上发起 MITM 攻击。你可以选择一个网站,找到一个需要登录的帐户,然后使用你的 MITM 代理窃取密码。许多流行的服务器(例如 Facebook)具有复杂的登录机制,你可以找一个具有简单登录机制的服务器。如果你使用的是真实密码,请记住在实验报告中隐藏密码。

    清理。完成此任务后,请记得从浏览器中删除 CA 的证书,并且删除在虚拟机上添加到 /etc/hosts 的所有条目。

  • 你需要提交一份带有截图的详细实验报告来描述你所做的工作和你观察到的现象。你还需要对一些有趣或令人惊讶的观察结果进行解释。请同时列出重要的代码段并附上解释。只是简单地附上代码不加以解释不会获得学分。实验报告的提交方式会由你的老师进行具体安排。