该实验的目的是让学生获得有关 PKI 的第一手经验。 SEED labs有一系列关于公钥加密的实验,而这个实验则针对 PKI 。 通过完成本实验中的任务,学生应该能够更好地理解 PKI 的工作原理, 了解如何使用 PKI 保护 Web 以及如何用 PKI 抵御中间人攻击。
该实验已在SEED Ubuntu 20.04 VM上进行了测试。您可以从 SEED 网站下载VM影像,并在自己的计算机上运行 SEED VM。此外,大多数 SEED 实验都可以在云上进行,您也可以按照我们的指示在云上创建SEED VM。
实验设置文件下载:Labsetup.zip 请下载实验设置文件Labsetup.zip到你的SEED VM中,并解压,然后进入解压目录中,使用下面介绍 的dcbuild命令构建初始的实验环境。 在本实验中,我们将生成公钥证书,然后使用它们来保护 Web 服务器。 证书生成任务将在虚拟机上执行, 但是我们将使用容器托管 Web 服务器。
2.容器安装及其命令
由于本实验需要从 docker hub 拉取镜像。但是从官方 docker register 下载 docker 镜像很慢,您可能需要找到一个注册镜像(register mirror)。 鉴于 Docker 的流行,我们利用国内已经存在一些注册镜像(register mirror),并将它们添加到 /etc/docker/daemon.json,告诉 docker 使用这些注册镜像(register mirror)。如果 此文件不存在,请创建一个。 我们在下面给出一个例子:
{
"registry-mirrors":
[ "https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn" ] }
修改文件后,运行以下命令使更改生效。 第三个命令让你看到你正在使用的注册镜像(register mirror)。
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ sudo docker info
通过建设相关的镜像环境,我们能够安装实验所需要的容器,确保正常打开和关闭,以确保我们实验能够完成。
在下面,我们列出了一些与 Docker 和 Compose 相关的常用命令。 由于我们将非常频繁地使用这些命令, 因此我们在 .bashrc 文件(在我们提供的 SEEDUbuntu 20.04 虚拟机中)中为它们创建了别名。
$ docker-compose build # Build the container image
$ docker-compose up # Start the container
$ docker-compose down # Shut down the container
// Aliases for the Compose commands above
$ dcbuild # Alias for: docker-compose build
$ dcup # Alias for: docker-compose up
$ dcdown # Alias for: docker-compose down
操作命令结果如下:
所有容器都在后台运行。 要在容器上运行命令,我们通常需要获得容器里的shell 。 首先需要使用 docker ps 命令找出容器的 ID , 然后使用 docker exec 在该容器上启动 shell 。 我们已经在 .bashrc文件中为 这两个命令创建了别名。
$ dockps //Alias for: docker ps --format "{{.ID}} {{.Names}}"
$ docksh // Alias for: docker exec -it /bin/bas
3、DNS 设置
在本文档中,我们以 www.bank32.com 为例说明如何部署具有此域名的 HTTPS Web 服务器。 学生需要 使用其他名称完成实验。除非教师额外指定名称,否则学生应在服务器名称中包括其姓名拼音和实验年份。 例如,王小二在2020年进行了此实验, 则服务器名称应为 www.wangxiaoer2020.com 。 你不需要拥 有此域名,你只需要通过在/etc/hosts中添加以下条目即可 将此名称映射到容器的IP地址(第一个条目 是必需的,否则,本实验说明中的示例将会失效):
10.9.0.80 www.bank32.com
10.9.0.80 www.zhangsan1234.com
任务 1: 构建一个证书颁发机构(CA)
任务 2: 为你的 Web 服务器生成证书请求
任务 3: 为你的服务器生成证书
任务 4: 在基于Apache的HTTPS网站中部署证书
证书颁发机构(CA)是颁发数字证书的一个受信任的实体。 数字证书通过证书指定的主体(Subject)证明公 钥的所有权。 有许多商业化的CA被视为根CA。 在撰写本文时,VeriSign是最大的CA。 用户需要付费才能获 得这些商业CA颁发的数字证书。 在这个实验中,我们需要创建数字证书,但是我们不会向任何商业CA付费。 我们会自己创建一个根CA,然 后使用该CA为其他实体(例如服务器)颁发证书。 在此任务中,我们将自己设为根CA,并为此CA生成一 个证书。 与通常由另一个CA签名的其他证书不同,根CA的证书是自签名的。 根CA的证书通常预加载到大 多数操作系统,Web浏览器和其他依赖PKI的软件中。 根CA的证书是无条件信任的。
配置文件''openssl.conf''
要使用 OpenSSL 来创建证书,首先需要有一个配置文件。 配置文件的扩展名通常为 .cnf 。 在OpenSSL 的 ca、 req 和 x509命令中会使用到这个配置文件。 openssl.conf 的说明文档可以网络上找到, OpenSSL 默认会使用/usr/lib/ssl/openssl.cnf作为配置文件。 由于我们需要对这个文件做出一些 改动,我们把它复制到当前目录, 并指定OpenSSL使用这个副本。 配置文件中的 [CA_default] 一节展示了我们需要准备的默认设置。 我们需要创建几个子目录。 请去掉 unique_subject 一行的注释, 以允许创建有相同主体的多张证书。
Listing 1: Default CA setting
[ CA_default ]
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certs with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
serial = $dir/serial # The current serial number
对于 index.txt 文件, 创建一个空文件即可。 对于 serial,放一个字符串格式的数(例如 1000)在文件中。 当你设置好了配置文件openssl.cnf 之后就可以创建和颁发证书了。
取消对#unique_subject = no的注释
创建demoCA文件夹并在其中创建index.txt文件和serial文件并在其中放入数值1000
证书颁发机构(CA)
如前所述,我们需要为我们的CA生成一个自签名证书。 这意味着该CA是完全受信任的,并且其证书将用 作根证书。 你可以运行以下命令为CA生成自签名证书:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
-keyout ca.key -out ca.crt
系统将提示你输入一个密码。 不要丢失此密码,因为每次要使用此CA为其他人签名证书时,都必须输入 密码。 它还将要求填写证书主体信息,例如“国家名称”、“通用名称”等。
命令的输出存储在两个文件中:ca.key 和 ca.crt。 文件ca.key包含CA的私钥,而ca.crt包含公钥证书。你也可以在命令行中指定主体信息和密码,这样就不会提示你输入任何其他信息。 在以下命令中,我们使 用 -subj 设置主体信息; 使用 -passout pass:dees 将密码设置为 dees 。
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
-keyout ca.key -out ca.crt \
-subj "/CN=www.modelCA.com/O=Model CA LTD./C=US" \
-passout pass:dees
我们可以使用以下命令查看 X509 证书和 RSA 密钥的解码内容 (-text表示将内容解码为纯文本;-noout 表 示不打印出编码版本):
openssl x509 -in ca.crt -text -noout
openssl rsa -in ca.key -text -noout
运行以上命令,并从输出中找出以下内容:
公钥相关信息
私钥相关信息
证书中的哪一部分说明了这是一个自签名证书?
此部分,可以看到Issuer和Subject内的属性内容是相同的。
在 RSA 算法中,我们有公钥指数e 、私钥指数d、模数n以及两个秘密的数p和q 使得n = pq 。
公钥指数e:Exponent: 65537 (0x10001)
私钥指数d:
模数n:
质数p:
质数q:
生成证书签名请求(CSR)的命令与在创建 CA自签名证书时使用的命令非常相似, 唯一的区别是是否带有 - x509 选项。 没有这个选项,该命令将生成一个证书签发请求; 加上这个选项,该命令将生成一个自签名 证书。 以下命令为www.bank32.com生成 CSR (您应该使用自己的服务器名称),并添加备用名称(Alternative Name) 许多网站都有不同的 URL 。 例如, www.example.com, example.com,example.net 和example.org都指向 同一 Web 服务器。 由于浏览器实施了主机名匹配策略,因此证书中的通用名(Common Name)必须与服 务器的主机名匹配, 否则浏览器将拒绝与服务器通信。 为了使证书具有多个名称, X.509规范定义了一个可以附加到证书的扩展,名为主体备用名称(SAN)。 使用 SAN扩展名,可以在证书的 subjectAltName字段中指定多个主机名。 要使用此类字段生成证书签名请求,我们可以将所有必要的信息放在配置文件中或命令行中。 我们在本任务中使用命令行的方法(在 TLS 实验中会使用配置文件的方法)。 我们可以在 openssl req 命令中添加以下选项。 应当注意,subjectAltName 扩展字段还必须包括通用名称字段中的主机名。否则,通用名称将不会被接受为有效名称。
openssl req -newkey rsa:2048 -sha256 \
-keyout server.key -out server.csr \
-subj "/CN=www.bank32.com/O=Bank32 Inc./C=US" \
-addext "subjectAltName = DNS:www.bank32.com, \
DNS:www.bank32A.com, \
DNS:www.zhangsan1234.com"\
-passout pass:dees
该命令将生成一对公私钥对,然后使用公钥创建证书签名请求。 我们可以使用以下命令查看CSR和私钥文件的解码内容,并在自己证书签名请求中添加备用名称:DNS:www.zhangsan1234.com。确保在后面的任务中能够使用。具体操作过程及运行结果如下:
命令:openssl req -in server.csr -text -noout
命令:openssl rsa -in server.key -text -noout
CSR文件需要具有CA的签名才能形成证书。 在现实世界中,通常将CSR文件发送到受信任的CA进行签名。 在本实验中,我们将使用我们自己的受信任CA生成证书。 以下命令使用CA的ca.crt 和 ca.key , 将证书签 名请求(server.csr)转换为X509证书(server.crt):
openssl ca -config myopenssl.cnf -policy policy_anything \
-md sha256 -days 3650 \
-in server.csr -out server.crt -batch \
-cert ca.crt -keyfile ca.key
在上面的命令中,myCA_openssl.cnf 是我们从/usr/lib/ssl/openssl.cnf 复制的配置文件 (我们在 任务 1中对此文件进行了更改)。 我们使用配置文件中定义的policy_anything策略,这不是默认策略。默认策略有更多限制,要求请求中的某些主体信息必须与CA证书中的主体信息匹配。命令中使用的策略不 强制执行任何匹配规则。
复制扩展域 出于安全原因,openssl.cnf中的默认设置不允许openssl ca命令将扩展字段从请求复制到最终证书。 为 此,我们可以在配置文件的副本中,取消以下行的注释:
# Extension copying option: use with caution.
copy_extensions = cop
签署证书后,请使用以下命令输出证书的解码内容,并检查是否包含备用名称。
openssl x509 -in server.crt -text -noout
在此任务中,我们将看到网站如何使用公钥证书来保护 Web 浏览。 我们将建立一个基于Apache的HTTPS网站。我们的容器中已经安装了Apache服务器,它支持 HTTPS协议。要搭建 HTTPS 网站,我们只需要配置 Apache服务器,让它知道从哪里获取私钥和证书。 在容器内部,我们已经为bank32.com设置了 HTTPS 站点。可以按照以下示例来设置自己的 HTTPS网站。
一个Apache服务器可以同时托管多个网站。它需要知道网站文件的存储目录。 这是通过位 于/etc/apache2/sites-available目录中的VirtualHost文件来配置完成的。 在我们的容器中,我们 有一个名为 bank32_apache_ssl.conf 的文件,其中包含以下条目:
DocumentRoot /var/www/bank32
ServerName www.bank32.com
ServerAlias www.bank32A.com
ServerAlias www.bank32B.com
DirectoryIndex index.html
SSLEngine On
SSLCertificateFile /certs/bank32.crt (*1*)
SSLCertificateKeyFile /certs/bank32.key (*2*)
上面的示例设置了 HTTPS 站点 https://www.bank32.com (端口443是默认的 HTTPS 端口)。 ServerName 条目指定网站的名称,而DocumentRoot 条目指定网站文件的存储位置。使用 ServerAlias 条目,允许网站使用不同的名称,所以我们提供别名条目,同时还需要告诉 Apache 服务器证书(*1*)和私钥(*2*)的存储位置。 Dockerfile 中,我们已经包含了用 于将证书和密钥复制到容器的/certs文件夹的命令。为了使该网站正常工作,我们需要启用 Apache 的 ssl模块,然后启用该网站。 可以使用以下命令完成操作,这些命令在构建容器时已经执行。
此时打开后,可以看到最后的www.bank32w.com被修改成为www.zhangsan1234.com
由上可知我们已经增加了相关的别名条目,下面我们会对网站中的页面显示进行操作,确保apache服务器运行是能够达到预定目标:
由下图可知index.html中的原来显示数据为:“Hello,world!”
我们通过对其编辑,使得其显示内容为:“Hello,world!zhangsan@2020/10/20!”
主要是对
标签内的内容进行编辑。后面我们将打开浏览器,具体查看展示效果
完成上述内容之后,我们需要为容器装入证书和密钥,通过Volumes文件夹,我们对server.crt文件和server.key文件,进行更名,并且拷贝进volumes文件夹中,而后启动apache服务器。
启动 Apache 服务器
在容器中 Apache 服务器不会自动启动。 我们需要在容器里运行以下命令来启动服务器(我们还列出了一 些相关命令):
// Start the server # service apache2 start
// Stop the server # service apache stop
// Restart a server # service apache restar
Apache 启动时,需要为每个 HTTPS 站点加载私钥。 我们的私钥已加密,因此Apache会要求我们输入密码进行解密。在容器内,用于bank32的密码为 dees 。如果一切设置正确,我们就可以浏览该网站,并且浏览器和服务器之间的所有流量都将被加密。请使用以上示例作为指导,为您的网站设置 HTTPS 服务器。 请描述你的操作步骤、添加到 Apache的配置文件中的内容以及最终结果的屏幕快照,以展示你可以成功浏览 HTTPS站点。
浏览网站:显示如index.html中的段落标签中内容
使用https和http来访问出现的结果不同,是因为https使用了http+ssl的加密认证协议,自己的域名的证书没有被浏览器接受,所以访问的时候没有访问到。
通过本次PKI实验的学习,我对加密解密、数字签名、以及其中的顺序和理念有了深入的了解,密码学也是非常重要的基础,安全不仅仅是个人的安全,更是国家的安全,通过以学习PKI加密的实验,再进行公钥认证的原理和流程的学习,也让我对这套加密体系有了深入的理解,收获很多。