6. 实施和使用 SSL 来保护 HTTP 流量

如今,存储在文件服务器上的数据的安全性非常重要。数据泄露可能会给公司造成数千美元的损失。在上一节中,我们将 LDAP 身份验证模块编译到 Apache 构建中,以提供身份验证机制。然而,HTTP 流量非常不安全,所有数据都以明文形式传输 - 这意味着 LDAP 身份验证(用户名/密码)也将以明文形式传输。这造成了一个问题。任何人都可以嗅探到这些用户名/密码并获得对 DAV 存储的访问权限。为了防止这种情况,我们必须加密 HTTP 流量,本质上是 HTTP + SSL 或 HTTPS。通过 HTTPS 传输的任何内容都是加密的,因此 LDAP 用户名/密码不易被破解。HTTPS 运行在端口 443 上。从上一节的编译过程中生成的构建将使 Apache 监听端口 80(普通 HTTP)和 443(HTTPS)。如果您只打算将此服务器用于 DAV,那么我强烈建议您关闭端口 80。在本 HOWTO 的这一节中,我将提供有关 SSL 以及在 Apache HTTP 服务器上维护 SSL 的一些信息。

6.1. SSL 简介

SSL(安全套接字层)是存在于网络层和应用层之间的协议层。顾名思义,SSL 提供了一种加密各种流量的机制 - LDAP、POP、IMAP 以及最重要的 HTTP。

以下是 SSL 中涉及的层的一个过度简化的结构。
	+-------------------------------------------+
	|   LDAP   |    HTTP    |   POP   |   IMAP  |
	+-------------------------------------------+
	|                   SSL                     |
	+-------------------------------------------+
	|               Network Layer               |
	+-------------------------------------------+
	

6.1.1. SSL 中使用的加密算法

SSL 中使用了三种加密技术:公钥-私钥、对称密钥和数字签名

公钥-私钥加密 - 启动 SSL 连接: 在此算法中,加密和解密使用一对私钥和公钥执行。Web 服务器持有私钥,并在证书中将公钥发送给客户端。

  1. 客户端使用 HTTPS 从 Web 服务器请求内容。

  2. Web 服务器使用数字证书响应,其中包括服务器的公钥。

  3. 客户端检查证书是否已过期。

  4. 然后客户端检查签署证书的证书颁发机构是否是浏览器中列出的受信任机构。这解释了为什么我们需要从受信任的 CA 获取证书。

  5. 然后客户端检查 Web 服务器的完全限定域名 (FQDN) 是否与证书上的通用名称 (CN) 匹配?

  6. 如果一切成功,则启动 SSL 连接。

Note注意
 

用私钥加密的任何内容只能使用公钥解密。 同样,用公钥加密的任何内容只能使用私钥解密。 有一种常见的误解,认为只有公钥用于加密,而私钥用于解密。 情况并非如此。 任何密钥都可以用于加密/解密。 但是,如果一个密钥用于加密,则另一个密钥必须用于解密。 例如,消息不能仅使用公钥进行加密和解密。

使用私钥加密和公钥解密确保了发送者(私钥所有者)对接收者的完整性。 使用公钥加密和私钥解密确保只有预期的接收者(私钥所有者)才能访问数据。(即,只有持有私钥的人才能解密消息)。

对称加密 - 数据的实际传输:在 SSL 连接建立后,对称加密用于加密数据,因为它使用的 CPU 周期较少。在对称加密中,数据可以使用相同的密钥进行加密和解密。对称加密的密钥在启动过程中使用公钥加密进行交换。

消息摘要 服务器使用消息摘要算法,例如 HMACSHA-1MD5,以验证传输数据的完整性。

6.1.2. 确保真实性和完整性

加密过程

            Sender's                 Receiver's
           PrivateKey                 PublicKey
          ,-.                     ,-.
         (   )..........         (   )..........
          `-' ''''|'|'||          `-' ''''''''||
                  | |                    |
                  | |                    |
   .----------.   | |    .----------.    |     .----------.
   |          |   V |    |          |    V     |          |
   |Clear Text|--------->|CipherText|--------->|CipherText|
   |          |  Step1   |    1     |  Step2   |    2     |\
   `----------'     |    `----------'          `----------' \    __
         |          |                                        \   [_'
         |          |                                   step5 \   |
         |Step3     |                                       __  --|--
         |          |                                  _.--'      |
         V          |                            _..-''          / \
    .---------.     |    .---------.       _..-''              Receiver
    |  SHA 1  |     V    | Digital | _..-''
    |MsgDigest|--------->|Signature|'            _
    `---------'  Step4   `---------'         _  (_)
        _____ ____   ____  ____ _   _ ____ _| |_ _  ___  ____
       | ___ |  _ \ / ___)/ ___) | | |  _ (_   _) |/ _ \|  _ \
       | ____| | | ( (___| |   | |_| | |_| || |_| | |_| | | | |
       |_____)_| |_|\____)_|    \__  |  __/  \__)_|\___/|_| |_|
                               (____/|_|
	

  • 步骤 1:在此步骤中,原始“明文”消息使用发送者的私钥加密,生成密文 1。这确保了发送者的真实性。

  • 步骤 2:在此步骤中,“密文 1”使用接收者的公钥加密,生成“密文 2”。这将确保接收者的真实性,即只有接收者可以使用其私钥解密消息。

  • 步骤 3:此处创建“明文”的 SHA1 消息摘要。

  • 步骤 4:然后使用发送者的私钥加密 SHA1 消息摘要,生成“明文”的数字签名。接收者可以使用此数字签名来确保消息的完整性和发送者的真实性。

  • 步骤 5:“数字签名”和“密文 2”然后发送给接收者。

解密过程

           Receiver's               Sender's
           PrivateKey               PublicKey
         ,-.                     ,-.
        (   )..........         (   )..........
         `-' ''''''''||          `-' '''''''|||
                |                      |    |
                |                      |    |
  .----------.  |       .----------.   |    | .----------.
  |          |  V       |          |   V    | |          |       .---#1----.
  |CipherText|--------->|CipherText|--------->|ClearText |------>|  SHA 1  |
  |    2     |  Step1   |    1     |  Step2 | |          | Step3 |MsgDigest|
  `----------'          `----------'        | `----------'       `---------'
                                            |                        ||
                                            |                        ||Step5
                                            |                        ||
                                            |                        ||
                               .---------.  |                    .---------.
                               | Digital |  V                    |  SHA 1  |
                               |Signature|---------------------->|MsgDigest|
                 _             `---------'  Step4     _          `---#2----'
                | |                               _  (_)
              __| |_____  ____  ____ _   _ ____ _| |_ _  ___  ____
             / _  | ___ |/ ___)/ ___) | | |  _ (_   _) |/ _ \|  _ \
            ( (_| | ____( (___| |   | |_| | |_| || |_| | |_| | | | |
             \____|_____)\____)_|    \__  |  __/  \__)_|\___/|_| |_|
                                    (____/|_|

  • 步骤 1:在此步骤中,“密文 2”消息使用接收者的私钥解密,生成密文 1。

  • 步骤 2:在此步骤中,“密文 1”使用发送者的公钥解密,生成“明文”。

  • 步骤 3:此处创建“明文”的 SHA1 消息摘要。

  • 步骤 4:然后使用发送者的公钥解密“数字签名”,生成“SHA 1 MSG 摘要”。

  • 步骤 5:“SHA1 MsgDigest #1”然后与“SHA1 MsgDigest #2”进行比较。如果它们相等,则数据在传输过程中未被修改,并且原始“明文”的完整性已得到维护。

6.2. 测试证书

在编译 Apache 时,我们创建了一个测试证书。我们使用 mod_ssl 提供的 makefile 创建了这个自定义证书。我们使用了命令
# make certificate TYPE=custom

此证书可用于测试目的。

6.3. 生产环境使用的证书

对于生产环境使用,您将需要来自证书颁发机构(以下简称 CA)的证书。证书颁发机构是证书供应商,它们在用户的浏览器中被列为受信任的 CA。如加密算法部分所述,如果 CA 未被列为受信任的机构,则当用户尝试连接到安全位置时,将收到警告消息。

同样,测试证书也会导致用户的浏览器上出现警告消息。

6.4. 如何生成 CSR

CSR 或证书签名请求必须发送到受信任的 CA 进行签名。本节讨论如何创建 CSR,并将其发送到您选择的 CA。可以使用 # openssl req 命令来创建 CSR,如下所示

# cd /usr/local/apache/conf/
# /usr/local/ssl/bin/openssl req -new -nodes -keyout private.key -out public.csr
Generating a 1024 bit RSA private key
............++++++
....++++++
writing new private key to 'private.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Jose
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Seagate 
Organizational Unit Name (eg, section) []:Global Client Server
Common Name (eg, YOUR name) []:xml.seagate.com
Email Address []:saqib@seagate.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:badpassword
An optional company name []:

Note“PRNG 未播种”
 

如果您没有/dev/random在您的系统上,您将收到 “PRNG 未播种” 错误消息。 在这种情况下,您可以使用以下命令

# /usr/local/ssl/bin/openssl req -rand some_file.ext -new -nodes -keyout private.key -out public.csr 

将 some_file.ext 替换为您文件系统上现有文件的名称。 可以指定任何文件。 Openssl 将使用该文件来生成种子

Solaris 9 附带/dev/random。 但是在 Solaris 上,您可能需要安装 112438 补丁才能获得 /dev/random

此时,系统会询问您有关服务器的几个问题,以生成证书签名请求

注意:您的通用名称 (CN) 是 Web 服务器的完全限定 DNS (FQDN) 名称,例如 dav.server.com。 如果您输入其他任何内容,它将无法工作。 记住您使用的密码,以备将来参考。

过程完成后,您将拥有private.key和一个public.csr。 您将需要提交public.csr到证书颁发机构。 此时,public.key 未加密。 要加密

 # mv private.key private.key.unecrpyted
# /usr/local/ssl/bin/openssl rsa -in private.key.unecrpyted -des3 -out private.key

6.5. 安装服务器私钥和服务器证书

一旦证书颁发机构处理了您的请求,他们会将编码的证书(数字证书)发回给您。 数字证书的格式由 X.509 v3 定义。 以下显示了典型 X509 v3 数字证书的结构

6.5.1. 验证数字证书

要验证 X.509 证书,请使用以下命令

# openssl verify server.crt
server.crt: OK 

其中server.crt是包含数字证书的文件名

6.5.2. 查看数字证书的内容

数字证书的内容可以使用 # openssl x509 命令查看,如下所示

# openssl x509 -text -in server.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 312312312 (0x0)
        Signature Algorithm: md5WithRSAEncryption
	Issuer: C=US, O=GTE Corporation, CN=GTE CyberTrust Root
        Validity
            Not Before: Feb  8 03:25:50 2000 GMT
            Not After : Feb  8 03:25:50 2001 GMT
	    Subject: C=US, ST=New York, L=Pelham, O=xml-dev, OU=web, CN=www.xml-dev.com/Email=saqib@xml-dev.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
		............
		............
                Exponent: 65537 (0x10001)
    Signature Algorithm: md5WithRSAEncryption
    	............
	............

	

6.5.3. 修改 httpd.conf 以安装证书

您需要将此证书放置在服务器上,并告诉 Apache 在哪里可以找到它。

对于此示例,私钥放置在/usr/local/apache2/conf/ssl.key/目录中,服务器证书放置在/usr/local/apache2/conf/ssl.crt/.

目录中。将从证书颁发机构收到的文件复制到名为server.crt的文件中/usr/local/apache2/conf/ssl.crt/.

并将上一步中生成的 private.key 放置在/usr/local/apache2/conf/ssl.key/

中。然后修改/usr/local/apache2/conf/ssl.conf以指向正确的私钥和服务器证书文件

#   Server Certificate:
#   Point SSLCertificateFile at a PEM encoded certificate.  If
#   the certificate is encrypted, then you will be prompted for a
#   pass phrase.  Note that a kill -HUP will prompt again.  Keep
#   in mind that if you have both an RSA and a DSA certificate you
#   can configure both in parallel (to also allow the use of DSA
#   ciphers, etc.)
SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
#SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server-dsa.crt

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/private.key
#SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server-dsa.key

6.6. 从 RSA 私钥中删除密码短语

存储在 Web 服务器上的 RSA 私钥通常是加密的,您需要密码短语才能解析该文件。 这就是为什么当您使用 modssl 启动 Apache 时,系统会提示您输入密码短语的原因

# apachectl startssl
Apache/1.3.23 mod_ssl/2.8.6 (Pass Phrase Dialog)
Some of your private key files are encrypted for security reasons.
In order to read them you have to provide us with the pass phrases.
Server your.server.dom:443 (RSA)
Enter pass phrase:

加密 RSA 私钥非常重要。 如果破解者获得了您的“未加密的 RSA 私钥”,他/她可以轻松地冒充您的 Web 服务器。 如果密钥已加密,则破解者在不暴力破解密码短语的情况下无法执行任何操作。 建议使用强(即:长)密码短语。

但是,加密密钥有时可能很麻烦,因为每次启动 Web 服务器时都会提示您输入密码短语。 特别是如果您使用 rc 脚本在启动时启动 Web 服务器。 密码短语提示将停止启动过程,等待您的输入。

您可以通过解密密钥轻松摆脱密码短语提示。 但是,请确保没有人可以持有此密钥。 我建议在解密 Web 服务器上的密钥之前,应遵循强化和安全指南。

要解密密钥

首先制作加密密钥的副本

# cp server.key server.key.cryp

然后使用加密重新写入密钥。 系统将提示您输入原始加密密钥密码短语

# /usr/local/ssl/bin/openssl rsa -in server.key.cryp -out server.key
read RSA key
Enter PEM pass phrase:
writing RSA key

保护解密的私钥的一种方法是使其仅对 root 用户可读
# chmod 400 server.key

6.7. SSL 性能调优

6.7.1. 进程间 SSL 会话缓存

Apache 使用多进程模型,其中所有请求并非都由同一进程处理。 当客户端发出多个请求时,这会导致 SSL 会话信息丢失。 多次 SSL 握手会在 Web 服务器和客户端上造成大量开销。 为了避免这种情况,SSL 会话信息必须存储在进程间会话缓存中,允许所有进程访问握手信息。 SSLSessionCache 指令在/usr/local/apache2/conf/ssl.conf文件中可用于指定 SSL 会话缓存的位置

SSLSessionCache        shmht:logs/ssl_scache(512000)
#SSLSessionCache        shmcb:logs/ssl_scache(512000)
#SSLSessionCache         dbm:logs/ssl_scache
SSLSessionCacheTimeout  300

使用 dbm:logs/ssl_scache 会将缓存创建为本地磁盘上的 DBM 哈希文件。

使用 shmht:logs/ssl_scache(512000) 在共享内存段中创建缓存

Noteshmht vs shmcb
 

shmht: 使用哈希表在共享内存中缓存 SSL 握手信息

shmht: 使用循环缓冲区在共享内存中缓存 SSL 握手信息

Note注意
 

并非所有平台/操作系统都支持在共享内存中创建哈希表。 因此,必须改为使用 dbm:logs/ssl_scache

6.7.2. 验证 SSLSession 缓存

要验证 SSLSessionCache 是否正常工作,您可以使用 openssl 实用程序和 -reconnect,如下所示

# openssl s_client -connect your.server.dom:443 -state  -reconnect

CONNECTED(00000003)
.......
.......
Reused, TLSv1/SSLv3, Cipher is EDH-RSA-DES-CBC3-SHA
SSL-Session:
.....
Reused, TLSv1/SSLv3, Cipher is EDH-RSA-DES-CBC3-SHA
SSL-Session:
.....
Reused, TLSv1/SSLv3, Cipher is EDH-RSA-DES-CBC3-SHA
SSL-Session:
.....
Reused, TLSv1/SSLv3, Cipher is EDH-RSA-DES-CBC3-SHA
SSL-Session:
.....
Reused, TLSv1/SSLv3, Cipher is EDH-RSA-DES-CBC3-SHA
SSL-Session:
.....

-reconnect 强制 s_client 使用相同的 SSL 会话 ID 连接到服务器 5 次。 您应该看到 5 次尝试重用相同的会话 ID,如上所示。