ネットワーク

実践入門「TLS/SSL」とは?

投稿日:2023年3月12日 更新日:

インターネットを使ったWebアプリケーションでは、相手(サーバとクライアント)の認証と、通信データの暗号化のため、プロコトルにTLS(Transport Layer Security)/SSL(Secure Socket Layer)が使われます。

認証には、サーバの正当性を確認するためのサーバ認証と、クライアントの正当性を確認するための2つの方法があります。

一般的には、インターネット上のサーバにアクセスする場合には、接続する先のサーバの正当性を確認するために、サーバ認証が行われます。

ただし、接続されるサーバにおいても、クライアントの正当性を確認したい場合、サーバ認証に加えてクライアント認証も行われます。
例えば、サーバに接続できる端末やアプリケーションを限定する必要がある場合、あらかじめ鍵ペアとクライアント証明書を端末やアプリケーションに登しておき、クライアント認証を実施します。

認証が正常に行われ、TLS/SSLのセッションが確立された後、送受信されるすべてのデータが暗号化されます。

■ 主なバージョン

TLSとSSLは、同じものですが、TLSはSSLより後発で、暗号アルゴリズムの強度が上がっています。
これまで使われてきた主なバージョンは、古い順に並べると以下となります。

 SSL3.0
 TLS1.0
 TLS1.2
 TLS1.3

現時点では、TLS1.2以上が主流となりつつ時期ですが、いまだTLS1.0も使われています。
これらのバージョンは、社会で発生するリスクに応じて、推奨されるバージョンが上がっていきます。

■ クライアント認証とサーバ認証のシーケンス

TLS/SSLのシーケンス(シェークハンドと呼ばれます)は、TCPでコネクションを確立した後、以下の手順で実施されます。

認証は、公開鍵暗号化方式(RSA)を使って行われ、データの暗号化はセッション鍵により処理速度の早いAESなどの共通鍵暗号化方式を使って行われます。

クライアントには、クライアント証明書とRSA秘密鍵、サーバには、サーバ証明書とRSA秘密鍵を保持します。

クライアントはサーバ証明書を取得し署名を検証します。サーバはクライアント証明書を取得し、署名を検証します。
さらに、クライアントは、サーバへサーバHELLOメッセージの署名を送信し、サーバでは、その署名を検証することで、クライアントを認証します。


クライアントとサーバでプリマスターシークレットを共有し、マスターシークレットを生成後、お互いに同じセッション鍵を生成し、暗号化通信を開始します。

■ 実践

サーバにApache、クライアントにPythonプログラムと使ったサーバ認証とクライアント認証の両方を実施します。

1)仮のCA局を生成し、CA局の鍵ペアと証明書を作成する

testcaディレクトリを作成し、その配下に、newcerts、privateディレクトリを作成します。

さらに、index.txt、index.txt.attrの空ファイルを作成し、
00を初期値とするserialファイルを作成します。

$ mkdir testca
$ cd testca
S cd testca
testca$ touch index.txt
testca$ touch index.txt.attr
testca$ echo 00 > serial
testca$ tree
.
├── index.txt
├── index.txt.attr
├── serial
├── newcerts
└── private

testca/private配下に、CA局の鍵ペアを生成します。

testca/private$ openssl genrsa 2048 > cakey.key
Generating RSA private key, 2048 bit long modulus (2 primes)
…………………………………………………………..+++++
………………………………………………………………………………………………….+++++
e is 65537 (0x010001)


testca配下に、CA局の証明書発行のためのCSRを生成します。

testca$ openssl req -new -key private/cakey.key -out cakey.csr
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
State or Province Name (full name) [Some-State]:tokyo
Locality Name (eg, city) []:minato
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []:test.com
Email Address []:test@test.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

testca配下にCA局の証明書を生成します。

testca$ openssl x509 -days 365 -req -signkey private/cakey.key -in cakey.csr -out cacert.crt
Signature ok
subject=C = JP, ST = tokyo, L = minato, O = test, OU = test, CN = test.com, emailAddress = test@test.com
Getting Private key

2)サーバの鍵ペアと証明書を作成する

次に、testca配下にサーバのドメイン(test.jp)のフォルダを作成します。certs、privateディレクトリを作成します。
また、testca配下に以下のサーバ用のドメイン情報を記載したsan.txtファイルを作成します。

subjectAltName=DNS:*.test.jp, DNS:test.jp

testca配下は以下のようなディレクトリ・ファイル構成となります。

testca$ tree
.
├── index.txt
├── index.txt.attr
├── newcerts
├── private
├── san.ext
├── serial
└── test.jp
    ├── certs
    └── private

testca/test.jp/private配下に、サーバの鍵ペアを生成します。

testca$ openssl genrsa 2048 > ./test.jp/private/server.key

testca/test.jp/certs配下に、サーバの証明書発行のためのCSRを生成します。

testca$ openssl req -new -key ./test.jp/private/server.key  -out ./test.jp/certs/server.csr 
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
State or Province Name (full name) [Some-State]:tokyo 
Locality Name (eg, city) []:minato
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []:test.jp
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

testca/test.jp/certs配下にサーバ証明書を生成します。(CA局の署名つき)

※)openssl.cnfの以下のデフォルトCAのパスを設定しておくこと

  [ CA_default ]
  dir = <testcaのパス>

testca$ openssl ca -keyfile ./private/cakey.key -cert ./cacert.crt -in ./test.jp/certs/server.csr -out ./test.jp/certs/server.crt -days 825 -outdir ./newcerts -extfile ./san.ext
Using configuration from /home/swata/anaconda3/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 0 (0x0)
        Validity
            Not Before: Mar 11 11:23:04 2023 GMT
            Not After : Jun 13 11:23:04 2025 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = tokyo
            organizationName          = test
            organizationalUnitName    = test
            commonName                = test.jp
            emailAddress              = test@test.jp
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:*.test.jp, DNS:test.jp
Certificate is to be certified until Jun 13 11:23:04 2025 GMT (825 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

3)クライアントの鍵ペアと証明書を作成する

次に、testca配下にクライアントのドメイン(test_cl.jp)のフォルダを作成します。certs、privateディレクトリを作成します。
また、testca配下に以下のサーバ用のドメイン情報を記載したsan.txtファイルを作成します。

subjectAltName=DNS:*.test_cl.jp, DNS:test_cl.jp


testca配下は以下のようなディレクトリ・ファイル構成となります。

S:~/testca$ tree
.
├── cacert.crt
├── cakey.csr
├── index.txt
├── index.txt.attr
├── index.txt.attr.old
├── index.txt.old
├── newcerts
│   ├── 00.pem
│   └── 01.pem
├── private
│   ├── cakey.key
│   └── server.key
├── san.ext
├── serial
├── serial.old
├── test.jp
│   ├── certs
│   │   ├── server.crt
│   │   └── server.csr
│   └── private
│       └── server.key
└── test_cl.jp
    ├── certs
    └── private

testca/test_cl.jp/private配下に、クライアントの鍵ペアを生成します。

testca$ openssl genrsa 2048 > ./test_cl.jp/private/client.key
Generating RSA private key, 2048 bit long modulus (2 primes)
.....+++++
....+++++
e is 65537 (0x010001)

testca/test_cl.jp/certs配下に、クライアントの証明書発行のためのCSRを生成します。

testca$ openssl req -new -key ./test_cl.jp/private/client.key  -out ./test_cl.jp/certs/client.csr 
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
State or Province Name (full name) [Some-State]:tokyo
Locality Name (eg, city) []:minato
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test_cl
Common Name (e.g. server FQDN or YOUR name) []:test_cl.jp        
Email Address []:test_cl@test_cl.jp

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

testca/test_cl.jp/certs配下にクライアント証明書を生成します。(CA局の署名つき)

※)openssl.cnfの以下のデフォルトCAのパスを設定しておくこと

  [ CA_default ]
  dir = <testcaのパス>

testca$ openssl ca -keyfile ./private/cakey.key -cert ./cacert.crt -in ./test_cl.jp/certs/client.csr -out ./test_cl.jp/certs/client.crt -days 825 -outdir ./newcerts -extfile ./san.ext
Using configuration from /home/swata/anaconda3/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Mar 11 11:38:41 2023 GMT
            Not After : Jun 13 11:38:41 2025 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = tokyo
            organizationName          = test
            organizationalUnitName    = test_cl
            commonName                = test_cl.jp
            emailAddress              = test_cl@test_cl.jp
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:*.test.jp, DNS:test.jp
Certificate is to be certified until Jun 13 11:38:41 2025 GMT (825 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

testca配下は以下のようなディレクトリ・ファイル構成となります。

testca$ tree
.
├── cacert.crt
├── cakey.csr
├── index.txt
├── index.txt.attr
├── index.txt.attr.old
├── index.txt.old
├── newcerts
│   ├── 00.pem
│   └── 01.pem
├── private
│   ├── cakey.key
│   └── server.key
├── san.ext
├── serial
├── serial.old
├── test.jp
│   ├── certs
│   │   ├── server.crt
│   │   └── server.csr
│   └── private
│       └── server.key
└── test_cl.jp
    ├── certs
    │   ├── client.crt
    │   └── client.csr
    └── private
        └── client.key

4)UbuntuでのApacheの設定(サーバ認証とクライアント認証)


/etc/apache2/sites-available/default-ssl.confのSSLCertificateFileとSSLCertificateKeyFileにサーバ証明書ファイルとサーバ鍵ペアファイルのパスを記載します。

また、SSLVerifyClientを"require"とすることでクライアント認証を有効にし、
CA局の証明書にてチェックできるように、SSLVerifyDepthに"1"、SSLCACertificateFileにCA局の証明書ファイルのパスを設定します。
<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost

		DocumentRoot /var/www/html
		ErrorLog ${APACHE_LOG_DIR}/error.log
		CustomLog ${APACHE_LOG_DIR}/access.log combined
		SSLEngine on

		SSLCertificateFile	/home/swata/testca/test.jp/certs/server.crt
		SSLCertificateKeyFile   /home/swata/testca/test.jp/private/server.key

		SSLCACertificateFile /home/swata/testca/cacert.crt
		

		SSLVerifyClient require
		SSLVerifyDepth  1

		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
				SSLOptions +StdEnvVars
		</Directory>

	</VirtualHost>
</IfModule>

ApacheのSSL機能を有効にし、再起動します。

$ sudo a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  systemctl restart apache2

$ sudo systemctl restart apache2

5)クライアントからのサーバ認証とクライアント認証によるHTTPS接続

サーバのドメイン名:test.jpで接続するため、/etc/hostsに以下を追記しておきます。

[/etc/hosts]
# test local server
127.0.0.1	test.jp

以下にサーバ認証とクライアント認証によるHTTPS接続のコードを示します。
クライアントの証明書と鍵ペア、そして、CA局の証明書を指定し、サーバのドメイン名で接続します。

# -*- coding: utf-8 -*-
import requests

# path of key and cert files.
path = 'testca/'

# client cert file
crt = path+"test_cl.jp/certs/client.crt"

# client key file
key = path+"test_cl.jp/private/client.key"

# ca cert file
crt_ca = path+"cacert.crt"

# server url
endpoint = "https://test.jp/"

# connect to server.
response=requests.get(endpoint, cert=(crt,key),verify=crt_ca)

print(response.text)

■ まとめ

クライアントをサーバで特定するには、サーバ認証に加えクライアント認証が必要になります。
HTTPのBASIC認証(ユーザIDとパスワード)を使ってクライアントを認証する方法もありますが、クライアント証明書を使う方法のほうが、操作不要であり、PKIの仕組みを使うという点でセキュリティ面で優れています。

ただし、別途、クライアント証明書と鍵ペアを発行し、クライアントにダウンロードさせる仕組みが必要になり、期限の管理も含め、運用面は負担が大きくなる点がデメリットです。



ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい

-ネットワーク

執筆者:


comment

メールアドレスが公開されることはありません。

関連記事

はじめての「パケットキャプチャ」入門

一般的に、パケットキャプチャとは、WireSharkやtcpdumpなどソフトウェアツールを使ってネットワーク上を流れるパケットを収集することを言います。 ネットワークを流れるパケットをキャプチャする …

はじめての「ネットワーク」入門

ITインフラを支えるのは、ネットワークです。ネットワークがなければ、コンピュータを使う意味がないと言ってもいいでしょう。ここでは、ネットワークの基本について解説します。 ■ネットワークの基本概念 国際 …

Chinese (Simplified)Chinese (Traditional)EnglishFilipinoFrenchGermanHindiJapaneseKoreanMalayThaiVietnamese