HTTPでのクライアント認証
HTTPでのクライアント認証はいろいろとありますね。.htaccessを使う方法、httpd.confに記述しておいて、ダイジェスト認証を使う方法など。だけど、コレだと、''ちっとセキュリティ的になんとなく心配だったり。気にしすぎなのかもしれませんが、せっかくだから、SSLを使った暗号化通信で、SSLキーのクライアント認証をしてみたい!と思った次第です。なんだか高級そうで、セキュリティも高そうだし。
SSLでの認証の方式
右の図を見てみてください。SSLのシーケンスがどのように開始されるかを説明しております。まず、通信を使用とする双方(または片方)がお互いの証明書を交換し合います。お互いの証明書が間違いないかどうかを認証局(CA)という第三者機関(べりサインとかですね)に問い合わせます。これを問題なし!と判定したら、お互いに、公開鍵という公開しても問題ない暗号化するための鍵を双方で交換し合います。これを受け入れたところからSSLの暗号化通信が始まります。 で、公開鍵をなぜお互いに見せ合いしても問題ないかというと、データを暗号化する際にもらった公開鍵で暗号化します。データを受け取った側は、誰にも秘密な秘密鍵を使って暗号化を解くわけです。暗号化を解くためには、この秘密鍵でないと暗号化が解けません。なので、公開鍵がばれてしまっても、秘密鍵がわからない限り暗号は容易に解けないというわけです。いちおう設定には 自前認証局でSSLクライアント認証を参考にさせてもらってます。
証明書の発行
ここで問題なのが、自分自身を証明する証明書の発行ですが、本当に第三者機関をつかうと、結構お金をとられてしまいます(1年間10万円らしい)。なので、嫌ですね。OpenSSLには、この認証局を自前で何とかする機能があります。ですが、公開組織で認証されていないため、ブラウザなどで警告が出ます(この証明書はチェックできなかったよと言われる)。ブラウザはあらかじめ登録された第三者機関に問い合わせに行くので仕方がありません。ですが、個人で運用するぶんにはコレで十分だと思います。
/etc/ssl/openssl.cnfの設定
[ CA_default ] default_days = 365 # デフォルトの証明期間(1年) [ req ] default_bits = 1024 # デフォルトKEY長(IE5以下のためにKEY長を512bitに) [ req_distinguished_name ] countryName_default = JP # デフォルト国名 stateOrProvinceName_default = Kanagawa # デフォルト州名 localityName_default = Yokohama # デフォルト地方名 0.organizationName_default = CA # デフォルト機構名 commonName_default = XXX.XXX.XX # デフォルトドメイン emailAddress_default = foo@bar.com # デフォルトメールアドレス
認証局を作る(認証局)
証明書を認証する認証局を作ります。つまりはベリサインの代わりを構築するわけですね。認証局も認証するためにパスワードが必要です。覚えておきましょう
$ cd ssl/CA $ /etc/ssl/misc/CA.sh -newca CA certificate filename (or enter to create) Making CA certificate ... Using configuration from /usr/lib/ssl/openssl.cnf Generating a 1024 bit RSA private key ..++++++++++++ ...++++++++++++ writing new private key to './demoCA/private/./cakey.pem' Enter PEM pass phrase: CAのパスワード Verifying password - Enter PEM pass phrase: 認証局のパスワード ----- 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) [JP]: State or Province Name (full name) [Kanagawa]: Locality Name (eg, city) [Yokohama]: Organization Name (eg, company) [CA]: Organizational Unit Name (eg, section) [none]: Common Name (eg, YOUR name) [XXX.XXX.XX]: Email Address [foo@bar.com]:
これを実行すると以下ができます。
ssl/CA/ownCA/private/cakey.pem - 認証局の秘密鍵 ssl/CA/ownCA/cacert.pem - 自己署名型の認証局証明書
サーバ証明書発行願と鍵を作る(サーバ管理者)
まずは暗号鍵と、サーバ証明書を発行してもらうための発行願を作ります。
$ cd ssl/admin $ openssl req -new -keyout securekey.pem -out csr.pem Using configuration from /usr/lib/ssl/openssl.cnf Generating a 1024 bit RSA private key ................++++++++++++ ...........++++++++++++ writing new private key to 'securekey.pem' Enter PEM pass phrase: サーバ管理者のパスワード Verifying password - Enter PEM pass phrase: サーバ管理者のパスワード ----- 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) [JP]: State or Province Name (full name) [Kanagawa]: Locality Name (eg, city) [Yokohama]: Organization Name (eg, company) [server]: Organizational Unit Name (eg, section) [none]: Common Name (eg, YOUR name) [XXX.XXX.XX]: Email Address [foo@bar.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
この結果以下が出来ます。
ssl/admin/csr.pem #サーバ証明書発行願 ssl/admin/securekey.pem #サーバ秘密鍵
認証局でサーバ証明書発行願を認証してもらう(認証局)
サーバ証明書発酵用に、/etc/ssl/ssl.confを変更いたします。
[ usr_cert ] nsCertType = server
$ cd ssl/CA $ cp ../admin/csr.pem . $ openssl ca -out server_cert.pem -infiles csr.pem Using configuration from /usr/lib/ssl/openssl.cnf Enter PEM pass phrase: 認証局のパスワード Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'JP' stateOrProvinceName :PRINTABLE:'Kanagawa' localityName :PRINTABLE:'Yokohama' organizationName :PRINTABLE:'server' organizationalUnitName:PRINTABLE:'none' commonName :PRINTABLE:'XXX.XXX.XX' emailAddress :IA5STRING:'foo@bar.com' Certificate is to be certified until Dec 16 01:56:12 2002 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
この結果、サーバ証明書が出来ます。
ssl/CA/server_cert.pem #認証局署名済サーバ証明
作った証明書でサーバを運用するよう設定する(サーバ管理者)
次に、サーバ側は、この証明書を使用するように設定しましょう。HTTPサーバですね。ただし、先ほどパスワードを設定していますから、apacheを起動するたびにパスワードを聞かれてしまいます。コレを防ぐために、セキュリティは下がりますがパスワードを解除しておきます。
# cd ssl/admin/ # openssl rsa -in securekey.pem -out securekey_unpass.pem
こうして出来たファイルを適当な場所にコピーします。例えば/etc/apache2/ssl
# cp securekey_unpass.pem /etc/apache2/ssl/securekey.pem # cp ../CA/server_cert.pem /etc/apache2/ssl/server_cert.pem
次に、/etc/apache2/modules.d/41_mod_ssl.default-vhost.confに、コピーしたさっきのファイルを設定します。
SSLCertificateFile /etc/apache/ssl/server/server_cert.pem SSLCertificateKeyFile /etc/apache/ssl/server/securekey.pem
クライアント証明書発行願&鍵を作る(ユーザ)
では、同じようにクライアント側の証明書発行願を作ります。これは証明書を発行して欲しい各ユーザが行います。
$ cd ssl/client $ openssl req -new -keyout privatekey.pem -out privatecsr.pem Using configuration from /usr/lib/ssl/openssl.cnf Generating a 1024 bit RSA private key ..................++++++++++++ .............++++++++++++ writing new private key to 'privatekey.pem' Enter PEM pass phrase: クライアントのパスワード Verifying password - Enter PEM pass phrase: クライアントのパスワード ----- 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) [JP]: State or Province Name (full name) [Kanagawa]: Locality Name (eg, city) [Yokohama]: Organization Name (eg, company) [server]: Organizational Unit Name (eg, section) [none]: Common Name (eg, YOUR name) [XXX.XXX.XX]: Email Address [foo@bar.com]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
これで出来たものが
ssl/user/privatekey.pem - クライアントの秘密鍵 ssl/user/privatecsr.pem - クライアントの証明書発行願
クライアント証明書を発行する(認証局)
次にユーザからクライアント証明書発行願を受け取って、認証局で証明書を発行してあげます。 先にクライアント証明書発酵用に/etc/ssl/ssl.confを変更します。
[ usr_cert ] nsCertType = client
次に発行作業です
$ cd ssl/CA $ cp ../user/privatecsr.pem . $ openssl ca -out private_cert.pem -infiles privatecsr.pem Using configuration from /usr/lib/ssl/openssl.cnf Enter PEM pass phrase: CAのパスワード Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'JP' stateOrProvinceName :PRINTABLE:'Kanagawa' localityName :PRINTABLE:'Yokohama' organizationName :PRINTABLE:'user' organizationalUnitName:PRINTABLE:'Users Name' commonName :PRINTABLE:'foo@bar.com' Certificate is to be certified until Dec 16 03:11:29 2002 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
これで、クライアント側証明書ができます。
ssl/CA/demoCA/private_cert.pem
出来た証明書と、秘密鍵の2つを受け取って、ブラウザにインストールできる形にしてあげます。
$ cd ssl/CA
このディレクトリに先ほど作ったprivate_cert.pemとprivatekey.pemを置く
$ openssl pkcs12 -export -inkey privatekey.pem -in private_cert.pem -certfile ownCA/cacert.pem -name uso -out private_cert.p12 Enter PEM pass phrase: クライアントのパスワード Enter Export Password: ブラウザ取込用パスワード Verifying password - Enter Export Password: ブラウザ取込用パスワード
クライアントパスワードが認証局管理者にばれてしまいますが、まぁ信頼できる人、ということでクライアントさんは信じてください(笑)逆に認証局運営者は悪用しないよう心しないといけません。
これで出来たprivate_cert.p12をユーザさんに渡してあげて、自分が使用するブラウザにインストールしてあげると、このブラウザを使用するユーザが誰なのかがわかるという仕組み。
クライアント認証のためのapacheの設定
まず、クライアント認証をするために、提示されたクライアント証明書をどうやって許可されたユーザと判定するのでしょうか。これには、 先ほど作った認証局の証明書で署名されたユーザ証明書は信頼できると判断するようにしましょう。まずサーバ証明書をapacheからみえる場所にコピーします。
# cp ssl/CA/demoCA/cacert.pem /etc/apache2/conf/trustCA
次にapacheの設定を変えます。/etc/apache2/conf/modules.d/41_mod_ssl.default-vhost.confを開きます。
SSLCACertificatePath conf SSLCACertificateFile conf/trustCA
次に、例えばWebサーバの特定の場所はかなりセキュリティ的にクリティカル(例えば会社内に構築した上司の悪口サイトとかアハハ!!(~▽~*)/≡クルッヽ( )ノギャハハ!!≡クルッ(*_ _)/バンバン!!)で、セキュアなアクセスを構築するために、以下の方針を立てます。
- URLはhttp://foo.bar.com/board
- SSLでの通信しか許さない
- クライアント認証を要求する。自分が信頼する認証局で署名したユーザしか許さない
ためには、/etc/apache2/commonappache.confにこんな風に設定します。
<Directory /home/var/www/localhost/htdocs/board> Options -Indexes FollowSymLinks MultiViews AllowOverride All SSLRequireSSL ←SSLでの通信以外許さない SSLVerifyClient require ←SSLクライアント認証を要求する <IfModule mod_access.c> Order deny,allow Allow from all </IfModule> </Directory>
で、apacheを再起動します
# /etc/init.d/apache2 restart
これで、http://foo.bar.com/boardでアクセスするとForbiddenではじかれましたね?次に、https://foo.bar.com/boardでアクセスすると、証明書を要求されましたね?ユーザ証明書が無いブラウザでアクセスすると、アクセスがはじかれます。ユーザ証明書をインストールしたブラウザで、ユーザ証明書を選択して送ってあけると、パスワードを入力する小窓がでましたよね。ここで、自分で設定したパスワードを入力してあげると、アクセスが許可されて通信OKになります。これはセキュアだ!
Page Info | |
---|---|
Page Name : | HTTPoverSSLでクライアント認証させてみる |
Page aliases : | None |
Page owner : | maruo |
Can Read | |
Groups : | All visitors |
Users : | All visitors |
Can Edit | |
Groups : | No one |
Users : | No one |