Apache HTTP Server 版本 2.4
诸如“mod_ssl: 子进程无法打开 SSLMutex 锁定文件 /opt/apache/logs/ssl_mutex.18332(系统错误如下)[...] 系统:权限被拒绝(errno: 13)
”之类的错误通常是由父目录上的过度限制性权限引起的。确保所有父目录(此处为 /opt
、/opt/apache
和 /opt/apache/logs
)都为 Apache 子进程运行的 UID 设置了 x 位(至少)。(请参阅 User
指令)。
加密软件需要一个不可预测数据的来源才能正常工作。许多开源操作系统提供一个“随机性设备”来实现此目的(通常名为 /dev/random
)。在其他系统上,应用程序必须在生成密钥或执行公钥加密之前,使用适当的数据手动为 OpenSSL 伪随机数生成器 (PRNG) 播种。从 0.9.5 版本开始,需要随机性的 OpenSSL 函数如果 PRNG 未播种至少 128 位随机性,则会报告错误。
为了防止此错误,mod_ssl
必须为 PRNG 提供足够的熵,以使其正常工作。这可以通过 SSLRandomSeed
指令来完成。
SSL_XXX
变量?可以。HTTP 和 HTTPS 使用不同的服务器端口(HTTP 绑定到端口 80,HTTPS 绑定到端口 443),因此它们之间没有直接冲突。您可以运行绑定到这些端口的两个独立的服务器实例,或者使用 Apache 的优雅虚拟主机功能创建两个虚拟服务器,这两个服务器都由 Apache 的同一个实例提供服务 - 一个通过 HTTP 响应端口 80 上的请求,另一个通过 HTTPS 响应端口 443 上的请求。
您可以在任何端口上运行 HTTPS,但标准指定端口 443,这是任何符合 HTTPS 的浏览器默认情况下会查找的端口。您可以通过在 URL 中指定端口来强制浏览器查找其他端口。例如,如果您的服务器设置为在端口 8080 上通过 HTTPS 提供页面,则可以在 https://example.com:8080/
处访问它们。
虽然您通常只使用
$ telnet localhost 80
GET / HTTP/1.0
用于通过 HTTP 对 Apache 进行简单测试,但对于 HTTPS 来说并不容易,因为 TCP 和 HTTP 之间存在 SSL 协议。但是,借助 OpenSSL 的 s_client
命令,您可以通过 HTTPS 进行类似的检查
$ openssl s_client -connect localhost:443 -state -debug
GET / HTTP/1.0
在实际的 HTTP 响应之前,您将收到有关 SSL 握手的详细信息。对于更通用的命令行客户端,它直接理解 HTTP 和 HTTPS,可以执行 GET 和 POST 操作,可以使用代理,支持字节范围等,您应该查看很棒的 cURL 工具。使用它,您可以检查 Apache 是否通过 HTTP 和 HTTPS 正确响应请求,如下所示
$ curl http://localhost/
$ curl https://localhost/
当您尝试通过 HTTP 连接到 HTTPS 服务器(或虚拟服务器)时(例如,使用 http://example.com/
而不是 https://example.com
),可能会发生这种情况。当尝试通过 HTTPS 连接到 HTTP 服务器时(例如,在不支持 HTTPS 的服务器或在非标准端口上支持 HTTPS 的服务器上使用 https://example.com/
),也可能会发生这种情况。确保您连接到支持 SSL 的(虚拟)服务器。
此错误可能是由错误的配置引起的。请确保您的 Listen
指令与您的 <VirtualHost>
指令匹配。如果所有其他方法都失败,请使用 mod_ssl
提供的默认配置重新开始。
SSL_XXX
变量?请确保您已为 CGI/SSI 请求的上下文启用了“SSLOptions +StdEnvVars
”。
通常,要切换 HTTP 和 HTTPS,您必须使用完全限定的超链接(因为您必须更改 URL 方案)。但是,使用 mod_rewrite
,您可以操作相对超链接,以实现相同的效果。
RewriteEngine on RewriteRule "^/(.*)_SSL$" "https://%{SERVER_NAME}/$1" [R,L] RewriteRule "^/(.*)_NOSSL$" "http://%{SERVER_NAME}/$1" [R,L]
此重写规则集允许您使用 <a href="document.html_SSL">
形式的超链接,以在相对链接中切换到 HTTPS。(将 SSL 替换为 NOSSL 以切换到 HTTP。)
RSA 私钥文件是一个数字文件,您可以使用它来解密发送给您的消息。它有一个公共组件,您可以分发(通过您的证书文件),这允许人们将这些消息加密到您。
证书签名请求 (CSR) 是一个数字文件,其中包含您的公钥和您的姓名。您将 CSR 发送到证书颁发机构 (CA),CA 将通过对其进行签名将其转换为真实的证书。
证书包含您的 RSA 公钥、您的姓名、CA 的名称,并由 CA 数字签名。知道 CA 的浏览器可以验证该证书上的签名,从而获取您的 RSA 公钥。这使他们能够发送只有您才能解密的消息。
有关 SSL 协议的总体描述,请参阅 简介 章节。
是的。通常,使用内置的 mod_ssl
启动 Apache 与不使用它启动 Apache 是一样的。但是,如果您在 SSL 私钥文件上设置了密码短语,则会弹出一个启动对话框,要求您输入密码短语。
在启动服务器时必须手动输入密码短语可能会很麻烦 - 例如,从系统引导脚本启动服务器时。在这种情况下,您可以按照 以下步骤从私钥中删除密码短语。请记住,这样做会带来额外的安全风险 - 请谨慎操作!
PATH
中。server.key
和 server.crt
文件$ openssl req -new -x509 -nodes -out server.crt -keyout server.key
httpd.conf
文件中按如下方式使用SSLCertificateFile "/path/to/this/server.crt" SSLCertificateKeyFile "/path/to/this/server.key"
server.key
没有任何密码短语。要向密钥添加密码短语,您应该运行以下命令,并按要求输入和验证密码短语。$ openssl rsa -des3 -in server.key -out server.key.new
$ mv server.key.new server.key
server.key
文件和您输入的密码短语备份到安全位置。以下是分步说明
PATH
中。$ openssl genrsa -des3 -out server.key 2048
server.key
文件和您输入的密码短语备份到安全位置。您可以使用以下命令查看此 RSA 私钥的详细信息$ openssl rsa -noout -text -in server.key
$ openssl rsa -in server.key -out server.key.unsecure
$ openssl req -new -key server.key -out server.csr
https://www.foo.dom/
访问的网站生成 CSR 时,在此处输入“www.foo.dom”。您可以使用以下命令查看此 CSR 的详细信息$ openssl req -noout -text -in server.csr
$ openssl x509 -noout -text -in server.crt
server.key
和 server.crt
。这些可以在您的 httpd.conf
文件中按如下方式使用SSLCertificateFile "/path/to/this/server.crt" SSLCertificateKeyFile "/path/to/this/server.key"
server.csr
文件不再需要。简而言之,可以使用 OpenSSL 提供的 CA.sh
或 CA.pl
脚本。除非有充分的理由,否则应优先使用这些脚本。如果无法使用,可以按照以下步骤创建自签名证书:
$ openssl genrsa -des3 -out server.key 2048
server.key
文件和您输入的密码短语备份到安全位置。您可以使用以下命令查看此 RSA 私钥的详细信息$ openssl rsa -noout -text -in server.key
$ openssl rsa -in server.key -out server.key.unsecure
$ openssl req -new -x509 -nodes -sha1 -days 365 -key server.key -out server.crt -extensions usr_cert
server.crt
文件。$ openssl x509 -noout -text -in server.crt
您只需使用旧密码读取它,然后再次写入,并指定新密码。可以使用以下命令完成此操作:
$ openssl rsa -des3 -in server.key -out server.key.new
$ mv server.key.new server.key
第一次提示输入 PEM 密码时,应输入旧密码。之后,将再次提示您输入密码 - 这次,使用新密码。如果要求您验证密码,则需要再次输入新密码。
此对话框在启动时以及每次重新启动时都会弹出,原因是 server.key
文件中的 RSA 私钥出于安全原因以加密格式存储。需要密码来解密此文件,以便可以读取和解析它。删除密码会从您的服务器中删除一层安全性 - 请谨慎操作!
$ cp server.key server.key.org
$ openssl rsa -in server.key.org -out server.key
server.key
文件只能由 root 用户读取$ chmod 400 server.key
现在 server.key
包含密钥的未加密副本。如果将服务器指向此文件,它不会提示您输入密码。但是,如果任何人获得了此密钥,他们将能够在网络上冒充您。请确保此文件的权限设置为只有 root 用户或 Web 服务器用户可以读取它(最好让您的 Web 服务器以 root 用户身份启动,但以其他用户身份运行,并且密钥只能由 root 用户读取)。
作为另一种方法,可以使用 ``SSLPassPhraseDialog exec:/path/to/program
'' 功能。请记住,这既不更安全也不更不安全。
私钥包含一系列数字。其中两个数字构成“公钥”,其他数字构成“私钥”的一部分。“公钥”位包含在您生成 CSR 时,并随后成为相关证书的一部分。
要检查证书中的公钥是否与私钥的公钥部分匹配,您只需比较这些数字即可。要查看证书和密钥,请运行以下命令:
$ openssl x509 -noout -text -in server.crt
$ openssl rsa -noout -text -in server.key
密钥和证书中的 modulus
和 public exponent
部分必须匹配。由于公钥通常为 65537,并且很难直观地检查长模数是否相同,因此可以使用以下方法:
$ openssl x509 -noout -modulus -in server.crt | openssl md5
$ openssl rsa -noout -modulus -in server.key | openssl md5
这将为您留下两个更短的数字进行比较。理论上,这些数字可能相同,而模数不相同,但这种情况发生的可能性极低。
如果您想检查特定 CSR 属于哪个密钥或证书,可以对 CSR 执行相同的计算,如下所示:
$ openssl req -noout -modulus -in server.csr | openssl md5
OpenSSL 的默认证书格式为 PEM,它只是带有标题和页脚行的 Base64 编码的 DER。对于某些应用程序(例如 Microsoft Internet Explorer),您需要以纯 DER 格式使用证书。可以使用以下命令将 PEM 文件 cert.pem
转换为相应的 DER 文件 cert.der
:$ openssl x509 -in cert.pem -out cert.der -outform DER
发生这种情况的一个原因可能是您的服务器证书由中间 CA 签署。各种 CA,例如 Verisign 或 Thawte,已开始使用中间证书而不是其根证书签署证书。
中间 CA 证书位于根 CA 证书(安装在浏览器中)和服务器证书(安装在服务器上)之间。为了使浏览器能够遍历并验证从服务器证书到根证书的信任链,它需要提供中间证书。CA 应该能够为您提供可以安装在服务器上的此类中间证书包。
您需要将这些中间证书与 SSLCertificateChainFile
指令一起包含。
这可能有多种原因,但主要原因是 SSLSessionCache
指令指定的 SSL 会话缓存存在问题。DBM 会话缓存是最有可能出现问题的地方,因此使用 SHM 会话缓存(或根本不使用缓存)可能会有所帮助。
SSL 使用强大的加密加密,这需要大量的数字运算。当您通过 HTTPS 请求网页时,所有内容(包括图像)都会在传输之前进行加密。因此,HTTPS 流量增加会导致负载增加。
这通常是由 SSLRandomSeed
的 /dev/random
设备引起的,该设备会阻塞 read(2) 调用,直到有足够的熵来服务请求。有关 SSLRandomSeed
指令的更多信息,请参阅参考手册。
通常,mod_ssl
也支持使用中的 OpenSSL 版本支持的任何 SSL 密码。哪些密码可用取决于您构建 OpenSSL 的方式。通常,至少支持以下密码:
要确定可用的实际密码列表,应运行以下命令:
$ openssl ciphers -v
默认情况下,OpenSSL 出于安全原因不允许 ADH 密码。请确保您了解启用这些密码的潜在副作用。
为了使用匿名 Diffie-Hellman (ADH) 密码,您必须使用 ``-DSSL_ALLOW_ADH
'' 构建 OpenSSL,然后将 ``ADH
'' 添加到您的 SSLCipherSuite
中。
您要么在 SSLCipherSuite
指令中犯了错误(将其与 extra/httpd-ssl.conf
中的预配置示例进行比较),要么在生成私钥时选择使用 DSA/DH 算法而不是 RSA,并忽略或忽略了警告。如果您选择了 DSA/DH,那么您的服务器将无法使用基于 RSA 的 SSL 密码进行通信(至少在您配置额外的基于 RSA 的证书/密钥对之前)。现代浏览器(如 NS 或 IE)只能使用基于 RSA 的密码通过 SSL 进行通信。结果是“没有共享密码”错误。要解决此问题,请使用 RSA 算法重新生成服务器证书/密钥对。
原因非常技术性,并且是一个有点“鸡和蛋”的问题。SSL 协议层位于 HTTP 协议层之下,并封装 HTTP。当建立 SSL 连接(HTTPS)时,Apache/mod_ssl 必须与客户端协商 SSL 协议参数。为此,mod_ssl 必须咨询虚拟服务器的配置(例如,它必须查找密码套件、服务器证书等)。但是,为了转到正确的虚拟服务器,Apache 必须知道 Host
HTTP 标头字段。为此,必须读取 HTTP 请求标头。这在 SSL 握手完成之前无法完成,但完成 SSL 握手阶段需要此信息。有关如何规避此问题的说明,请参见下一个问题。
请注意,如果您有通配符 SSL 证书,或者证书使用 subjectAltName 字段包含多个主机名,那么您可以在基于名称的虚拟主机上使用 SSL,无需进一步的解决方法。
基于名称的虚拟主机是一种非常流行的识别不同虚拟主机的方法。它允许您对许多不同的站点使用相同的 IP 地址和相同的端口号。当人们迁移到 SSL 时,似乎自然地认为可以使用相同的方法在同一服务器上拥有许多不同的 SSL 虚拟主机。
这是可能的,但前提是使用 2.2.12 或更高版本的 Web 服务器,并使用 0.9.8j 或更高版本的 OpenSSL 构建。这是因为它需要一个功能,该功能仅由 SSL 规范的最新修订版添加,称为服务器名称指示 (SNI)。
请注意,如果您有通配符 SSL 证书,或者证书使用 subjectAltName 字段包含多个主机名,那么您可以在基于名称的虚拟主机上使用 SSL,无需进一步的解决方法。
原因是 SSL 协议是一个独立的层,它封装了 HTTP 协议。因此,SSL 会话是一个独立的事务,它发生在 HTTP 会话开始之前。服务器在 IP 地址 X 和端口 Y(通常为 443)上接收 SSL 请求。由于 SSL 请求不包含任何 Host: 字段,因此服务器无法确定要使用哪个 SSL 虚拟主机。通常,它只使用它找到的第一个与指定的端口和 IP 地址匹配的虚拟主机。
但是,如果您使用的是支持 SNI 的 Web 服务器和 OpenSSL 版本,并且客户端的浏览器也支持 SNI,那么主机名将包含在原始 SSL 请求中,Web 服务器可以选择正确的 SSL 虚拟主机。
当然,您可以使用基于名称的虚拟主机来识别许多非 SSL 虚拟主机(例如,都在端口 80 上),然后拥有一个单一的 SSL 虚拟主机(在端口 443 上)。但是,如果您这样做,您必须确保将非 SSL 端口号放在 NameVirtualHost 指令上,例如:
NameVirtualHost 192.168.1.1:80
其他解决方法包括:
对不同的 SSL 主机使用单独的 IP 地址。对不同的 SSL 主机使用不同的端口号。
尽管 SSL 压缩协商是在 SSLv2 和 TLS 的规范中定义的,但直到 2004 年 5 月 RFC 3749 才将 DEFLATE 定义为可协商的标准压缩方法。
OpenSSL 0.9.8 在使用 `zlib` 选项编译时,默认开始支持此功能。如果客户端和服务器都支持压缩,则会使用它。但是,大多数客户端仍然尝试使用 SSLv2 Hello 初始连接。由于 SSLv2 在其握手过程中不包含首选压缩算法数组,因此无法与这些客户端协商压缩。如果客户端禁用对 SSLv2 的支持,则可能会发送 SSLv3 或 TLS Hello,具体取决于使用哪个 SSL 库,并且可以设置压缩。您可以通过记录 `%{SSL_COMPRESS_METHOD}x` 变量来验证客户端是否使用 SSL 压缩。
不,用户名/密码是加密传输的。Netscape 浏览器中的图标实际上并没有与 SSL/TLS 层同步。它只会在实际网页数据的第一部分传输时切换到锁定状态,这可能会让人感到困惑。基本身份验证功能是 HTTP 层的一部分,它位于 HTTPS 中的 SSL/TLS 层之上。在 HTTPS 中进行任何 HTTP 数据通信之前,SSL/TLS 层已经完成了其握手阶段,并切换到加密通信。所以不要被这个图标迷惑。
第一个原因是某些 MSIE 版本中的 SSL 实现存在一些与 HTTP 保持活动功能和套接字连接关闭时的 SSL 关闭通知警报相关的细微错误。此外,某些 MSIE 版本中 SSL 与 HTTP/1.1 功能之间的交互存在问题。您可以通过强制 Apache 不使用 HTTP/1.1、保持活动连接或向 MSIE 客户端发送 SSL 关闭通知消息来解决这些问题。这可以通过在您的 SSL 感知虚拟主机部分中使用以下指令来完成
SetEnvIf User-Agent "MSIE [2-5]" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0
此外,某些 MSIE 版本在特定密码方面存在问题。不幸的是,无法为此实现 MSIE 特定的解决方法,因为密码在 SSL 握手阶段就需要。因此,MSIE 特定的 `SetEnvIf
` 无法解决这些问题。相反,您将不得不对全局参数进行更大幅度的调整。在您决定这样做之前,请确保您的客户端确实存在问题。如果没有,请不要进行这些更改 - 它们会影响您所有客户端,无论是 MSIE 还是其他客户端。
TLS-SRP(用于 TLS 的安全远程密码密钥交换,在 RFC 5054 中指定)可以补充或替换证书以验证 SSL 连接。要使用 TLS-SRP,请将 `SSLSRPVerifierFile
` 指令设置为指向 OpenSSL SRP 验证器文件。要创建验证器文件,请使用 `openssl` 工具
openssl srp -srpvfile passwd.srpv -add username
创建此文件后,在 SSL 服务器配置中指定它
SSLSRPVerifierFile /path/to/passwd.srpv
要强制客户端使用非证书 TLS-SRP 密码套件,请使用以下指令
SSLCipherSuite "!DSS:!aRSA:SRP"
从 2.4.7 版本开始,`mod_ssl
` 将使用包含长度超过 1024 位的素数的 DH 参数。但是,Java 7 及更早版本将其对 DH 素数大小的支持限制为最大 1024 位。
如果您的基于 Java 的客户端因异常而中止,例如 `java.lang.RuntimeException: Could not generate DH keypair` 和 `java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)`,并且 httpd 记录 `tlsv1 alert internal error (SSL alert number 80)`(在 `LogLevel
` `info` 或更高版本),您可以使用 `SSLCipherSuite
`(可能与 `SSLHonorCipherOrder
` 结合使用)重新排列 mod_ssl 的密码列表,或者您可以使用具有 1024 位素数的自定义 DH 参数,它将始终优先于任何内置 DH 参数。
要生成自定义 DH 参数,请使用 `openssl dhparam 1024` 命令。或者,您可以使用来自 RFC 2409 第 6.2 节的以下标准 1024 位 DH 参数
-----BEGIN DH PARAMETERS----- MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL /1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC -----END DH PARAMETERS-----
将自定义参数(包括“BEGIN DH PARAMETERS”和“END DH PARAMETERS”行)添加到您使用 `SSLCertificateFile
` 指令配置的第一个证书文件的末尾。
以下信息资源可用。如果出现问题,您应该首先在此处搜索。
以下列出了 mod_ssl 的所有支持可能性,按优先级排序。请按此顺序浏览这些可能性 - 不要只选择您喜欢的那个。
您应该始终至少提供以下信息
configure
` 命令行。一般来说,不,至少除非您提供有关 Apache 转储核心代码位置的更多详细信息。通常,为了帮助您,始终需要回溯(见下一个问题)。没有此信息,几乎不可能找到问题并帮助您解决它。
以下是您需要完成的步骤,以获取回溯