ApacheでSSL (その勘所)

CSR作成まで

まずはSSL関係ファイルの置き場所を作成。場所は任意。
作成したSSL関係ファイル置き場に移動。

# mkdir /usr/local/etc/apache22/ssl
# cd /usr/local/etc/apache22/ssl

この下の秘密鍵作成からCSRの作成まではRSA暗号方式のものですが、処理の面で有利なECDSAな証明書も作成するならECDSAなSSL証明書を作ってみるをご参照願います。2016年時点ではECDSAな証明書のみのウェブサーバ公開はまだお勧めできないのでこの下のとおりにRSAな証明書も作成して下さい。

秘密鍵作成
最近はSSL証明書申請の際に最低でも2048bitの鍵長のCSRを求められることが多いので以下のように作成。

# openssl genrsa -out private.key -aes128 2048
Generating RSA private key, 2048 bit long modulus
..................................................................+++
..............................+++
e is 65537 (0x10001)
Enter pass phrase for private.key: パスワード入力
Verifying - Enter pass phrase for private.key: パスワード再入力
#

むかし流でopenssl genrsa -out private.key 2048とやってしまうとDESの弱い鍵が出来てしまうので注意。

以上でprivate.keyというファイル名で秘密鍵が作成された。
この秘密鍵をApacheなどでそのまま使うことも可能だがApacheなどの起動時にパスワードを求められて入力するまで起動しないので面倒。以下のようにパスワードを入力しなくて済む鍵に変更する。

# openssl rsa -in private.key -out server.key
Enter pass phrase for private.key:秘密鍵のパスワードを入力
writing RSA key
#
server.keyというファイル名でApache用のパスワード入力不要な秘密鍵が作成された。

次にCSRを作成。

2013年11月のMicrosoftの発表以降、従来のSHA1からSHA-2への移行が始まっている。SHA-1でのサーバ証明書発行受付は2015年末で終了らしいが、それ以前であっても利用するSSL認証局でSHA-2でのCSR受付が開始されているならSHA-2で発行するということで。

  • SHA1(旧) openssl req -new -key private.key -out server.csr
  • SHA2(新) openssl req -new -sha256 -key private.key -out server.csr
# openssl req -new -sha256 -key private.key -out server.csr
Enter pass phrase for 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]:JP (日本ならJP固定)
State or Province Name (full name) [Some-State]:Tokyo (都道府県を英語で)
Locality Name (eg, city) []:Chiyoda-ku (区市郡を英語で)
Organization Name (eg, company) [Internet Widgits Pty Ltd]:組織名・会社名などを英数字で
Organizational Unit Name (eg, section) []:部署などを英数字で
Common Name (e.g. server FQDN or YOUR name) []: host.example.com ※注意※
Email Address []:改行で可
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:改行で可
An optional company name []:改行で可
#

これでserver.csrというファイル名でCSRが作成された。
なお、Common Nameの欄を間違えてCSRを作成してSSLサーバ証明書を申請してしまうと軽く死ねる。(最近は再申請も簡単にはなってるが面倒だし時間も無駄になる)
打ち間違いはもちろんNGだが、ホスト名+ドメイン名なのかドメイン名だけなのかも間違えてはダメ。
SSLサーバ証明書申請前なら何度でも再作成可能。

作成したCSRを表示してみる。

% cat server.csr
-----BEGIN CERTIFICATE REQUEST----- MIICrzCCAZcCAQAwajELMAkGA1UEBhMCSlAxDjAMBgNVBAgTBVRva3lvMRMwEQYD BgqDDBzGWiv+oizxYi462itWTkRNYCg2ufxDwUYMfMzKDYkV1vbc5MQlO92e3wqm su/tUDlsG8X1OBzbILQUFl6uVHkqulBXHDKMHBXOYHnMCIzMOEor9uS/h/+T+1kL (途中略) 6lIZ+9p//z1Zp7LnldPW/V5knK/9xF3ndmO12E6NmwqyRAykV0j3qPDhF/dT4nEt uxpPljZUkmu+nqkjAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAALA9XdbNt+gv /QI75OBqK3AQyMwoK0QTIKrZ7pQgbbWTkfwOQMmwiE3JPYeddHW0ONAELWCij8I1 27FlFIkwDO5EOnid7oxds3Xzlw== -----END CERTIFICATE REQUEST-----

SSLサーバ証明書申請

日本のSSL認証登録サイトも安くなってきているが外国の格安サイトと比べるとまだまだ高い。
個人的によく利用するのはCHEAPSSLs.com。(追記: その後SSLs.comになった。)
ComodoのPositiveSSLなら$4.99/年(5年分申請時の場合)、GeotrustのRapidSSLなら$7.99/年(5年分申請時の場合)というお値段(2014年1月現在)なので最長の5年分で申し込むのが良い。
少ない年数分だと割高で証明書の更新が面倒。

CHEAPSSLs.comでSSL証明書を申請する場合はオンラインショッピングと同様にSSL証明書のブランドや種類を選択してカートに登録、その時に何年分かも選択。通常は前述のComodoのPositiveSSLかGeotrustのRapidSSL辺りで十分。一部の古いスマートフォンで正しくSSL証明書が機能しない場合があるが後述のクロスチェーンの設定を行えば問題無い筈。

支払いを完了してサイトの左メニューからMy SSLsを選ぶと購入したものが表示されるのでActivateボタンを押す。CSRの登録画面が出たら先に作成したCSRファイルの内容全てをコピペで貼り付ける。
他幾つかの質問に回答し、登録を完了させるとComodoまたはGeotrustから途中の質問に回答したメールアドレス宛にメールが送付されて来る。そのメールにRapidSSLの場合は本文に、PositiveSSLの場合は本文(Web Server CERTIFICATE以下)と添付ファイル(ZIPファイル中の申請したホスト名orドメイン名.csrという名前のファイル)の両方にSSLサーバー証明書があるので/usr/local/etc/apache22/ssl/example/にserver.crtというファイル名で保存。

SSLサーバー証明書の例

-----BEGIN CERTIFICATE-----
MIIpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
(途中略)
T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDI
-----END CERTIFICATE-----

次に、RapidSSLの場合はメール本文の(INTERMEDIATE CA:以下)に、PositiveSSLの場合は添付ファイルの(ZIPファイル中のPositiveSSLCA2.crtという名前のファイル)を/usr/local/etc/apache22/ssl/example/にchain.crtというファイル名で認証局証明書を保存。

認証局証明書の例

-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
(途中略)
Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----

Comodo PositiveSSLの場合はメールに添付されているZIPファイルからCOMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crtの順に繋ぎ/usr/local/etc/apache22/ssl/example/にchain.crtを作成する。

-----BEGIN CERTIFICATE-----
COMODORSADomainValidationSecureServerCA.crtの中身全部
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
COMODORSAAddTrustCA.crtの中身全部
-----END CERTIFICATE-----

DH Groupを作成する

% openssl dhparam -out dhparams.pem 2048
% mv dhparams.pem /usr/local/etc/apache22/ssl/example/

Apacheの設定

Apache2.2をFreeBSDのportsでインストールしているなら/usr/local/etc/apache22/extra/httpd-ssl.confを編集する。
SSLのセキュリティを考えると使えるプロトコルと鍵交換の方式は以下の様に変更するのがオススメ。(Apache2.2.26以上用)

SSLProtocol  +TLSv1.2 +TLSv1.1 +TLSv1
SSLCompression off
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:CAMELLIA256-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA
証明書関係は次の様になる。
SSLCertificateFile "/usr/local/etc/apache22/ssl/example/server.crt"
SSLCertificateKeyFile "/usr/local/etc/apache22/ssl/example/server.key"
SSLCACertificateFile "/usr/local/etc/apache22/ssl/example/ca.crt"

ちなみにVirtual Domainで公開するならこのファイルは殆ど要らなくて下以外全削除で可。

SSLRandomSeed startup file:/dev/random  512
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect file:/dev/random  512
SSLRandomSeed connect file:/dev/urandom 512
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl
SSLPassPhraseDialog  builtin
SSLSessionCache        "shmcb:/var/run/ssl_scache(512000)"
SSLSessionCacheTimeout  300
SSLMutex  "file:/var/run/ssl_mutex"

Virtual Domainの設定ファイルは以下のようにする。

<VirtualHost *:80>
    ServerName example.com
    ServerAlias *.example.com
    ServerAdmin foobar@example.com
    DocumentRoot /usr/local/www/example
      <Directory "/usr/local/www/example">
        Options +FollowSymLinks +Includes +ExecCGI
        AllowOverride All
        Order allow,deny
        Allow from all
      </Directory>
    ErrorLog /var/log/error-example.log
    CustomLog /var/log/access-example.log combined
    ErrorDocument 404 /
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias *.example.com
    ServerAdmin foobar@example.com
    DocumentRoot /usr/local/www/example
      <Directory "/usr/local/www/example">
        Options +FollowSymLinks +Includes +ExecCGI
        SSLOptions +StdEnvVars
        AllowOverride All
        Order allow,deny
        Allow from all
      </Directory>
    ErrorLog /var/log/error-example-ssl.log
    CustomLog "/var/log/access-example-ssl.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    ErrorDocument 404 /
    Header set Strict-Transport-Security "max-age=315360000; includeSubDomains"

    SSLEngine on
    SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
    SSLCompression off
    SSLHonorCipherOrder on
    SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:CAMELLIA256-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA

    SSLCertificateFile "/usr/local/etc/apache22/ssl/example/server.crt"
    SSLCertificateKeyFile "/usr/local/etc/apache22/ssl/example/server.key"
    SSLCertificateChainFile "/usr/local/etc/apache22/ssl/example/chain.crt"

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>

    BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
</VirtualHost>

2015年4月追記: RC4はもはや不要(危険)なのでSSLCipherSuiteからECDHE-RSA-RC4-SHAを外した。
上のように個別指定でも良いが簡略化して SSLCipherSuite HIGH:!3DES:!aNULL:!DH:!DSS:!PSK:!SRP のようなのもアリ。(追記ココマデ)
2015年12月追記: 以前はSSLCipherSuiteの指定は正直あまり考えなくても特に問題が発生することはなかったが、最近はいろいろ難しくなってて指定順序もしっかりさせないとダメ(特にHTTP/2では)ということもあるのでHIGHを先頭で指定するのは要注意。指定の先頭から優先使用なのでHIGHの前に優先的に使用したいのを1つまたは複数付けておくと良い。
例: EECDH+AESGCM:HIGH:!3DES:!aNULL:!DH:!DSS:!PSK:!SRP (追記ココマデ)

ホスト名部分がワイルドカードで大丈夫なSSL証明書なら上の例の様に、ホスト名が特定名でなければならないSSL証明書の場合は例えばServerName www.example.comとなり、ServerAliasの行は無しになる。
SSL証明書を購入する場合はその辺りも注意しておかないと後で困ることに。一般的にホスト名+ドメイン名形式のSSLが安価で、それプラス、ホスト名部分無しのドメイン名だけで使える証明書が増額無しか僅かに増額、ホスト名部分を自由に使えるSSL証明書が少し高めに設定されているみたい。

/usr/loccal/etc/apache22/httpd.confの最後の部分から次の行の先頭のコメント「#」を外す。

# Secure (SSL/TLS) connections
Include etc/apache22/extra/httpd-ssl.conf

最後にApacheを再起動または起動します。

# /usr/local/etc/rc.d/apache22 restart ・・・強制再起動なら
# /usr/local/etc/rc.d/apache22 graceful ・・・閲覧者に影響の少ない再起動なら
# /usr/local/etc/rc.d/apache22 gracefulstop ・・・閲覧者に影響の少ない停止なら
# /usr/local/etc/rc.d/apache22 start ・・・起動なら
# /usr/local/etc/rc.d/apache22 stop ・・・停止なら

なお、FreeBSD9.*まではOS標準で入っているOpenSSLのバージョンが0.9.*なのでそのままではTLSv1.1,TLSv1.2は使用できない。
packageかportsでsecurity/opensslをインストールし、Apacheを再インストールする。
FreeBSD10.*は最初からOpenSSL 1.0.*が入っているのでそのままTLSv1.1,TLSv1.2が使用できる筈。(未検証)

FreeBSD9.*以下の場合

# cd /usr/ports/security/openssl
# make install
# echo "WITH_OPENSSL_PORT=yes" >> /etc/make.conf  
# portupgrade -f apache22

暗号強度(SSLCipherSuite)の指定は正直結構難しいし、どうしたいというポリシーもサイトや運営者によって違う筈。調べながら調整するのが良いかと。

% openssl ciphers -v 'HIGH:MEDIUM'  #追加は : で区切ってそのまま足す。
% openssl ciphers -v 'HIGH:!3DES'   #HIGHの中から3DESを除くならこんなの、!を付けると除外。
% openssl ciphers -v 'HIGH:\!3DES'  #シェルによっては!があると実行エラーになるので!の前にバックスラッシュを付ける。

確認

設定が完了し、Apacheを起動したらSSLが正しく使えるか先ずはブラウザで表示。次にSSLが正しく設定されているか次のサイトでURLを入力して確認。

どちらも詳しく見てくれる。 SSL Lab's SSL Server Test - SSL Server Test

上の様に評価のサマリが「A+」や「A」でその下に重大な問題が出ていなければ基本的には大丈夫。重大な問題があるとB以下の筈。全てが100点になる必要はない。運用目的から外れる設定や矛盾する項目もあるので完璧は難しいかと。
サマリがAになる設定で上のVirtual Hostの設定の33行目を付けれサマリがA+になる。それほど意味は無さ気だけど。

もう少し簡単に主要な脆弱性の判定を行ってくれるのがGeoTrust SSL Toolbox

Poodle, FREAK, Heartbleedなどの話題?の脆弱性のテストを行ってくれる。

GeoTrust SSL Toolbox

This server is safe from the Poodle vulnerability.の様な表示ならOK。

2015年5月追記

Logjam Attack対応

基本的には2048ビット以上でDiffie-Hellman Groupを作成してDHE_EXPORTしないようにすれば良いが、その方法はApache2.4.8以降ならできるがApache2.2系は無理。

DH Groupを作成する

% openssl dhparam -out dhparams.pem 2048

設定ファイルに以下を指定

SSLOpenSSLConfCmd DHParameters "/usr/local/etc/apache24/ssl/dhparams.pem"

Apache2.4系に移行できるなら問題ないが、Apache2.2系から変えられない場合も多いのでこのままでは困る。

Apache2.2系の場合は以下のようにSSLCipherSuiteからDHを除去し、!EXPORTを付けてやる。

SSLCipherSuite SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:CAMELLIA256-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA:!EXPORT

または簡略化して(ただし、最近は使用注意)

SSLCipherSuite HIGH:AES128:!aNULL:!DH:!DSS:!PSK:!SRP

もしも暗号強度LOVEなら

SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH

(古いブラウザが対応できないので注意)

Guide to Deploying Diffie-Hellman for TLSのページでテスト。
Server Testの項目のTest A Serverのテキストボックスにホスト名を入力して「Go」ボタン。

Guide to Deploying Diffie-Hellman for TLS

上の画像の用に水色のバーの中がGood News!になればOK。

OCSP Stapling

Apache 2.3.3以降で対応なのでApache2.2系では無理です。可能であればApache2.4系に移行しましょう。
この記事は2.2系用なので省略。