エンジニアなら知っておきたい、絵で見てわかるセキュア通信の基本

# **はじめに**

昨今のセキュリティ意識の高まりから、どこかしこで聞くSSLやらHTTPS。
下記のようなものがセキュリティや通信に関係する言葉であるとは認識しているかと思いますが、このあたりの言葉をカジュアルに、ゆるっと理解している人も少なくないのではないでしょうか？

- SSL
- HTTPS
- サーバ証明書
- 自己署名証明書 (オレオレ証明書)

？？？「 **セキュリティ** を考えれば、最近だとやっぱり **HTTPS** がスタンダードみたいな？でも **オレオレ** だとよくないし？」

最初に言葉でも説明しますが、セキュリティは真面目にやると意外と観点が難しく、理解しづらい部分が多くあります。
実際に、こうした話を新人にしようとした場合に、言葉だけではどうにも話しづらいことを実感しました。
しかし、そんな状況でも **絵を交えるといくらかわかりやすいような気がした** ので絵を使いながらセキュア通信というものをまとめてみたいと思います。

# **セキュリティとは**

私たちは意外と簡単に **セキュリティ** という言葉を使ってしまいますが、おそらくはきちんと体系的にセキュリティという言葉を押さえている人はそのごく一部だと思います。
まずこの言葉、セキュリティを考えてみましょう。

恒例のWikipediaでセキュリティを調べてみます。

**[セキュリティ(曖昧さ回避) - Wikipedia](https://www.wikiwand.com/ja/%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3)**

まず大事なのは、セキュリティをWikipediaで調べると、 **曖昧さ回避** のページにたどり着くということです。
実際にリンクされている項目を見ても、

- **一般**
    - 保安
- **現実世界、物理的な領域**
    - 警備
    - ホームセキュリティ
    - 安全保障
- **コンピュータや仮想空間、IT**
    - コンピュータセキュリティ
    - 情報セキュリティ
    - ネットワークセキュリティ
- **金融**
    - 証券

など、色々な観点があります。
今回のターゲットは当然、「一般」や「現実世界、物理的な領域」で述べられているようなALSOK的な話ではありません。
(ちなみにALSOKは "**AL**ways **S**ecurity **OK**" の略です。知ったときは正直、衝撃を受けました。)

今回はターゲットのイメージとして、上記から「 **情報セキュリティ** 」を採用します。

## **情報セキュリティ** 

それでは、情報セキュリティについて掘り下げてみましょう。

**[情報セキュリティ - Wikipedia](https://www.wikiwand.com/ja/%E6%83%85%E5%A0%B1%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3)**

> 情報セキュリティ（じょうほうセキュリティ、英: information security）とは、情報の **機密性、完全性、可用性** を維持すること。

ここで大事なことは、情報セキュリティの特性を象徴する、 **機密性、完全性、可用性** という単語のそれぞれが意味するものです。
これらは、英語にしたときの頭文字を取り、 **情報セキュリティのCIA** と呼ばれたりします。

もう少し掘り下げて、それぞれの観点がセキュア通信とどのように関わるのかを考えてみたいと思います。

### **C: Confidentiality(機密性)**

![WS000076.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/04492d88-9c07-0460-5ffb-da7191a87339.jpeg)

情報セキュリティとして最もわかりやすいのが、 **Confidentiality(機密性)** です。
情報セキュリティが重要視するのは当然情報ですが、セキュリティにおいて「 **認可されたものだけが情報にアクセスできる** 」という点は最も基本的で、重要な内容です。
これはいわゆるシステム内部における権限管理などの話にもつながりますが、セキュア通信という観点からすると第三者から「 **盗聴されない** 」と読み替えることができます。

上の図ではまさに盗聴を表現していますが、盗聴の別の方式として下の図のような **なりすまし** というものも存在します。

![WS000100.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/bf518d63-0ec8-34fe-7951-8d1ebef82303.jpeg)

これはいわゆる **[中間者攻撃(man-in-the-middle attack)](https://www.wikiwand.com/ja/%E4%B8%AD%E9%96%93%E8%80%85%E6%94%BB%E6%92%83)** と呼ばれるタイプの攻撃です。

そんなバカなと思われるかもしれませんが、情報を送る際に「本当に相手が送ろうとしているその人か」という **認証** を行わない場合、上記のようなことがITの世界では容易に実現できてしまいます。

そのため、今回説明する技術の中では、

- 通信相手の認証
- 通信内容の暗号化

という点が機密性に関係します。

### **I: Integrity(完全性)**

![WS000075.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/4b029852-3af1-b302-613c-9d29db19acb6.jpeg)

次に、 **Integrity(完全性)** です。言われてみればなるほどというものですが、いわゆる「 **改竄されない** 」という性質です。
システムの内外において、情報はいたるところに存在します。システム内部においても情報が改竄されないというのは重要ですが、今回取り上げるセキュア通信では特に **システム外部** との通信をどう守るかというのがポイントです。
例えば、ネットショッピングで買い物をする場合、カスタマーは色々な情報をネットショップとやり取りします。
しかし、その情報が改竄を受けるようなことがあると、非常に困ったことが起きます。
例えば、下記のような情報が改竄されるケースを考えてみてください。

- お届け先住所
- 注文商品名
- 注文数

これらの改竄によって「ネットショップ側に損害を与える」ことや「カスタマー側に損害を与える」方法はいくらでも思いつきます。
そうした意味で、インターネットを経由して **ビジネスを行う際にはどうあってもセキュアな通信が必要** になってきます。

また、「 **改竄されない** 」という性質に広義には含まれますが、特に「 **破壊されない** 」という性質も重要です。
こちらの2点は、

- 改竄の検出

で説明します。

### **A: Availability(可用性)**

![WS000074.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/0b607f4d-64a6-6d0c-712d-15493072244d.jpeg)

最後に、 **Availability(可用性)** があります。
暗号化などの文脈で話していると「情報の可用性？」というのがピンときませんが、例えば図で表現したような「通信経路の破壊」が情報の可用性を損なう攻撃のひとつです。
実際に、一般的な感覚で言えば **セキュリティを強化する** と言えば「 **攻撃に備える** 」ことがほとんどを占めると思います。
大事な書類を金庫にしまったり、泥棒が家に入らないように警備員を配置したりすることです。

Availabilityでは、こうした観点から「 **情報を常に使える状態に保つ** 」ということを主に考えます。
昨今では、様々な手法によって「情報(システム)を使用不可能にする」攻撃を受けます。
**[DoS攻撃](https://www.wikiwand.com/ja/DoS%E6%94%BB%E6%92%83)** や **[マルウェア](https://www.wikiwand.com/ja/%E3%83%9E%E3%83%AB%E3%82%A6%E3%82%A7%E3%82%A2)** という言葉を聞いたことがあるかもしれませんが、インターネット上でビジネスを行う以上、これらの攻撃対象から根本的に外れることは難しく、いかにして守るかということが重要になります。
例えば、ファイアウォールやウイルスセキュリティソフトを導入したりすることがAvailabilityを高める最も基本的なアクションです。

今回のセキュア通信という文脈ではこの観点はあまり出てきませんが、もし **セキュリティ** というもの全体を考えるのであれば、決して逃すことのできない観点になります。

# **SSL/TLSとHTTPS**

![ssl-ecusson.png](https://qiita-image-store.s3.amazonaws.com/0/45253/39fb805b-b214-cdfc-3a44-63d5b84a068a.png)

こうしたセキュリティを保つことに関して重要な役割を果たしているのがSSL/TLSと、それによって実現されるHTTPSです。
とりあえず座学的に言葉で追っかけてみましょう。

## **SSL/TLSとは**

まずSSL/TLSについて調べてみます。

**[SSL/TLS - Wikipedia](https://www.wikiwand.com/ja/Transport_Layer_Security)**

> Transport Layer Security（トランスポート・レイヤー・セキュリティ、TLS）は、インターネットなどのコンピュータネットワークにおいてセキュリティを要求される通信を行うためのプロトコルである。
> 主な機能として、**通信相手の認証**、**通信内容の暗号化**、**改竄の検出**を提供する。

とのことでした。
プロトコルですので、いわゆる通信のお作法というやつですね。

上にも書いてありますが、SSL/TLSの機能を捉える場合に大事なのは

- **通信相手の認証**
- **通信内容の暗号化**
- **改竄の検出**

の3つです。

SSLとTLSは実際には別物なのですが、TLSの元になったプロトコルがSSLということで、通信の文脈ではセキュア通信技術としてSSL/TLSとまとめて呼ばれたりもします。
バージョンがいくつかありますが、「 **TLSはSSLより新しい** 」ことを頭に入れておけば、セキュリティの度合いについてはある程度感覚的に理解できるようになると思います。

|名前|登場年|状態|備考|
|:---:|:---:|:---:|:---|
|SSL 1.0|-|-|全体仕様上、致命的な脆弱性があったため公表なし|
|SSL 2.0|1994年|使用禁止(2011年)|初のセキュア通信仕様|
|SSL 3.0|1995年|使用禁止(2015年)|主な **[POODLE脆弱性](https://jp.globalsign.com/blog/2015/ssl_poodle_about.html)** の対象|
|TLS 1.0|1999年|運用中|基本的にはSSL 3.0の拡張|
|TLS 1.1|2006年|運用中|攻撃耐性の強化|
|TLS 1.2|2008年|運用中|認証付き暗号方式に対応|
|TLS 1.3|-|策定中|RSAのみを用いた鍵交換が禁止に|

TLS 1.3は現在策定中ですが、 **[前方秘匿性](https://www.wikiwand.com/ja/Forward_secrecy)** の問題から **RSAのみ** を用いた鍵委共有が禁止になる見込みです。(詳細は後述します)

## **HTTPSとは**

次に、HTTPSです。

**[HTTPS - Wikipedia](https://www.wikiwand.com/ja/HTTPS)**

> HTTPS（Hypertext Transfer Protocol Secure）は、HTTPによる通信を安全に（セキュアに）行うためのプロトコルおよびURIスキームである。
> 厳密に言えば、HTTPS自体はプロトコルではなく、SSL/TLSプロトコルによって提供される **セキュアな接続の上でHTTP通信を行うこと** をHTTPSと呼んでいる。

とのことです。
HTTPの説明を割愛するとすれば、「SSL/TLSでセキュアにHTTPをやる」というだけの説明で済んでしまいます。

最近では個人情報等の観点から全てのサイトをHTTPSにするような動きが見られますが、元々HTTPSが使われやすかったのが金融などの盗まれてはいけない情報を扱うWebサイトです。
そのため、ビジネスにインターネットへと進出するためには、SSL/TLS自体が提供する「認証」「暗号化」「改竄検出」というものが必要不可欠になっていました。

### **HTTPSは何の略か**

上ではWikipediaを引用して、HTTPSを "Hypertext Transfer Protocol Secure" と紹介しました。
ところが、こういうページもあります。

**[HTTPS@IT](http://www.atmarkit.co.jp/ait/articles/0401/01/news122.html)**

> Hyper Text Transfer Protocol over SSL

これはこれで非常に納得感のある名称です。
実際、 **S** を **over SSL** からだとしているサイトも多く、そちらで理解している人もまた多いかと思います。
こうした疑問について調べた記事がありました。

**[HTTPSの「S」は何の略か](http://blog.mwsoft.jp/article/39910926.html)**

結局のところ、国際機関である **[IANA](http://www.iana.org/)** が

「**HTTPS**は **H**ypertext **T**ransfer **P**rotocol **S**ecureの略だよ」

と **[示して](http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml)** いるので **S**ecure が正式な名称で間違いなさそうです。

# **絵で見てわかるセキュア通信の仕組み**

それでは、Yahoo! におけるショッピングを例に、絵を使って

- **通信相手の認証**
- **通信内容の暗号化**
- **改竄の検出**

がどのように実現されるのかをみてみたいと思います。
(特に Yahoo! を選んでいることに意図はありません。必要であればAmazonでも楽天でも自由に読み替えてください。)

## **通信相手の認証**

Yahoo! でショッピングすることを考えてみましょう。

![WS000062.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/ccd0700a-9c7a-9255-163f-e66bfcf38f4e.jpeg)

インターネットで Yahoo! に行くには、アドレスバーに Yahoo! のアドレスを打ち込むだけ。簡単です。

![WS000063.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/509fd862-267c-17c9-b724-a1ccc46fd4e1.jpeg)

そうすると、Yahoo! の売り場とおぼしき場所にたどり着くわけですが...

![WS000060.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/72c887f0-9e9b-1696-a2be-23df2a4a00a5.jpeg)

さて、ここは本当に Yahoo! なのでしょうか。
実際にあなたが足を運んだならともかくとして、ここはインターネットなので、そうした感覚もありません。
変なURLを踏まされているくらいなら人間でもある程度分かるのですが、 **[DNS偽装](https://www.wikiwand.com/ja/DNS%E5%81%BD%E8%A3%85)** などの手段でIPレベルに偽装されてはさすがに人間はお手上げです。
当然そんなところで、素直に聞こうものなら、...

![WS000077.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/96a9c52d-f047-1d2f-eb55-4bb59e156788.jpeg)

というようなマヌケなことになってしまうわけです。

そこで登場するのか **証明書** です。
○○証明書としては、

- SSL証明書
- TLS証明書
- サーバ証明書
- SSLサーバ証明書

などの単語を耳にすることがありますが、ほとんどの場合、同じものを指していると思って大丈夫です。
Googleの検索結果件数によると、この中では **SSL証明書** が最も市民権を得ているものと思われます。

HTTPSでアクセスを行うサイトには、証明書が装着されています。その状態は例えばChromeであれば、F12キーで呼び出せるコンソールからSecurityタブで確認することができます。

![WS000064.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/092b4f5a-d199-33d0-5c93-ece113cb0558.jpeg)

そして、 **[View certificate]** から証明書を確認すると、

![WS000066.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/456f311f-f1e1-e3fd-160e-4f572520c0d9.jpeg) ![WS000067.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/8d8a05a4-ec0c-263b-619a-d00556536dc7.jpeg)

のように、DigiCert BaltimoreとCybertrust Japanを上位に持つ **正規の証明書** が使われていることがわかります。
あとで公開鍵暗号に合わせて説明しますが、証明書には **有効期限がある** ことも念のため覚えておいてください。

![WS000068.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/9091cfd9-b7d5-a8a6-c94c-61a0648f3200.jpeg)

こうしてアクセスしようとしたサイト、 Yahoo! が間違いなく Yahoo! であることが **証明** されました。
日常生活になぞらえれば、セキュアな郵便物を受け取る際に、身分証明書を提示することと似ています。あれも結局は **第三者の発行した書面** によって、受け取り主を認証している構図になっています。
この仕組みを実現する具体的な要素は、実際に正規の認証局から **証明書を発行** する流れを一度体験するとよくわかります。

### **自己署名証明書**

補足ですが、証明書は作成の過程で認証局による電子署名を行います。
このとき、自分自身で署名を行うものを特に **自己署名証明書** といいます。

今回説明している **通信相手の認証** という観点だと、自己署名証明書ではその効果を発揮することができません。
通信相手の認証で大事なのは、「信頼できる第三者が通信相手を保証してくれる」ことです。

あるべき証明書としては今回の例でいくと、

- **ドメイン名**
    - order.shopping.yahoo.co.jp
- **提供者**
    - Yahoo! JAPAN
- **保証人**
    - DigiCert Baltimore
    - Cybertrust Japan

のような状態となり、利用者は安心して信じることができます。
しかし、正規の認証局のような第三者が関係しない自己署名証明書(オレオレ証明書)では

- **ドメイン名**
    - oreore.com
- **提供者**
    - 俺
- **保証人**
    - 俺

のように、自分で自分を保証するというような、 **通信相手の認証** という観点では意味不明な状態になるわけです。
もちろん、自己署名証明書を使った場合でも、このあと説明する通信内容の暗号化自体は可能ですので、暗号化だけが必要な場合は自己署名証明書を使うことに何の問題もありません。

(追記)

コメントにて「自己署名証明書による暗号化は **中間者攻撃に対して脆弱** で、暗号化の恩恵がない」とのご指摘を @tetsukay さんからいただきました。
これはまさしくその通りで、暗号化は盗聴されるケースにおいてはその効力を発揮するものの、最終的に復号できるようになっているため、なりすましの一種である中間者攻撃に対しては何の効果もありません。

そのため、中間者攻撃を想定しつつも自己署名証明書で暗号通信を行いたい場合、自己署名証明書による通信を原則禁じつつ、信頼済みの自己署名証明書のみ利用を許可して通信を行うようにクライアントを設定するなどの対策が必要になります。

![WS000101.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/c43a9262-6885-63e5-2476-73c00064958d.jpeg)

自己署名証明書を用いた通信を行おうとする場合、上記のような画面が各ブラウザで出てくると思いますが、これはまさに中間者攻撃などのリスクを警告している画面です。
社内サーバなど、意図した通信先の自己署名証明書を予め信頼するように設定できていれば、実際に中間者攻撃を受けようとしている場合にはこの **見慣れない画面が出てくる** ことになり、攻撃に気付くことができるかもしれません。

### **信頼できる第三者**

あれ、と気付いた方もいるかもしれませんが、「信頼できる第三者が通信相手を保証してくれる」方式の場合、その **第三者の信頼性** をどのように考えればいいのでしょうか。
今回の例では、「DigiCert Baltimore」と「Cybertrust Japan」によってYahoo!の認証が行われたことを見ましたが、「 **証明のパス** 」を見るとわかるように、Yahoo!からCybertrust Japan、Cybertrust JapanからDigiCert Baltimoreという3階層(※)で認証されている格好です。
このとき、Cybertrust Japanのような第二階層に位置する証明書を中間(CA)証明書、DigiCert Baltimoreのような第一階層に位置する証明書をルート証明書と言います。

※ この3階層に **クロスルート証明書** が加わり、4階層となることがあります

それでは、このように **上位者のいない** DigiCert Baltimoreの認証はどのように行われているのでしょうか？
実は、こうした認証の頂点に存在する認証局( **ルート認証局** )に関する認証は、予めブラウザなどにその信頼が **組み込まれる** ことで実現されています。
実際にChromeで [設定] -> [詳細設定] -> [HTTPS/SSL] -> [証明書の管理] を見てみると、

![WS000126.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/0f6eebc9-05a2-8f2d-1cba-eabf47fda2c7.jpeg)

のように、先ほど認証の最上位に存在したDigiCert Baltimoreの名前(フレンドリ名)が確認できます。
これらはChromeやIE, Firefoxといった著名なブラウザから、非常に高い信頼を持つものとして扱われています。
実はルート認証局自身を認証するためのルート証明書は自己署名証明書ですが、このようにブラウザ自身に組み込まれる形で事前に信頼されており、 **ルート認証局自体の認証は必要ありません** 。

その信頼がどこからくるのか、という点に関しては「どうして国が信頼できるのか」「どうして銀行が信頼できるのか」という問いに同じく、社会全体で信頼が認知され、またそれが継続的に維持されるような構造になっています。
認証局として社会の信用を得ていたとしても、自分自身のセキュリティが甘かったりする場合は、すぐにその信用を失い、認証局としての機能を果たせなくなってしまいます。
実際に、2011年にオランダの認証局であるデジノター社が不正アクセスを受け、不正な証明書を大量に発行していた **[事件](https://www.wikiwand.com/ja/2011%E5%B9%B4%E3%83%87%E3%82%B8%E3%83%8E%E3%82%BF%E3%83%BC%E4%BA%8B%E4%BB%B6)** がありましたが、 **あっという間に倒産する** 結果となりました。

このように、認証局は自身の信用力を維持するため、それこそ情報セキュリティに止まらない **本質的なセキュリティ** を高めることが求められます。

## **通信内容の暗号化**

さて、次は支払いです。

![WS000069.JPG](https://qiita-image-store.s3.amazonaws.com/0/45253/cd1ae5fc-0f47-ae24-2a8e-d99c46b4e383.jpeg)

便利ですね。クレジットカード。番号を送るだけでお買い物ができてしまいます。
それ故に、この番号を盗まれたら大変ですので、 **通信内容の暗号化** をして第三者からはクレジットカード情報がわからないようにしなければなりません。

### **暗号通信の難しさ**

HTTPSによる暗号通信が一般化している世の中においては、暗号通信自体に何の真新しさもないかもしれません。
しかし、元来暗号通信を行うことは原理的な難しさを抱えており、歴史的にも長い間悩まれ続けてきました。

通信というものは歴史的には日常生活よりも、特に軍事面での重要性が高く、安全に配送することはもちろんのこと、万が一文書が **奪取/盗聴されても解読されない** ことが重要なポイントです。

このあたりの話はシーザー暗号に始まり、エニグマ暗号に至るまでの非デジタル暗号からRSAをはじめとする現代のデジタル暗号まで **[暗号解読―ロゼッタストーンから量子暗号まで](https://www.amazon.co.jp/dp/4105393022)** という本にみっちり書いてあり、個人的に非常にオススメな一冊です。

### **鍵配送問題**

さて、暗号通信の難しさとして、歴史的に有名なのが **鍵配送問題** です。

奪取や盗聴の可能性を踏まえ、相手との通信を安全に行いたい場合、送信者は

- メッセージを守る(物理的な鍵)
- メッセージを暗号化する(論理的な鍵)

ような方法で第三者からの奪取や盗聴によるメッセージの流出を防ぎます。

![WS000085.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/3affaaeb-b9ca-a9f8-6340-af80aaf58675.jpeg)

しかし、受信者はメッセージを読むためには「鍵の受け取り(物理鍵)」「復号方法の取得(論理鍵)」が必要になりますが、いずれの場合にもさらにその鍵を安全に受け渡さないと何の意味もなさないことがわかります。

![WS000086.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/00a61df2-8244-6a48-4a7f-5b330f7d3d76.jpeg)

もちろん第三者を介すことなく直接鍵をやり取りしてもいいのですが、それでは通信でなくなってしまい、本末転倒です。
ということを念頭に置けば、

- メッセージに鍵をかける
    - メッセージを守る鍵を安全に受け渡す必要がある
- 鍵に鍵をかける
    - 鍵を守る鍵を安全に受け渡す必要がある
- ...

のように、まさにいたちごっこの様相を呈してきます。
このように、メッセージを守るための鍵をそもそもどのように配送するか、というのが鍵配送問題です。

### **公開鍵暗号**

こうした鍵配送の問題は、普通に考えていると **原理的に解決できないのではないか** と思えるほどです。
しかし、そうした多くの研究者が頭を悩ませた話に非常にシンプルな解決策が示されました。

まず下図のように、送信者と受信者がそれぞれの鍵を準備します。

![WS000089.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/cf993ee2-b93e-a16d-1340-1b9652c202ee.jpeg)

これらの鍵はお互いその特性などを知らせ合う必要はなく、それぞれで管理しておけば大丈夫です。
そして、下記の手順でメッセージをやりとりします。

1. 送信者は送信者の鍵でメッセージを保護、送信する
2. 受信者は受信者の鍵でメッセージをさらに保護し、送信者に返送する
3. 送信者は自分の鍵でかけられた保護を解除し、受信者に再送信する
4. 受信者は自分の鍵でかけられた保護を解除し、メッセージを受け取る

![WS000090.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/4485fbd5-cdd9-59c3-ea35-9f293a60ca78.jpeg)

どうでしょうか。
このようにすれば、鍵の配送に悩まされず、かつ安全にメッセージの配信ができているのではないでしょうか。

さらに、インターネットのように、 **鍵の生成、コピーや受け渡し自体が容易な場合** 、さらにこの手順を簡略化することができます。

![WS000091.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/d1f94ca5-481c-99c3-2cc1-7bac8d1eabd1.jpeg)

1. 送信者は、受信者から受信者の鍵を取得する
2. 送信者は受信者の鍵でメッセージを保護、送信する
3. 受信者は自分の鍵でかけられた保護を解除し、メッセージを受け取る

さて、このとき送信者から見ると受信者の鍵は送信者に対して **公開** されています。
しかし、公開されているのはあくまで保護の仕組み(暗号化)の部分だけで、保護を解除する仕組み(復号)の部分は公開されていないことがポイントです。
このように、「保護の仕組みは公開してはいけないもの」という発想から、「保護を "**解除する**" 仕組みは公開してはいけないもの」という発想に転換させることで、鍵配送問題を見事にクリアしています。
これがいわゆる **公開鍵暗号** です。

### **公開鍵暗号の弱点**

さて、このように鍵配送問題を華麗に解決した公開鍵暗号ですが、弱点がありました。

- 「保護の仕組み(暗号化)」を公開しながら、それが「保護を解除する仕組み(復号)」に結びつかない方法があるのか

という点です。
よく「壊せるけど戻せない」と言ったりはしますが、「後で戻せるようにこの手順で壊してね」と言われると、結局それが戻し方をほどんど表すものになってしまい、条件を満たしません。
いわゆる **処理の一方向性** を実現する仕組みがうまく見つからなかったのです。

しかし、実際にはこの点も **[RSA暗号](https://www.wikiwand.com/ja/RSA%E6%9A%97%E5%8F%B7)** の考案によって既にクリアされており、これには **素因数分解** の仕組みが利用されています。

素因数分解とは、ある素数でない数(合成数)を素数の積で表すというアレですが、実は

**15 = 3 * 5**

のような「合成数から素数を得る」計算は、その逆の「素数から合成数を得る」計算に比べて **実はそんなに簡単じゃない** ことを利用しています。
端的に言えば、「素因数分解が **現実的な時間では** 到底行うことができない」ということを暗号強度の根拠にしています。

このあたりは **[リーマン予想](https://www.wikiwand.com/ja/%E3%83%AA%E3%83%BC%E3%83%9E%E3%83%B3%E4%BA%88%E6%83%B3)** をはじめとして、 **素数の規則性が未解明** であり効率的な計算ができないこととか、 **[P≠NP問題](https://www.wikiwand.com/ja/P%E2%89%A0NP%E4%BA%88%E6%83%B3)** で考察されるような **[多項式時間](https://www.wikiwand.com/ja/%E5%A4%9A%E9%A0%85%E5%BC%8F%E6%99%82%E9%96%93)** に関係します。興味のある人はぜひ調べてみてください。

この公開鍵暗号が世に出るまで「暗号理論は言語学者の領域」であるとされ、また素数を扱うような代数学が世の中へ直接的に貢献した例はなかったのですが、これにより暗号の世界で数学が一躍脚光を浴びることになりました。
実際にこの公開鍵暗号のアイデアを初めて(※)実装した **[RSA暗号](https://www.wikiwand.com/ja/RSA%E6%9A%97%E5%8F%B7)** の発案者は数学にも明るく、言語学者が頭を悩ませた **処理の一方向性** の実装を難なく閃いてしまったようです。

※ 実際には1960年代から1970年代のイギリスで初めて考案、実装されていたとされていますが、 **軍事機密** として長らくこの事実が **[隠されて](https://www.wikiwand.com/ja/RSA%E6%9A%97%E5%8F%B7#/.E6.AD.B4.E5.8F.B2)** いました

もう1点、もう一歩先に進んだ先にある弱点としては

- 公開鍵暗号は共通鍵暗号に比べて暗号化/復号の総計算コストが高い

ことが挙げられます。
そのため、実際にHTTPSで情報をやりとりする場合には、

1. SSL認証を行いつつ、送信者が受信者の公開鍵を取得する
2. 送信者はその場限りの共通鍵を生成し、公開鍵で暗号化して受信者に送信する
3. 受信者は復号を行い、共通鍵を取得する

![WS000093.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/04cb3c24-b5e7-6054-cf48-826def725e27.jpeg)

のようにして **まずは公開鍵暗号を用いて受信者と送信者で共通鍵を安全に共有** します。
そして以降の暗号通信は高速な共通鍵暗号を用いて行われていきます。

![WS000095.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/821892ee-1e62-622d-c60f-eb55596b9889.jpeg)

このように **公開鍵暗号 + 共通鍵暗号** というハイブリッド方式を取ることで、安全性と高速性の両立が図られています。

#### **他の公開鍵暗号**

先ほどは具体的な公開鍵暗号として **RSA暗号** を紹介しました。
素因数分解の難しさを根拠とし、巨大素数の積で作られる公開鍵から暗号を解読されないことがポイントでした。

しかし、RSA暗号では **[前方秘匿性](https://www.wikiwand.com/ja/Forward_secrecy)** の問題が存在します。
先ほど「公開鍵から暗号を解読されない」と言いましたが、これには「現実的な時間(多項式時間)で」という注釈がつくのでした。
ただし、それもアルゴリズム的に調べる場合に現実的でないという話であり、運任せに割り算をして **運よく素因数分解できてしまう** 可能性は否定できません。こうして公開鍵に対する秘密鍵が知られた場合、何が起こるでしょうか。

RSA暗号で暗号通信をする場合、認証とセットになるため、 **公開鍵は常に同じもの** が使われます。
このとき、この公開鍵に対する秘密鍵が運悪く知られていると、当然ながらいとも簡単に **後続の通信も解読される** ようになります。
それどころか、攻撃者が公開鍵の解読前からひたすらメッセージを盗聴/蓄積し続けていた場合には、それらもすべて解読されることになってしまいます。
このように、どこかで暗号が解読された場合に、過去や未来に被害が波及することを **前方秘匿性がない** と表現します。
このような理由からTLS 1.3においては **鍵交換方式として** RSAの利用が禁止される方針で現在検討が進んでいます。

一方、RSAに代わる別の鍵交換方式としては、 **[Diffie-Hellman鍵交換](https://www.wikiwand.com/ja/%E3%83%87%E3%82%A3%E3%83%95%E3%82%A3%E3%83%BC%E3%83%BB%E3%83%98%E3%83%AB%E3%83%9E%E3%83%B3%E9%8D%B5%E5%85%B1%E6%9C%89)** が推奨されるようになります。
RSAが素因数分解の難しさを安全性の根拠としていたように、Diffie-Hellman鍵交換では **離散対数問題** の難しさを安全性の根拠に置いています。
(ただこちらも結局は「計算が多項式時間で終わらない」というところに行きつきます)

Diffie-Hellman鍵交換では、概念的にはお互いが乱数を秘密に生成し、その乱数で計算した値を互いに送りあうことで鍵の交換を実現します。
これだけの説明だとさっぱりですが、剰余を使っていくところなど、原理的にはRSAに似ているものがあります。
RSAに比較した特徴は公開鍵を毎回変更できる点です。通信ごとに公開鍵を新しく生成し、一時的な公開鍵とする方式を特に **DHE(Diffie-Hellman Ephemeral)** と呼び、DHEにおいては前方秘匿性の問題が解決されます。

なお、Diffie-Hellman鍵交換はあくまで鍵交換の仕組みであるため、中間者攻撃に対する耐性は全くありません。
そのため、別途RSAなどによる認証の仕組みが必須となりますが、そういった意味でTLSにおける鍵交換方式は

- **RSA**
    - RSAによる鍵交換/認証 (TLS 1.3で禁止)
- **DH-RSA**
    - DHによる鍵交換、RSAによる認証 (TLS 1.3で禁止)
- **DHE-RSA**
    - DHEによる鍵交換、RSAによる認証

などと表現されます。

#### **物理世界での公開鍵暗号**

元々南京錠に例えて説明した公開鍵暗号ですが、物理世界ではこうした仕組みは上手くいきません。
なぜなら、このパターンを物理世界で実現するためには

- 任意の送信者からメッセージを受け取るためには無数の鍵が必要になる
- 任意の送信者は安全に鍵を受け取るべく、直接受け取るしかない

![WS000092.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/ae53d15c-fcb8-a19f-5dab-c89bb2630c8f.jpeg)

ためです。特に、2点目で安全に鍵を受け取ろうとする場合には相手の認証を行う方法がない以上、直接行って受け取るほかはなく、であればそのままメッセージ渡せばいいよね的な考えになってしまいます。
また、そもそも鍵をいつでも受け取れるようにしておくと、その鍵を眺めて解除方法を準備する輩が出てくるかもしれません。
そうすると、理想的には「送信者ごとに」「受け渡しごとに」鍵を変える必要があります。しかし、そうした対応は国などの大きな組織ではなんとかなるかもしれませんが、今日のインターネットのように、暗号通信を必要とする全ての人にその準備することは極めて困難だと考えられます。

### **鍵の長さ**

公開鍵や証明書を作る際に、「2048bitの鍵を作る」などという表現が出てきます。

```
$ openssl genrsa 2048 > server.key
```

こんな具合です。この2048という数字は「2048bitの長さをもつ合成数を用いて公開鍵を作る」という意味を持ちます。
ここでいう長さは2進数における桁数ですので、10進数に直すと "**(ビット数) × 0.3010**" で求めることができます。
例えば、 **1024bitで約300桁** 、 **2048bitで約600桁** です。

既に終了しましたが、面白い取り組みとして、「 **RSA暗号解読コンテスト** 」というものが以前RSAセキュリティ社の主催で開催されていました。
これは問題として与えられた鍵の素因数分解にチャレンジし、計算できたら賞金を与えるというものです。
賞金は鍵長や解読時間によって決まり、当時は最高で20万ドルという賞金がかけられていたようです。
2007年に終了した当時では663bitの鍵までが解読されていましたが、その後も賞金に関係なく解読は続けられ、2009年に768bitの鍵が解読されるに至りました。
少し前までは一般的に1024bitの鍵で十分な強度を持っていると見られていたのですが、こうした背景から **2048bitが最低限必要** だという認識に変わっています。

改めて述べると、素因数分解自体は全く難しい計算ではありません。
非常に単純な話をすれば、1からその数までの数字全てで割り算をしてみればよく、いつかは必ず終わる計算です。
難しいと言われているのは、「 **現実的な時間(多項式時間)で** 計算すること」です。
特に、難しさが認められているのはいわゆる現在のコンピュータに限った話で、現在着々と研究が進んでいる **[量子コンピュータ](https://www.wikiwand.com/ja/%E9%87%8F%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)** が実用的になれば立ちどころに解読されてしまうといわれています。
そのため、証明書には有効期限を設定するようになっており、攻撃者がひたすら計算を続けていつか解読してしまうリスクを回避するようになっています。
オレオレ証明書などでは「取り換えが面倒だから有効期限を長くしよう」という方もいますが、この使い方では認証のみならず暗号化に対しても **意味をなさなくなり得る** ことに注意が必要です。

## **改竄の検出**

さて、安全に注文を送信することができたので、あとは　Yahoo!  側で注文処理を進めるだけです。
しかし、最後に問題となるのは、「 **Yahoo!から見て** 、本当にこの注文が正しいと確認できるか」という点です。

確かに、注文者の視点ではSSL証明書を用いて Yahoo! に間違いないことを確認し、暗号化を行って安全に注文情報を Yahoo! に送信しました。
しかし、ここまできてもなお、 Yahoo! から見た場合は **本当に注文が正しいかどうか** を確認するすべはありません。
暗号化によって確かに盗聴を防ぐことはできているのですが、実は **改竄** を防げているわけではありません。

![WS000096.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/7e33ea49-03b1-87ff-f460-319e06885cda.jpeg)

データというものはつまるところ0と1の羅列でしかないわけなので、どこかの0を1に変更してやるだけで意味ががらりと変わってしまうかもしれません。
もちろん、ランダムに改竄を加えた場合、ほとんどは訳のわからないデータになってしまうため、「データが壊れた」という状態になります。
また、明らかにあり得ないような内容になっていたとしても、業務ロジック的に除外することはできるでしょう。
しかし、運よく(?)、例えば注文数量が1個から10個になるとか、 **意味のあるデータのままに改竄ができた** としたらどうでしょうか。
そうすると、 Yahoo! 側からではどう頑張っても改竄されているという事実に気づくことはできません。

![WS000097.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/df9f660c-5e6d-faae-cd41-d0dfeeaf826a.jpeg)

そこで、このような改竄の検出を行うための仕組み、 **メッセージダイジェスト** が必要になります。

### **メッセージダイジェスト**

メッセージダイジェストとは、いわゆる **要約** のことです。
要約と言ってしまうとなんだか違うように感じますが、コンピュータにおける要約とは、いわゆるデータのチェックサム計算とかハッシュ化のような「データを元にした計算」を指します。
例えば、非常にシンプルなメッセージダイジェストの例としては「 **文字数をカウントする** 」ことが挙げられます。

![WS000098.jpg](https://qiita-image-store.s3.amazonaws.com/0/45253/63da1957-e820-4cbb-8e50-677305c1a620.jpeg)

このように、データの内容に紐づくメッセージダイジェストを一緒に送り、受け取ったデータを元に再度メッセージダイジェストを計算、照合することで改竄の検出を可能にしています。
もちろん、この方法では文字数が変わらなかった場合に改竄を検出できませんし、メッセージダイジェストの仕組み自体も簡単なのでメッセージダイジェストの内容と一緒にデータを改竄してしまうことも容易いでしょう。
そのため、メッセージダイジェストには

- 元データが少しでも異なると、メッセージダイジェストの **内容が変わる**
- 元データを使わずに、メッセージダイジェストとデータの **整合性を保つことが非常に難しい**

性質が求められ、具体的には **ハッシュ化** やそれに類する様々な方法が取られます。

実際には、HTTPSではその他いくつかの攻撃を検出するため、データだけでなくデータに添えられたいくつかの情報と合わせてハッシュ値を生成した **ハッシュ型メッセージ認証コード** (HMAC, Hash-based Message Authentication Code)をデータに添えて送信しています。
当然HMAC自体は何の意味も持たないのですが、データを受け取った側は同じ方式で再度HMACを計算し、データに添えられたメッセージ認証コードと比較することで、データが改竄されていないかを正確にチェックすることができます。

### **暗号化とハッシュ化**

さて、 **通信内容の暗号化** では **暗号化** を、 **改竄の検出** では **ハッシュ化** を主な技術要素として大まかに確認しました。
使われる局面が似通っているためか、暗号化とハッシュ化を同じように捉えている方が見受けられます。

？？？「データ保護の観点からすると、 **ハッシュ化して** 暗号化された状態で **データを格納すべき** だよね」

このような認識は明らかな間違いで、

- 暗号化
    - 暗号化されたデータの復元が難しいものの、鍵によって **復元できる** もの
    - 暗号化された後のデータ量は、暗号化方式と元データ量に依存する
- ハッシュ化
    - ハッシュ化されたデータの **復元ができない** もの
    - ハッシュ化された後のデータ量は、ハッシュ化方式に依存する

という違いを押さえていません。
見ての通り、暗号化されたデータは復号できることとセットです。仮に復号できないとするのであれば、それは単なる **データ破壊** です。
また、処理後のデータ量にも違いが表れます。
暗号化では復号して利用することを目的としていますから、そのデータ量は元データの量に依存します。この点では可逆圧縮と似た側面を持ちます。
しかし、ハッシュ化では今回取り上げた元データとの検証であるとか、分散データベースにおけるデータ配置先の決定など、データ本体とは別の **おまけ** として用いられます。
そのため、他データとの違いが表れるに十分な長さ(データ量)であればよく、どのようなデータをハッシュ化したとしても、同じ方式であればハッシュ化後のデータ量は変わりません。
(それ故に、一定の確率でハッシュの **[衝突](https://www.wikiwand.com/ja/%E8%A1%9D%E7%AA%81_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%A6))** が起こることは認識しておかなければなりません)

# **まとめ**

それでは、改めてセキュア通信に必要な内容と、それに対応する技術要素を振り返ってみましょう。

- **通信相手の認証**
    - SSL証明書
- **通信内容の暗号化**
    - 公開鍵暗号
    - 共通鍵暗号
- **改竄の検出**
    - メッセージダイジェスト
    - メッセージ認証コード

というようになり、SSL/TLSは上記を柱とするセキュアな通信のお作法を規定したものです。
一方で、HTTPSはそのSSL/TLSに則って行われるセキュアなHTTP通信のお作法であり、理解する分には「HTTPの仕様」「SSL/TLSの仕様」に分けるのがよいでしょう。
結局、下記のような関係性になります。

- **HTTPS**
    - **HTTP**
        - RFC2616
        - RFC7230-7235
    - **SSL/TLS**
        - 通信相手の認証
        - 通信内容の暗号化
        - 改竄の検出

今回はHTTPSによるショッピングを題材に、セキュア通信についてまとめましたが、他にもセキュア通信の仕組みはたくさんあります。

- **SSH** (Secure SHell)
- **FTPS** (File Transfer Protocol over SSL/TLS)
- **SCP** (Secure Copy Protocol)

特に、**SSHで配置する鍵** や **FTPSとSFTPの違い** などはぼんやり理解しがちなのですが、基本的な今回説明した内容と似たような切り口でセキュア通信を考えているため、HTTPSについてしっかり理解しておくことは、セキュア通信全般への理解を深めることに繋がります。

また、セキュア通信に限らずセキュリティというものでは「 **脅威** 」と「 **対策** 」の組を正しく理解することが重要です。
セキュリティ対策を眺めていると、似たような脅威にばかり気を配られており、「あれ？そもそもこっちの脅威は？」と思うこともしばしばあります。
例えば、今回色々な絵を使っていますが、基本的には「 **外部** 」からの攻撃というものをモチーフにしています。そのため、広くセキュリティという観点を掘り下げる場合には「 **内部** 」の問題にも目を向ける必要があるでしょう。
また、脅威と対策といった観点では、対策の原理やその効果を正しく理解できていないために、 **対策できていない脅威に対しても対策していると誤認する** ケースも見受けられます。
特に自己署名証明書によるHTTPSを使うことで「暗号化はできる」「認証はできない」ということなどは正確に押さえておく必要があるでしょう。

このように、セキュリティについて考慮するときには、漠然としたイメージではなく、まずは「脅威」に具体的なイメージを持つことが大切です。
そして、その上でどの脅威に「対策」する必要があるのかを **1つ1つ丁寧に** 対策を考えていくことがセキュリティへの第一歩となるでしょう。