Future Tech Blog
フューチャー技術ブログ

春の入門祭り 🌸 #14 暗号通信入門


はじめに

こんにちは。TIG メディアチームの竹中です。

春の入門祭り🌸 #14 暗号通信入門です。

新型コロナ肺炎の感染拡大に伴い、多くの方がインターネット通販をいつも以上に利用したのでは無いでしょうか?その際、クレジットカード番号など漏洩したら困る個人情報が多く含まれますので、どのような通信が行われているか分からないと気が気ではありませんね。もちろんやり取りには暗号通信が利用されています。

私自身、「仕組みは知っているけど検証はしたことがなかったな」と思い、HTTP通信とHTTPS通信の通信内容を確認しつつ、暗号通信入門記事としていきます。本記事では、入門記事として簡単な解説と検証内容を記載し、詳細な仕組みなど後記する参考文献などで調べて頂くことを想定しています。

では、早速見ていきましょう。

HTTP通信?HTTPS通信?

インターネット通販などでブラウザを使う際、ブラウザとWebサーバーで主に行われている通信です。
通信内容を暗号化せずに通信(=HTTP通信)すると無関係な人も通信内容を読み取れるため、通信内容を暗号化して、通信先にのみ通信内容を正しく読み取れるように(=HTTPS通信)しようというものです。

暗号化していないHTTP通信

HTTP通信ではどのように通信内容が見えるのでしょうか。早速検証してみましょう。

HTTP通信をするサーバを用意

Node.jsをインストールして、以下のファイルを用意します。

server-http.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var http = require('http')
var os = require('os')

var html = require('fs').readFileSync('form.html');
const port = 8080;

// サーバー起動
http.createServer(function (req, res) {
if(req.method === 'GET') {
// 初期表示ではformを返す
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(html);
} else if(req.method === 'POST') {
// formからの入力値を解釈して返却
var data = '';
res.writeHead(200, {'Content-Type': 'text/html'})
req.on('data', function(chunk) {data += chunk})
.on('end', function() {
res.end(`form: ${data} `)
})
}
}).listen(port)

console.log(`Server is running : http://localhost:${port}/`);
from.html
1
2
3
4
5
<form method="POST">
Name:<input type="text" name="name"><br>
Credit No:<input type="text" name="creditNo"><br>
<input type="submit">
</form>

HTTP通信を行うサーバを起動します。
node .\server-http.js start

ブラウザでhttp://localhost:8080/を開くと下記のようなフォームが表示されます。

通信内容を確認

今回はWiresharkでパケット取得してみます。

Wiresharkはネットワーク・アナライザ・ソフトウェアで、指定したネットワークインターフェイス上を通過するネットワークパケットをキャプチャすることができます。要するに、ブラウザからWebサーバへ送られるネットワーク通信の内容を監視することができます。

こちらを使って、ブラウザから送られるHTTP通信・HTTP通信の内容を見ていきます。

インストールや使い方については『Wiresharkの使い方 - ネットワーク入門サイト』を参考にしてください。

Wiresharkでキャプチャ取得を開始し、「http」でフィルターします。ブラウザからhttp://localhost:8000/のフォームを開き、『送信』(HTTPリクエスト)します。

サーバ側では問題なくリクエスト情報を取得できていますね。

Wiresharkで送信内容見てみると、NameもcreditNoもそのまま送られています。

HTTP通信で情報を送ってしまった場合、 通信内容から容易に情報が読み取れてしまう 、ということですね。

暗号化したHTTPS通信

HTTP通信では、「通信内容から容易に情報が読み取れてしまう」ことが分かりました。

次にHTTPS通信の内容を見て、HTTPS通信では本当に情報が読み取れないのかを確認していきます。

しかし、暗号通信を行うためには、暗号化するための情報や複合化するための情報が分からないと通信のやり取りができません。そのためHTTPS通信の際には、実際に送信したい内容を送る前に暗号通信準備を行っています。暗号通信準備については、『SSL/TLSネゴシエーション - ネットワークエンジニアとして』を参照ください。

暗号化のための証明書、秘密鍵を用意

HTTPS通信を行う際のSSL/TLSネゴシエーションに必須となる、サーバの証明書・秘密鍵を用意します。

執筆時はWindows、かつ認証Proxy環境の環境で検証を行っています。今回はchocolateyをインストール後、mkcertのインストールして、mkcertでサーバーの証明書・秘密鍵を作成を行います。mkcertはローカルで信頼された証明書を発行するためのソフトウェア、chocolateyはWindows用のパッケージ管理ソフトウェアで、今回はmkcertをインストールするために使用します。

まずは下記等を参考として、chocolateyのインストールをしてください。

次にmkcertのインストールして、サーバの証明書・秘密鍵を作成を行います。コマンドプロンプトを管理者権限で起動し、下記を実行してください。

1
2
3
4
5
6
7
8
9
# mkcertをインストール
$cinst -y mkcert

# ローカル環境に認証局を作成
$mkcert -install

# localhostの証明書、秘密鍵を作成
# ※カレントディレクトリに「localhost+2.pem」「localhost+2-key.pem」が生成される
$mkcert localhost 127.0.0.1 ::1

HTTPS通信をするサーバを用意

以下のファイルを用意します。

server-http.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const https = require('https');
const fs = require('fs');

var html = fs.readFileSync('form.html');
const port = 8443;
const options = {
key: fs.readFileSync('localhost+2-key.pem'),
cert: fs.readFileSync('localhost+2.pem')
};

// サーバー起動
https.createServer(options, (req, res) => {
if(req.method === 'GET') {
// 初期表示ではformを返す
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(html);
} else if(req.method === 'POST') {
// formからの入力値を解釈して返却
var data = '';
res.writeHead(200, {'Content-Type': 'text/html'})
req.on('data', function(chunk) {data += chunk})
.on('end', function() {
res.end(`form: ${data} `)
})
}
}).listen(port);

console.log(`Server is running : https://localhost:${port}/`);
from.html ※HTTPサーバで用意したものと同じです。
1
2
3
4
5
<form method="POST">
Name:<input type="text" name="name"><br>
Credit No:<input type="text" name="creditNo"><br>
<input type="submit">
</form>

用意したファイルは『暗号化のための鍵情報などを用意』で作成したファイルと同じ場所に配置します。

1
2
3
4
5
folder/
 ├ form.html
 ├ localhost+2-key.pem
 ├ localhost+2.pem
 └ server-https.js

HTTPS通信を行うサーバを起動します。
node .\server-https.js start

ブラウザでhttps://localhost:8443/を開きます。

WireSharckで通信内容を確認

Wiresharkでパケット取得してみます。

キャプチャ取得を開始し、「ipv6.src == ::1」でフィルターします。
フォームからHTTPリクエストします。

サーバ側では問題なくリクエスト情報を取得できていますね。

しかし、Wiresharkで通信内容見てみると、HTTP通信の時と違ってNameもcreditNoも見つかりません。それどころか、HTTP通信のときにあったGETやPOSTというやり取りすら見つけることができません。

このようにHTTPS通信の内容は、暗号化されているため、サーバが保持している秘密鍵がないと暗号化前の通信内容が分からない状態になっています。

HTTPS通信の内容を復号化して平文を確認

暗号化されている?見逃しているだけでHTTPS通信でも平文が送られてるのでは?と考える方もいるかもしれません。

次に、Wiresharkでキャプチャしている通信内容を復号して平文を確認してみましょう。復号方法は『HTTPSによる暗号化された通信のやり取りをWiresharkで復号して内容を読み取る』を参考にしてください。

筆者検証時はWireshark設定項目から「Protocols > SSL」がなくなっていたため、「Protocols > TLS」に同様の設定をして検証しています。参考先に記載がありますが「鍵情報が漏洩するとHTTPS通信内容が復号できる」ということですので、鍵情報の取扱にはご注意ください。

Wiresharkの設定後、再度HTTPS通信を行います。先ほどまでApplication Dataと表記されていた箇所が復号され、平文が確認できます。

キャプションを比較してみると、確かに設定を入れる前のWiresharkではApplication Dataと表記されていたところが、復号化されて平文になって確認できていることが分かります。

さいごに

今回はHTTP通信とHTTPS通信について、検証・確認しました。

昨今、インターネットの普及に伴い、企業では勿論ですが、プライベートで利用するインターネット通販でも個人情報を入力する機会は多くあるため、一人一人が当たり前にセキュリティ対策を知り、考えなければいけないものになってきています。

本記事は触れていませんが、HTTPS通信を行う際にその通信先を証明してくれる『信用できる第三者(証明局)』を何をもって信用するか、といった問題など、懸念を上げれば限がないぐらいセキュリティ対策は考えることが多いです。しかし、企業も個人も身を守るために避けては通れないことの一つがセキュリティ対策です。

HTTP通信に関しては、Chromeで2019年末から2020年第1四半期にわたってHTTPS/HTTP混在ページにおけるHTTPをデフォルトでブロックの対象としていくことが宣言されるなど、各サイトでHTTPSへの対応が必須となってきています。

フリーで自動化されたオープンな認証局として、『Let’s Encrypt』というサービスもあります。ISRGが公共の利益のために運営・提供しているサービスで、2016年4月12日 に正式サービスが開始して以降、毎日多くの証明書を発行しており、HTTPSへの対応もあまりコストかからずできるようになっています。

本記事は、前記の通り詳しい仕組みの解説記事とはなっておりません。最後に参考文献について記載しますので、皆さんの興味・関心に応じて別途調べてください。

普段何気なく使っている、身近な暗号通信に興味を持ってもらうきっかけになれば、幸いです!

参考文献

  • 暗号技術入門
    • 「対称暗号」「公開鍵暗号」「デジタル署名」「PKI」「PGP」「SSL/TLS」など、
      暗号技術の基礎を、たくさんの図とやさしい文章で解説しています。
  • プロフェッショナルSSL/TLS
    • いまやインターネットにおける暗号化通信に不可欠となったセキュリティプロトコルであるTLS(SSL)の全体像を体系的かつ具体的に語った、‟Bulletproof SSL and TLS”(Ivan Ristić 著)の全訳
  • Real World HTTP
    • HTTPが進化する道筋をたどりながら、ブラウザが内部で行っていること、サーバーとのやりとりの内容などについて、プロトコルの実例や実際の使用例などを交えながら紹介!!