CCCMKホールディングス TECH Labの Tech Blog

TECH Labスタッフによる格闘記録やマーケティング界隈についての記事など

ブログタイトル

セキュアなWeb通信を実現する"TLS"について調べてみました("TLS1.3"ベース)

こんにちは、技術開発ユニットの三浦です。最近我が家にデスクトップ型のゲーミングPCがやってきました。お休みを利用して部屋を掃除して、なんとか置き場所を確保することが出来ました。さらにメモリスロットが空いていたので、人生初のメモリの追加にもチャレンジしてみました!せっかくなので小学生の娘と一緒に、「これがCPUっていうパソコンの頭脳みたいなところで・・・」とパソコンの中身の観察会も兼ねてみました。とてもいい機会になったと思います。

今回は"TLS(Transport Layer Security)"についての話です。Web上でデータをやり取りする時に「この通信って安全なの?」という質問をされたらどんな答えを考えるでしょうか。「"HTTPS"で通信しているから、データが暗号化されていて、証明書で安全な通信先であることも担保されている、だから安全です。」こういう感じで私は答えていました。しかしどうやって暗号化されているのか、とか、証明書って何が書いてあるの、とか、もう少し詳しく調べておきたいと思い、まず"HTTPS"の仕組みについて調べ始めると、それを支える"TLS"という技術について調べる必要があることが分かりました。軽い気持ちで調べ始めたものの、この"TLS"が様々な技術で成り立つ非常に奥の深い技術で、まさに「"TLS"の沼」にはまってしまった次第です・・・。そしてこの記事を書いている今になってもその沼から抜け出せておらず、この数週間、気が付けば「"TLS", "TLS"...」とつぶやき続け、ブラウザの検索履歴がほぼ「"TLS" ××」で埋め尽くされてしまいました。 一旦自分の頭の整理を兼ねて、この場をお借りして調べたことをまとめたいと思います。 (もし間違いがありましたら、よろしければご指摘を頂けるとうれしいです。)

"HTTPS"と"TLS"

最初に"HTTPS"と"TLS"の関係から。"HTTPS"のベースにはWeb上でデータをやり取りするためのプロトコル"HTTP"がありますが、"HTTP"だけではデータが平文(暗号化されていない状態)でやり取りされるため、通信内容を第三者に盗み見られてしまう恐れがあります。クレジットカードや住所などの情報が意図しない誰かに知られてしまうということです。また、今データをやり取りしている相手は本当にやり取りをしたい相手かというとそうとは言い切れません。なりすましをした別の相手といつの間にかデータのやり取りをしているかもしれません。さらにやり取りしているデータを途中で第三者に書き換えられてしまう恐れもあります。ECサイトで注文内容を書き換えられてしまうと、大変な問題になってしまいます。

このように、"HTTP"だけではセキュリティの面で問題があります。これを解決する仕組みが"TLS"です。"TLS"は"SSL/TLS"とか"SSL"とか呼ばれることがあるようですが、"SSL"は"TLS"より以前に使われていた技術で現在では使われていません。現在は"TLS"の1.2というバージョンと、2018年に公開された1.3というバージョンが使われています。

"TLS"の1.2と1.3はマイナーバージョンアップかと思いきや大分仕組みが異なるようです。単純に"TLS"という単語で調べているとある資料では1.2の仕様で、ある資料では1.3の仕様で"TLS"について説明されていてこれも沼にはまることになった要因の一つでは・・・と思っています。この記事では基本的に1.3の仕様に沿って書いていこうと思います。

("HTTPS"は"TLS"の仕組み上で"HTTP"のやり取りをすることです。"TLS"は"HTTP"に限定された技術ではありません。"TLS"の仕組み上でメールのやり取りを行うこともあります。)

"TLS"について

"TLS"は、①信頼できる通信相手と、②第三者が盗み見れない方法で、③送られてきたデータに改ざんがないことを担保の上、データをやり取りすることを目標としています。以降ではこの3つを"TLS"ではどのように解決しているのかを見ていこうと思います。

①通信相手が信頼できるか

クライアントがこれからデータのやり取りをするサーバが信頼できる相手なのかを、データをやり取りする前に検証する必要があります。これはサーバ証明書で解決することが出来ます。

サーバ証明書はサーバの身分証明書です。サーバの運営者の住所やWeb上のアドレスなどが記されています。サーバはクライアントにこのサーバ証明書を送り、クライアントはこのサーバ証明書を検証し、信頼できる相手なのか確認します。サーバ証明書は作成者によるデジタル署名が付与されていて、デジタル署名を通じて本当に作成者が作ったものなのかを確認することが出来ます。サーバ証明書は、ローカルなどの限られた範囲ではサーバ運営者自身が作成し、自己署名したものを使用するケースもあります。しかし、一般的には認証局(Certification Authority, CA)という第三者機関が発行したものを使用します。これにより認証局による審査を通過したサーバであることが確認できます。証明書を発行する認証局を認証する認証局もあり、そのように認証局を辿っていくと、認証局の最上位には自身で自身の証明書を発行できるルート認証局にたどり着きます。サーバからサーバ証明書が送られてくる際には、ルート認証局までの認証局の証明書も併せて送られてきて、その証明書を上に辿っていき、最終的にパソコンにあらかじめインストールされているルート証明書と同じ証明書にたどり着くことができればこれからデータのやり取りを行うサーバが信頼できる相手であることが確認できる、という仕組みになっています。

②第三者が読み取れない方法

データの送信者はデータを送る前に鍵を使って暗号化し、受信者は暗号化されたデータを鍵を使って復号して平文に戻し、内容を確認します。"TLS"では主にデータの暗号化には共通鍵暗号方式を使用します。これは暗号化と復号に同じ鍵を利用する暗号化方式です。主にAdvanced Encryption Standard (AES)という暗号アルゴリズムが使用されています。共通鍵暗号方式は他の暗号方式と比較すると処理が高速であるというメリットがある一方で、暗号化・復号に同じ鍵を使用するため、この鍵そのものを通信の前に何らかの方法で送信者と受信者の間で共有するステップが必要になります。そしてこのステップを第三者に見られ、鍵を解読されてしまうと以降のやり取りを盗み見られてしまうことになります。"TLS"では共通鍵をサーバ、クライアントで共有するステップを鍵交換と呼んでいますが、この鍵交換を安全に行うために、公開鍵暗号方式が使用されます。有名な公開鍵暗号方式のアルゴリズムが"RSA暗号"という、大きな数の素因数分解の難しさを利用したものです。最近はディフィー・ヘルマン鍵共有(Diffie–Hellman key exchange, DH), 楕円曲線ディフィー・ヘルマン鍵共有(Elliptic curve Diffie–Hellman key exchange, ECDH)という離散対数問題の難しさを利用したアルゴリズムが使われています。

鍵交換の仕組みは"TLS1.2"と"TLS1.3"で大分異なるようで、それが分からなかったため、理解が難しかったところです。なんとなくですが、"TLS1.2"のサーバ証明書を介した鍵交換の仕組みで説明している資料が多いように感じました。ここでは"TLS1.2"と"TLS1.3"の鍵交換をそれぞれ簡単に記しておこうと思います。

"TLS1.2"での鍵交換

RSA暗号が主に使用されているようです。鍵の作成者しか知らない秘密鍵、それに対応する公開鍵が作られます。秘密鍵で暗号化したデータは対応した公開鍵でしか復号出来ず、逆に公開鍵で暗号化したデータは対応した秘密鍵でしか復号することが出来ません。秘密鍵は鍵の作成者だけが保持し、漏洩しないように厳重に管理する必要があります。一方公開鍵は通信相手に対して公開します。 "TLS1.2"ではサーバは先ほど述べたサーバ証明書に公開鍵を付与してクライアントに送ります。そしてクライアントはサーバ証明書を検証した後、そこに付与された公開鍵を使用して以降の"共通鍵暗号"で使用する共通鍵(鍵そのものではなく、鍵の素)を暗号化してサーバに送ります。そしてサーバは秘密鍵を使って共通鍵を復号し、これでサーバとクライアントで同じ共通鍵を保有することが出来ます。

"TLS1.3"での鍵交換

RSA暗号による鍵交換には実は問題があります。それは秘密鍵が不変である、ということです。第三者が暗号化された通信を一旦全て記録しておいたとすると、いつか秘密鍵を盗んだり解読してしまうと蓄積された通信から鍵交換のやり取りを解読、そこから共通鍵を取得し全ての暗号化されたやり取りを解読してしまう恐れがあります。"TLS1.3"での鍵交換はディフィー・ヘルマン鍵共有(Diffie–Hellman key exchange, DH)もしくは 楕円曲線ディフィー・ヘルマン鍵共有(Elliptic curve Diffie–Hellman key exchange, ECDH)が使われます。DH鍵共有では通信の度にサーバとクライアントで秘密鍵と公開鍵を作成し、お互いの公開鍵をやり取りすることでそれぞれの環境で同じ共通鍵を生成することが出来るアルゴリズムです(実際にはDH鍵共有で生成された値を鍵導出関数に与えて得られた値が鍵として使用されるようです)。やり取りされる公開鍵だけでは秘密鍵および共通鍵を計算することが困難です(ここに離散対数問題を解くことの困難さが利用されているようです。)。通信の度に秘密鍵を作り変えるため、将来秘密鍵が漏洩した際のリスクを抑えることが出来ます。このように長期的に共通鍵が守られる鍵交換の性質を"perfect forward secrecy(PFS)と呼ぶそうです。

RSA暗号は鍵交換では利用されなくなりましたが、サーバ証明書のデジタル署名には利用されているようです。先ほど記したように、サーバ証明書にはそれを発行した認証局のデジタル署名が付与されています。デジタル署名はサーバ証明書の内容をハッシュ化という不可逆な一定の長さへの暗号化処理を加えたのち、認証局の秘密鍵で暗号化を施したものです。クライアントはサーバ証明書と合わせてそれを発行した認証局の証明書も受け取ります。そして認証局の証明書に付与されている公開鍵を使って、サーバ証明書に付与されている認証局によって暗号化されたデジタル署名を復号することが出来ます。秘密鍵で暗号化されたデータは対応する公開鍵でしか復号することが出来ず、また公開鍵に対応する秘密鍵は一つであることから正常に復号することが出来ればこのデジタル署名が確かに認証局によって作成されたものであることが確認出来ます。

③送られてきたデータに改ざんがないか

データが送信途中で第三者の手で改ざんされていない、つまり完全性を保つ仕組みが認証付き暗号( Authenticated Encryption with Associated Data, AEAD)です。AEADでは送りたいデータの平文と、それを共通鍵とともにハッシュ関数を通して計算したメッセージ認証コード(Message Authentication Code, MAC)を結合したデータを共通鍵で暗号化します。データを受信する側は、まず共通鍵で復号をし、平文の部分とMAC部分を取り出して平文と共通鍵を使って送信者と同じハッシュ関数でハッシュ化、MACを計算します。ハッシュ関数は同じハッシュ値は同じ元のデータからしか生成されない性質があるため、MACが一致していれば送られてきたデータと送信時のデータが一致していることを確認することが出来ます。

データのやり取りの前に"TLS" では、"鍵交換"、"共通鍵暗号方式"に使用するアルゴリズムのサーバとクライアント間の合意、"鍵交換"の公開鍵のやり取り、サーバ認証などの処理を取り行います。これらの一連の流れは、"TLS ハンドシェイク"と呼ばれています。

"TLS1.3"におけるハンドシェイク

最後にインターネット技術の標準化団体IFTF(Internet Engineering Task Force)によって公開されている"RFC(Request for Comments)8466"から、"TLS1.3"のハンドシェイクの流れを引用します。

   Figure 1 below shows the basic full TLS handshake:

       Client                                           Server

Key  ^ ClientHello
Exch | + key_share*
     | + signature_algorithms*
     | + psk_key_exchange_modes*
     v + pre_shared_key*       -------->
                                                  ServerHello  ^ Key
                                                 + key_share*  | Exch
                                            + pre_shared_key*  v
                                        {EncryptedExtensions}  ^  Server
                                        {CertificateRequest*}  v  Params
                                               {Certificate*}  ^
                                         {CertificateVerify*}  | Auth
                                                   {Finished}  v
                               <--------  [Application Data*]
     ^ {Certificate*}
Auth | {CertificateVerify*}
     v {Finished}              -------->
       [Application Data]      <------->  [Application Data]

              +  Indicates noteworthy extensions sent in the
                 previously noted message.

              *  Indicates optional or situation-dependent
                 messages/extensions that are not always sent.

              {} Indicates messages protected using keys
                 derived from a [sender]_handshake_traffic_secret.

              [] Indicates messages protected using keys
                 derived from [sender]_application_traffic_secret_N.

               Figure 1: Message Flow for Full TLS Handshake

引用:Internet Engineering Task Force (IETF) , RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3, AUGUST 2018, https://datatracker.ietf.org/doc/html/rfc8446

クライアントからの'ClientHello'で"鍵交換"および"共通鍵暗号方式"に使用するアルゴリズムの提案、公開鍵の情報などが送られ、サーバ側の'ServerHello'でアルゴリズムの確定や共通鍵の生成処理を経てこれより先のやり取りは暗号化されて取り行われます。クライアントはサーバ側の公開鍵を受けて共通鍵の生成を行い、サーバから送られてきたサーバ証明書の検証を実行し、最後に'Finished'の処理を経てハンドシェイクを終了し本番のデータのやり取りが開始されます。"TLS1.2"ではサーバ証明書を通じて鍵交換が行われるため、暗号化通信開始のタイミングが"TLS1.3"と異なります。("TLS1.3"の方が早い段階で暗号化通信に移行します。)

まとめ

今回はWeb上でセキュア通信を実現するための"TLS"という技術について調べてみたことをまとめてみました。調べたことに半分くらいしかまとめられなかったのですが、要点は残せたのではないかと思います・・・。"TLS"と一言で言っても色々な技術で構成されていて、非常に奥深いものだと感じました。引き続き周辺の技術について調べてみたいと思います。