Apache HTTP Server 版本2.2

這個問題的解決方案是簡單而且直接的,只是為了給讀者做做練習。
-- 標準教科書
由于SSL、HTTP、Apache三者共同對請求進行處理,這使得在支持SSL的web服務器上實現特殊的安全制約變得不那么簡單。本節(jié)介紹了普通情況下的解決方案,作為找出最終方案的第一步。采用這些方案以前,先要盡量地去理解,不了解其限制和相關性就貿然使用是最糟糕的了。
可以這樣建立一個僅使用SSLv2協(xié)議及其密碼算法的服務器:
SSLProtocol -all +SSLv2
SSLCipherSuite SSLv2:+HIGH:+MEDIUM:+LOW:+EXP
如下設置為僅使用最強的七種密碼算法:
SSLProtocol all
SSLCipherSuite HIGH:MEDIUM
這個功能被稱為以服務器為網關的加密(Server Gated Cryptography[SGC]),在隨mod_ssl發(fā)布的README.GlobalID文檔中有詳細說明。簡單地說就是:服務器擁有一個由來自Verisign的一個特殊的CA證書簽發(fā)的服務器身份證,從而在對外瀏覽器上實現高強度加密。其過程如下:瀏覽器使用對外密碼進行連接,服務器返回其全局ID身份證,瀏覽器校驗后在后繼HTTP通訊產生之前提升其密碼組,F在的問題是:如何允許這樣的提升,而又強制性地使用高強度加密。換句話說就是:瀏覽器必須在開始連接時就使用高強度加密,或者提升到高強度加密,但是維持對外密碼是不允許的。以下巧妙地解決了這個問題:
# 允許在初始握手階段使用所有的密碼,以允許對外服務器通過SGC功能提升密碼組
SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
<Directory /usr/local/apache2/htdocs>
# 但是最終會拒絕所有沒有提升密碼組的瀏覽器
SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128
</Directory>
顯然,不能使用服務器全局設置SSLCipherSuite,它會限制密碼為強類型。但是,mod_ssl允許重配置針對目錄的密碼組,并自動進行一個帶有服從新配置的SSL參數的重協(xié)商。因此,其解決方案成了:
# 在一般情況下的處理是寬松的
SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
<Location /strong/area>
# 但對于 https://hostname/strong/area/ 及其以下的內容要求高強度密碼
SSLCipherSuite HIGH:MEDIUM
</Location>
如果你了解你的用戶群體(比如:一個封閉的用戶組),正如在一個Intranet中,則可以使用一般的證書認證。所有要做的事情只是,建立由你自己的CA證書簽發(fā)的客戶證書ca.crt ,并依此證書校驗客戶。
# require a client certificate which has to be directly
# signed by our CA certificate in ca.crt
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile conf/ssl.crt/ca.crt
這又要用到mod_ssl提供的針對目錄的重配置功能:
SSLVerifyClient none
SSLCACertificateFile conf/ssl.crt/ca.crt
<Location /secure/area>
SSLVerifyClient require
SSLVerifyDepth 1
</Location>
其關鍵在于對客戶證書的各個組成部分進行驗證,一般就是指驗證 Distinguished Name (DN) 的全部或部分。有基于mod_auth_basic和基于SSLRequire類型的兩種方法以驗證。第一種方法適合用于客戶完全屬于不同類型,并為所有客戶建立了密碼數據庫的情形;第二種方法適用于客戶都屬于一個被編碼寫入DN的公共分級的一部分的情形,因為匹配客戶會更容易。
第一種方法:
SSLVerifyClient none <Directory /usr/local/apache2/htdocs/secure/area> SSLVerifyClient require SSLVerifyDepth 5 SSLCACertificateFile conf/ssl.crt/ca.crt SSLCACertificatePath conf/ssl.crt SSLOptions +FakeBasicAuth SSLRequireSSL AuthName "Snake Oil Authentication" AuthType Basic AuthBasicProvider file AuthUserFile /usr/local/apache2/conf/httpd.passwd require valid-user </Directory>
/C=DE/L=Munich/O=Snake Oil, Ltd./OU=Staff/CN=Foo:xxj31ZMTZzkVA /C=US/L=S.F./O=Snake Oil, Ltd./OU=CA/CN=Bar:xxj31ZMTZzkVA /C=US/L=L.A./O=Snake Oil, Ltd./OU=Dev/CN=Quux:xxj31ZMTZzkVA
第二種方法:
SSLVerifyClient none
<Directory /usr/local/apache2/htdocs/secure/area>
SSLVerifyClient require
SSLVerifyDepth 5
SSLCACertificateFile conf/ssl.crt/ca.crt
SSLCACertificatePath conf/ssl.crt
SSLOptions +FakeBasicAuth
SSLRequireSSL
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"}
</Directory>假設Intranet客戶的IP地址是192.160.1.0/24,Intranet站點子區(qū)域的URL是/subarea ,則可以在HTTPS虛擬主機以外這樣配置(以同時作用于HTTPS和HTTP):
SSLCACertificateFile conf/ssl.crt/company-ca.crt
<Directory /usr/local/apache2/htdocs>
# subarea以外的區(qū)域只允許來自Intranet的訪問
Order deny,allow
Deny from all
Allow from 192.168.1.0/24
</Directory>
<Directory /usr/local/apache2/htdocs/subarea>
# 在subarea以內,允許所有來自Intranet的訪問,
# 但對來自Internet的訪問,僅允許HTTPS+Strong-Cipher+Password
# 或者HTTPS+Strong-Cipher+Client-Certificate
# 如果使用了HTTPS,則確保使用高強度加密
# 同時允許客戶以基本認證的形式認證
SSLVerifyClient optional
SSLVerifyDepth 1
SSLOptions +FakeBasicAuth +StrictRequire
SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128
# 強制來自Internet的客戶使用HTTPS
RewriteEngine on
RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.[0-9]+$
RewriteCond %{HTTPS} !=on
RewriteRule .* - [F]
# 允許網絡訪問和基本認證
Satisfy any
# 控制網絡訪問
Order deny,allow
Deny from all
Allow 192.168.1.0/24
# HTTP基本認證
AuthType basic
AuthName "Protected Intranet Area"
AuthBasicProvider file
AuthUserFile conf/protected.passwd
Require valid-user
</Directory>