HTTPS通信の中身を解説してみた

#はじめに
この記事ではHTTPS通信について、なんとなく知ってるフェーズからもう一歩踏み込みたい人のために**他のサイトより少しだけ詳しく**その仕組みについてまとめていきたいと思います。
※ハンズオンではなく、仕組みを理解するための内容となっております。

#HTTPとHTTPSの違いって？
HTTPやHTTPSとは、WebブラウザがWebサーバと通信する際に主として使用するプロトコルのことです。
HTTP (HyperText Transfer Protocol)通信ではデータの通信を平文で行います。
そのため、HTTP通信上でクレジットカードの番号やパスワードをやりとりした場合、その内容は簡単に盗まれてしまうのです。
一方、通信データを暗号化してやりとりするHTTPS (HyperText Transfer Protocol Secure)通信では、パケットを盗まれたとしても簡単に解読できません。
このHTTPS通信は個人情報やパスワード等のやりとりが必要なサイトで導入することで、盗聴・なりすまし・中間者攻撃・情報漏洩等の対策として活用されてきました。

#HTTPS通信の仕組み
##SSL/TLSプロトコル
HTTPS通信はSSLプロトコルを使っています。
HTTPやHTTPSプロトコルがアプリケーション層(第7層)のプロトコルであるのに対し、SSL (Secure Socket Layer)/TLS(Transport Layer Security)というのは暗号化・改ざん検知・認証機能を提供するセッション層(第5層)のプロトコルです。
以下では、SSLとTLSを区別せずにSSLと呼ぶことにします。
<img width="700" alt="スクリーンショット 2021-02-07 13.00.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057425/99554588-17ec-290e-6845-ccb9a998059d.png">
HTTP通信において、このSSLを利用したのがHTTPS通信です。
つまり、HTTPS通信の仕組みを理解するには、このSSLの仕組みを理解する必要があるってわけです。
##3つのセキュリティ技術
SSLの仕組みを学ぶ前に、必須である3つのセキュリティ技術について解説します。
###暗号化技術 -共通鍵暗号方式と公開鍵暗号方式-
盗聴の対策として、暗号化というセキュリティ技術が用いられます。
やりとりをする2者の間でルールを取り決め、そのルールに則って情報を変更することにより、通信路上でその2者にしか読めないデータをやりとりするのです。
現在使用されている暗号化のルールは主に2つ。

1つ目が「共通鍵暗号方式」です。
二者間で同じ鍵を持つことで、その鍵でデータを暗号化<->復元化を行うという手法です。
方式自体は非常に単純なのですが、そもそもどのようにして同じ鍵を手にするか、を考える必要があります。
また、やりとりする相手が増えた場合にその数だけ共通鍵を所有・管理しないといけないという問題もあります。
n人とやりとりする場合、n(n-1)/2種類の鍵が必要になります。

その難点を補うのが、2つ目の「公開鍵暗号方式」です。
これは共通鍵とは異なり、暗号化する鍵と復元化する鍵が別々に存在します。
この方式では、まず秘密鍵と公開鍵のセットを用意します。
そして秘密鍵は自分で大切に保管し、公開鍵は名前の通り、周りにそのまま公開します。
ここで、この秘密鍵で暗号化されたデータは公開鍵でしか復元化できません。
同様に公開鍵で暗号化されたデータは秘密鍵でしか復元化できません。
つまりデータを送りたい相手の公開鍵を使って暗号化すれば、復元化は秘密鍵を持っている相手しかできないので、盗聴されても他人には復元できないという仕組みです。
さらに、送られてきたデータを相手の公開鍵で復元できたなら、それはそのデータがその相手から送られてきたという証明になります。
これがこの後説明する「デジタル署名」と呼ばれる認証機能で用いられる技術です。

この公開鍵暗号方式であれば、n人でデータをやりとりする場合に2n種類の鍵で十分です。
ただし、暗号化と復元化の鍵が違うというアルゴリズムは、計算するのに時間がかかります。
以下にメリットとデメリットをまとめてみました。
<img width="600" alt="スクリーンショット 2021-02-07 22.10.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057425/8249148f-9cb5-6519-2d7e-375b9ba41888.png">
ここで説明した「共通鍵暗号」と「公開鍵暗号」はこの先のSSLの始まりの手続きであるハンドシェイクの際に、SSLの肝とも言える、非常に重要な役割を持ちます。
ネタバレになりますが、SSLのハンドシェイクでは安全に共通鍵を共有する方法として公開鍵暗号方式を使い、お互いのデメリットを補うようなハイブリット形式が採用されています。

###メッセージ認証符号 -MAC-
改ざんの対策として、データの完全性を保証するMAC (Message Authentication Code)というセキュリティ技術があります。
任意のデータを使って、MAC関数を用いて計算した値(MAC値)をそのデータと一緒に送ります。
受信側は受け取ったデータから全く同じMAC関数を用いて同様の計算を行い、MAC値と同じになるかを確認します。
ここでMAC関数は同じ入力値に対して同じ出力値であることが求められます。
悪意ある第三者が通信経路でデータを改ざんすることを防ぐために、ショッピングサイトは通常HTTPS通信が利用されています。
MAC関数として使われるハッシュ関数についても今後記事にしていきたいと思いますが、ここでは割愛。
###デジタル署名
なりすましや否認防止の対策として、デジタル署名が用いられます。
その仕組みは先ほど説明した、公開鍵暗号方式のあれです。
"送られてきたデータを相手の公開鍵で復元できたなら、それはそのデータがその相手から送られてきたという証明になる"というものでしたね。
これによって、なりすましてデータをやりとりしたり、相手がやりとりした内容を後から否認できないようにすることができます。
例えば、アクセスしたWebサイトが本当にアクセスしたいサイトであるか、フィッシングサイトではないか、というのを証明することができます。
そして、SSLでは本物かどうかを保証する機能を「サーバー証明書」を利用することで実現しています。
このサーバー証明書の種類については、この記事では詳しく触れません。

##SSLハンドシェイク
長い基礎知識を得て、やっと本題のSSLのハンドシェイクに辿り着きました。
ここではSSL通信で通信を行うための共通鍵交換まで完了する際に必要な手順を追っていきます。
###ハンドシェイクの目的
ハンドシェイクの目的は以下の3つ。
暗号化アルゴリズムの合意、鍵の確立、認証です。

これを大きく4つのステップで実現していきます。

* ステップ1: 使用するアルゴリズムの合意
* ステップ2: サーバーの認証
* ステップ3: データ転送で使用する鍵の確立
* ステップ4: ハンドシェイクが正しく行われていたことの確認

<img width="600" alt="スクリーンショット 2021-02-10 23.05.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057425/1011992c-a723-bec5-6ade-48df717079fb.png">

###ステップ1: 使用するアルゴリズムの合意
まず、クライアントが対応しているアルゴリズムのリストを送付します。
サーバー側はその中から、使用できるアルゴリズムを選択し、クライアントに実際に使用するアルゴリズムを返します。
この時合意するアルゴリズムを以下に挙げます。

* SSLのバージョン
* サーバー認証アルゴリズム
* 鍵交換アルゴリズム
* データ転送で使用する共通鍵暗号方式アルゴリズム
* データ転送で使用するMACアルゴリズム
* 圧縮アルゴリズム

###ステップ2: サーバーの認証
サーバーは使用するアルゴリズムの同意と同時に、自分の公開鍵を含む証明書を送付します。
クライアントはサーバーの証明書を確認することでそのサーバーの認証を行います。

###ステップ3: データ転送で使用する鍵の確立
クライアントとサーバーは同じ鍵生成関数(KDF)を用いて、ランダムな文字列(premaster secret)から共通鍵とMAC鍵を生成します。
同じ鍵の基と同じ関数を用いて鍵を生成するため、鍵自体を通信路に乗せずに鍵を生成します。
このpremaster secretは鍵の基にになるため、秘密にする必要があります。
そのためクライアントは生成したpremaster secretを公開鍵で暗号化して、サーバーに送ります。
ここで、premaster secretのみだと、以前の通信でなりすました第三者がクライアントになりすまして通信を開始する可能性が出てきます。
そこで毎回クライアントとサーバーがそれぞれ生成した乱数2つとpremaster secretを使って同じ共通鍵とMAC鍵を双方が安全に手にするのです。

###ステップ4: ハンドシェイクが正しく行われていたことの確認
最後にここまでのステップが正しく行われたことを確認して、ハンドシェイクは終わりです。
テストとして、ここまででやりとりしたメッセージ内容について、ステップ１で合意したMACアルゴリズムとステップ3で生成したMAC鍵を用いてMAC値を取得します。
この手順はクライアントとサーバー双方で行います。
取得したMAC値を共通鍵で暗号化し、お互いに送り合います。
そして、送られてきたMAC値をそれぞれが共通鍵で復元化し、一致していれば無事にハンドシェイク終了です。
はあ、長かった。
この先は得られた共通鍵でデータやりとりをします。

#まとめ
長い記事でしたが、お付き合い頂きありがとうございます。
SSL通信は奥が深いですね。
セキュリティ技術の進歩とともにハッカーも進歩するので、この分野では勉強し続ける必要がありそうです。
まだ私も勉強している身なので何か誤りを見つけたら、是非教えてください。

参考: [食べる！SSL！ ―HTTPS環境構築から始めるSSL入門 小島 拓也 (著)](https://www.amazon.co.jp/%E9%A3%9F%E3%81%B9%E3%82%8B%EF%BC%81SSL%EF%BC%81-%E2%80%95HTTPS%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%82%8BSSL%E5%85%A5%E9%96%80-%E5%B0%8F%E5%B3%B6-%E6%8B%93%E4%B9%9F-ebook/dp/B00PHC4480)