ページへ戻る

− Links

 印刷 

HTTPoverSSLでクライアント認証させてみる のソース :: Nest Of Hawk

xpwiki:HTTPoverSSLでクライアント認証させてみるのソース

« Prev[3]  
[[Gentoo Linuxな生活/サーバ設定関連]]

*HTTPでのクライアント認証 [#v6261c53]
HTTPでのクライアント認証はいろいろとありますね。.htaccessを使う方法、httpd.confに記述しておいて、ダイジェスト認証を使う方法など。だけど、コレだと、''ちっとセキュリティ的になんとなく心配だったり。気にしすぎなのかもしれませんが、せっかくだから、SSLを使った暗号化通信で、SSLキーのクライアント認証をしてみたい!と思った次第です。なんだか高級そうで、セキュリティも高そうだし。

*SSLでの認証の方式 [#e7cdda8f]
#ref(SSL.JPG,right,around);
右の図を見てみてください。SSLのシーケンスがどのように開始されるかを説明しております。まず、通信を使用とする双方(または片方)がお互いの証明書を交換し合います。お互いの証明書が間違いないかどうかを認証局(CA)という第三者機関(べりサインとかですね)に問い合わせます。これを問題なし!と判定したら、お互いに、公開鍵という公開しても問題ない暗号化するための鍵を双方で交換し合います。これを受け入れたところからSSLの暗号化通信が始まります。
で、公開鍵をなぜお互いに見せ合いしても問題ないかというと、データを暗号化する際にもらった公開鍵で暗号化します。データを受け取った側は、誰にも秘密な秘密鍵を使って暗号化を解くわけです。暗号化を解くためには、この秘密鍵でないと暗号化が解けません。なので、公開鍵がばれてしまっても、秘密鍵がわからない限り暗号は容易に解けないというわけです。いちおう設定には [[自前認証局でSSLクライアント認証:http://evo.human.waseda.ac.jp/~shigeki/linux/ca.html]]を参考にさせてもらってます。
#img(,clear);
*証明書の発行 [#u1f0b654]
ここで問題なのが、自分自身を証明する証明書の発行ですが、本当に第三者機関をつかうと、結構お金をとられてしまいます(1年間10万円らしい)。なので、嫌ですね。OpenSSLには、この認証局を自前で何とかする機能があります。ですが、公開組織で認証されていないため、ブラウザなどで警告が出ます(この証明書はチェックできなかったよと言われる)。ブラウザはあらかじめ登録された第三者機関に問い合わせに行くので仕方がありません。ですが、個人で運用するぶんにはコレで十分だと思います。
**準備 [#s4121124]
***作業場所 [#vf7ae099]
 $ mkdir -p ssl/CA        ←認証局の場所
 $ mkdir -p ssl/server    ←サーバ証明書の場所
 $ mkdir -p ssl/client     ←クライアント証明書の場所

***/etc/ssl/openssl.cnfの設定 [#bd04cb5b]
 [ 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 # デフォルトメールアドレス

**認証局を作る(認証局) [#b5efcdc1]
証明書を認証する認証局を作ります。つまりはベリサインの代わりを構築するわけですね。認証局も認証するためにパスワードが必要です。覚えておきましょう
 $ 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 - 自己署名型の認証局証明書

**サーバ証明書&鍵 [#vfb3aa1d]
***サーバ証明書発行願と鍵を作る(サーバ管理者) [#yc3a7450]
まずは暗号鍵と、サーバ証明書を発行してもらうための発行願を作ります。

 $ 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 #サーバ秘密鍵

***認証局でサーバ証明書発行願を認証してもらう(認証局) [#v6363c37]
サーバ証明書発酵用に、/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 #認証局署名済サーバ証明

***作った証明書でサーバを運用するよう設定する(サーバ管理者) [#c1a51b4c]
次に、サーバ側は、この証明書を使用するように設定しましょう。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

**クライアント証明書&鍵 [#i6349be4]
次にクライアントの証明書と鍵を作ります。最終的に出来たものをブラウザにインストールすると、これでクライアント(つまりは使う人)が誰であるかを特定できます。
***クライアント証明書発行願&鍵を作る(ユーザ) [#ne7eba43]
では、同じようにクライアント側の証明書発行願を作ります。これは証明書を発行して欲しい各ユーザが行います。

 $ 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 - クライアントの証明書発行願

***クライアント証明書を発行する(認証局) [#pb4cb8b0]
次にユーザからクライアント証明書発行願を受け取って、認証局で証明書を発行してあげます。
先にクライアント証明書発酵用に/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の設定 [#e1d320ec]
まず、クライアント認証をするために、提示されたクライアント証明書をどうやって許可されたユーザと判定するのでしょうか。これには、 先ほど作った認証局の証明書で署名されたユーザ証明書は信頼できると判断するようにしましょう。まずサーバ証明書を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になります。これはセキュアだ!

*制限事項 [#ycc7d371]
SSLクライアント認証をOKにすると、アクセスするたびにパスワード聞かれるし、テキストボックスに入力して「送信」ボタンを押すようなWebページだと、「Method not Allowed」とエラーがでます。なんなんだよぅ~!お陰で結局うちでは使えませんでした。(;´д`)トホホ

« Prev[3]