SSL/TLSって結局何をしているの？

最近、本番環境へのデプロイ練習を目的として、簡単なrailsアプリケーションをconohaサーバーにデプロイしました。
その際SSL証明書の取得や設定をしたのですが、正直なところ「httpsでセキュアな通信ができるんでしょ」程度の認識でしかおりませんでした。エンジニアになったばかりの頃知識としては取り入れたつもりでしたが、実践が伴っておらず雰囲気のみ記憶に残っていた気がします。

そこで、今回はSSL/TLSとHTTPSの違いからSSLの仕組み概要、そして実際に証明書を取得しサーバーで起きていることを（なんとなく）理解できればと思い、記事に残していきます。

## SSL/TLSとは
まず、これらの言葉についてざっと捉えておきます。
SSL：Secure Sockets Layer
TLS：Transport Layer Security
の略で、**クライアントとサーバー、またサーバーとサーバー同士で送信されるデータを暗号化する仕組み**のことです。あくまで暗号化の仕組みであるので通信自体を行うわけではなく、通信上に乗せるデータを暗号化・復元するための物になります。

両者の違いはざっくり、SSLの方が先に利用されていた仕組みで、その脆弱性を改善したものがTLSです。現在はほとんどTLSが利用されていますが、SSLという言葉で聞くことが多いです。

これにより、外部からのデータ盗聴や改ざん、なりすましを防ぐことができます。

イメージとしては、tokyo -> wrnbr みたいになっていて取得してもそれが何かわからない、みたいな形です。（本来はもっと複雑だと思います）

より詳細な暗号化プロセスは後述します。

## HTTPSとは
では、SSL/TLSとともによく出てくるHTTPSとは何なのでしょうか。

これは Hypertext Transfer Protocol Secure の略で、
**SSL/TLSを利用し安全な環境でHTTP通信を行うためのプロトコル**のことです。HTTPにsecureのSがついています。

HTTPSとSSL/TLSがともに出てくるのは、HTTPSで通信をする際にSSL/TLSの技術が必須だから、というわけです。

## 実際の通信プロセス
ここで、HTTPSがSSL/TLSを利用する流れを簡単に図示してみます。
サーバーのssl認証が済んでおり、ssl証明書及びそれに対応する公開鍵、秘密鍵が存在していることが前提です。これがあると、このサーバーは信頼できるものだ、と判断されhttpsによる接続が可能になります。

後ほどこの証明書の取得を行うので、とりあえず証明書とキーがサーバーにあるんだな、くらいで押さえておいてください。

※あくまで概要です。便宜上証明書はssl証明書と記載します。

前提の状態

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/291e3be8-a496-f1ea-c48e-a835af7dcf23.png)



まず、クライアント（webブラウザ）からサーバーにhttps通信をしたい旨をリクエストします。
サーバーはリクエストを受け取ると、クライアントにssl証明書とそれに付随する公開鍵を送信します。※公開鍵の含まれている証明書、の方が正確かもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/bd5442e2-c4ea-3261-0581-801c3030a49e.png)


クライアントはその証明書を取得することにより、サーバーが信頼できるものか確認します。

改ざん等がなく信頼できると判定した場合、クライアントは**共通鍵**（セッションキー）を生成し、一緒に送られてきた公開鍵で暗号化します。この共通鍵が割と大切です。

クライアントはそのセッションキーをサーバーに送信します。
サーバーは、送信されたセッションキーをssl証明書の公開鍵に対応する秘密鍵で復号します。これで**セッションキーがクライアント・サーバー間で共有されました**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/bdf1be2f-7924-acee-5391-75ac3ac59810.png)

このセッションキーは、その名の通りセッションが続く間（基本的にはブラウザが閉じられるまで）有効な一時的なキーです。
生成後は、クライアント・サーバーともにこの鍵を利用して通信内容の暗号化・復号を行います。
暗号化の詳細は分かりませんが、暗号化は順番に数式を実行、複合は逆の順に実行みたいな雰囲気のようです。

 <共通鍵を用いて暗号化・復号>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/414f7d7f-b7d4-2f06-84a1-9e323827ee0b.png)


## 実際に証明書を取得し、サーバーに設定する

というわけで、sslを利用したhttps通信についての概要を見てきましたが、実際にssl証明書を取得してみるとより理解した気になれるので、実際に認証を行います。
Let's Encrypt!という無料で証明書を発行してくれる認証局を利用します。今回はdnsを利用した認証を行います。

認証の概要としては、認証局に認証リクエストをすると、対象ドメインにこのレコードを登録してくれ、という旨が送られてきます。
こちらはそれを指示通りに保存します。そうすることで、そのドメインは確かにあなたのものですね、と認証できるという流れになります。

webサーバーとしてはnginxを利用していきます。

https://letsencrypt.org/ja/

### 実行環境
```
centOs9
nginx
```

### 実行手順

#### 1. certbotをサーバーにインストール

```:command
// パッケージ管理ツールがdnfの場合
sudo dnf -y install certbot
```

#### 2.認証用コマンドを実行する
以下コマンドを実行します。

```:command
sudo certbot certonly --manual -d <ドメイン名（xxxxxx.com等）> --preferred-challenges dns
```

すると、いくつか質問に答えたのち、以下のようなメッセージが送られてきます。（詳細は省いています。）
```
Please deploy a DNS TXT record under the name:

_acme-challenge.<ドメイン名>.

with the following value:

// テキストレコードとしてセットする値が表示される
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.<ドメイン名>.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
```

ここで、enterを押す前に取得したレコードをドメインに設定する必要があります。
（tmux等でターミナルのセッション管理をしていると便利です）
ドメインの設定は、契約しているコンソールなどから設定します。

#### 3.取得したレコードをドメインに設定
画像はお名前.comの場合になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/1f51a07d-26d0-8493-484f-6037cc463c75.png)

↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/39594961-04c6-20fd-23dc-b8e20d1015e3.png)

追加後、反映までしばらく時間がかかります。
以下のようなサイトで、反映された確認することができます。

https://mxtoolbox.com/SuperTool.aspx?action=txt

反映されていると、チェックマークや設定したレコードの値が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/485b6141-763b-f3b6-acc0-b61a757b2ddb.png)

#### 4. Enterで認証を完了する

テキストレコードの設定が完了したら、サーバーに戻りenterしましょう。
以下のようなメッセージが出れば成功です。

```:command
Press Enter to Continue

Successfully received certificate.
// 発行されたssl証明書（公開鍵含む）
Certificate is saved at: <PATH>/fullchain.pem
// 発行された秘密鍵
Key is saved at:         <PATH>/privkey.pem

// 期限は3ヶ月で、以降更新する場合は certificate renews をしてね、というメッセージ
This certificate expires on 2024-11-02.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

これでサーバーに証明書、公開鍵、共通鍵が保存されました。

#### 5. webサーバーの設定に反映

nginxの場合は以下のようになります。
証明書・鍵の位置を指定してあげることによって、httpsリクエストが来た際、証明書をクライアントに送ることや秘密鍵による複合が可能になる、ということでしょうか。なるほど。

保存後、再起動するとhttps通信が可能になっているはずです。

```:/etc/nginx/nginx.conf
server {
  listen       443 ssl http2;
  listen       [::]:443 ssl http2;

  ...その他設定
  
  ssl_certificate "/PATH/TO/fullchain1.pem";
  ssl_certificate_key "/PATH/TO/privkey1.pem";
}
```

## まとめ
というわけで、表層ではありますがSSL/TLSおよびHTTPSについて、また実際にサーバーを認証する流れについてみていきました。
書籍やwebサイトで学ぶのも良いですが、その後実際にやってみることも大事だなとつくづく思いました。

何かの参考になれば幸いですmm