Daydreaming in Brookline, MA

Webサイトに安全にアクセスするための仕掛け

1 はじめに

ブラウザーでWebサイトを見る際には、安全性を担保するために送受信するデータを暗号化します。暗号化は、ユーザーが意識することはほぼ無く、サーバーとブラウザーの間で水面下に行われます。ブラウザーで開いているページのURLがhttpでなくhttps(最後のsが重要)で始まっている場合、やり取りは暗号化されています。

今回のエントリーでは、Webサイトにアクセスする際のSSL暗号化について、特にWebサーバーが提示するSSL certificate(SSL証明書)がどういうものかを見ていきます。

2 公開鍵暗号と共通鍵暗号

ファイルなどの電子データを暗号化する方法に、公開鍵暗号共通鍵暗号があります(他にもあります)。ブラウザーとWebサーバーの間で使われるSSL暗号ではこの両方が使われます。特に公開鍵暗号は、digital signature(電子署名)やcertificate(サーバー証明書)といったものの中核をなす重要技術です。

2.1 公開鍵暗号

公開鍵暗号は、世間に公開するpublicキーと、持ち主以外には決して見せてはいけないprivateキーのキーペアを使います。ペアとなるpublicとprivateキーは数学的に密接に関係していて、片方で暗号化したデータはもう片方で「のみ」復号化できます。

この、もう片方のキーを使わないと決して復号化できないという性質を応用して、お互いに知らない者同士が、インターネットという安全でないインフラを経由して、安全に秘密情報(例:クレジットカード情報)をやりとりする方法が確立されています。

publicキーで暗号化したデータはペアとなるprivateキーでしか復号化することができません。例えばブラウザーからWebサーバーに秘密情報を送る際に、サーバーのpublicキーを使って暗号化したものを送付すれば、たとえ誰かに覗き見されていても安全です。サーバーの持つprivateキーでしか復号化できないのですから。

一方、privateキーを暗号化したデータは、ペアとなるpublicキーでしか復号化することができません。このため、例えばWebサーバーが自身のprivateキーで暗号化したデータを受領した場合、途中で何者かに書き換えられたことが決して無い(もし書き換えられていたらサーバーのpublicキーで復号化できないので)ことが確認できます。

ポイントは以下です。

  • publicキーとprivateキーがペアをなす
  • 片方のキーで暗号化したデータは、もう片方のキーでのみ復号化することができる
  • 暗号化するキーをpublic/privateのどちらにするかで異なる用途に使える

公開鍵暗号は極めて安全ですが、複雑な計算が必要なので、ここぞという用途で使われます。

2.2 共通鍵暗号

一方、共通鍵暗号は暗号化も復号化も同じ一つのキー(secretキー)を使って行います。公開鍵暗号と比べて軽いという特徴がありますが、そもそもやり取りしたい両者がキーを安全に共有すること自体が課題となります。

ブラウザーとWebサーバーとの間では、この共通鍵をお互いに共有するために公開鍵暗号を使い、その後のやりとり(セッション)は共通鍵暗号を使います。

簡単なまとめ

暗号化方式 キー種類 公開範囲
公開鍵暗号 publicキー 世間に公開する
公開鍵暗号 privateキー 持ち主しかアクセスできない
共通鍵暗号 secretキー やり取りする2者だけが知っている

3 Digital signature(電子署名)

Digital signatureは電子データが作成したままの状態である(改ざんされていない)ことを保証します。そしてこのために公開鍵暗号を利用します。

具体的には、保護したい電子データのハッシュを取り、ハッシュ値をprivateキーを使って暗号化したものがdigital signatureです。

受領した電子データにdigital signatureが付いていた場合、サインした者のpublicキーを使って復号化したハッシュ値と、電子データをハッシュした値を突き合わせて、それらが合致すればその電子データは作成したままの正しいデータであることになります。

4 SSL Certificate(SSL証明書)

SSL certificateはブラウザーとWebサーバーの間で安全にやりとりをするべく、暗号化されたコネクションを確立するために使われます。ブラウザーがWebサーバーにhttpsでアクセスしようとすると、Webサーバーは自身のcertificateをブラウザーに送ります。

このcertificateは、アクセスしているWebサーバーが正当であることを保証すると共に、Webサーバーのpublicキーを保持しています。ブラウザーはこのpublicキーを使って自身の生成したsecretキーを暗号化し、秘密裏にそして安全にWebサーバーに渡すことができます。

証明書で明確に理解しておきたいことは、2つのprivate keyが関連しているということです。1つ目はその証明書の元になっているキーで、証明書は1つ目のprivate keyの化身と言えます。2つ目はその証明書の正当性を保証するべくサインするのに使っているキーです。1つ目は、その証明書の持ち主が秘密裏に持っているもので、2つ目は、通常CAがやはり秘密裏に持っています。

証明書が有効期限内なのに失効した場合、それは対になる1つ目のprivate keyが流出した(compromiseされた)ことを意味します。証明書自体はオープンなので、流出するリスクはありません。めったにありませんが、2つ目のprivate keyが流出すると、それはかなり大事です。それでサインした証明書が全て実質無効化されてしまうので。

4.1 SSL Certificateを見てみる

ブラウザーでとりあえずSonyのWebサイト https://www.sony.co.jp/ に行ってみます。 (Firefoxの場合)URLの左側にある鍵アイコン > Connection secure > More information とクリックするとウインドウがオープンするので、View Certificateをクリックします。これがSonyサイトのcertificateです。

このままブラウザー上でcertificateを見てもいいのですが、コピペしやすいようにテキストファイルに変換してみます。certificateをMicellaneousセクションまでスクロールして、PEM (cert)をクリックすると Downloadsフォルダに www-sony-net.pem というファイルでダウンロードされます:

-----BEGIN CERTIFICATE-----
MIIHPjCCBiagAwIBAgIQDfh/6fcD463/IpRXcMni+DANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE
aWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMzExMDgwMDAwMDBa
Fw0yNDExMDcyMzU5NTlaMG0xCzAJBgNVBAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzES
<snip>

意味不明なので、opensslコマンドを使ってテキストファイルに変換します。

~/Downloads % openssl x509 -in www-sony-net.pem -text | less

無事に見られました。Issuerを見たところ、DigiCert Incが発行したものです。Serial NumberはDigiCertが発行したcertificatesにアサインされるユニークなシリアル番号です。

Certificate:
    Data:
	Version: 3 (0x2)
	Serial Number:
	    0d:f8:7f:e9:f7:03:e3:ad:ff:22:94:57:70:c9:e2:f8
	Signature Algorithm: sha256WithRSAEncryption
	Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
	Validity
	    Not Before: Nov  8 00:00:00 2023 GMT
	    Not After : Nov  7 23:59:59 2024 GMT
	Subject: C=JP, ST=Tokyo, L=Minato-ku, O=Sony Global Solutions Inc., CN=www.sony.net
<snip>

Validityはこのcertificateの有効期間を示します。昔はもっと長かったですが、最近は大体1年間ですね。GMTで2023/11/8の0:00から2024/11/7 23:59:59までです。

Subjectはこのcertificateが認めている組織です。国(C; Country)から市(L; Locality)までの所在地と、組織名(O): Sony Global Solutions Inc.、そしてCommon Name(CN): www.sony.netが指定されています。DigiCertなどのCA(Certificate Authority)は、このSony Global Solutions Incという組織が実際に存在し、このcertificateの発行を要求したのがSony Global Solutions Incであることを保証するために、役所の登記情報を調べたり実際に電話番号にかけたりして確認するそうです。

SSL certificateにはpublicキーが含まれていて、これを保証するのも証明書の目的です。publicキーが入っているのは、後でこれを使ってセッションを暗号化するsecretキーを共有するためです。非対称暗号はより安全ですが遅いので、セッション全体は対称暗号キーを使って暗号化します。ブラウザーは自分が生成した対称暗号キーを、certificateに入っているサーバーのpublicキーを使って暗号化し、サーバーに送ります。これはサーバーの持つprivateキーでしか復号化することができないので、安全に渡すことができるというわけです。

Subject Public Key Info:
    Public Key Algorithm: id-ecPublicKey
	Public-Key: (256 bit)
	pub:
	    04:e7:39:f7:43:da:fd:1d:4e:17:14:60:94:98:74:
	    03:59:ac:f3:e6:c3:4b:0e:d4:f9:9f:65:3e:27:63:
	    a9:3b:bf:52:f7:26:0a:bb:d6:d6:c5:7c:93:9b:5c:
	    13:e2:92:d4:36:21:1c:62:e2:14:5e:ad:4b:2e:a2:
	    4e:38:3c:06:50
	ASN1 OID: prime256v1
	NIST CURVE: P-256

publicキーはpub:以下に入っています。256ビットよりも長いですが、X.690 でエンコードされているためのようです。

X509v3 extensions:
    X509v3 Authority Key Identifier: 
	B7:6B:A2:EA:A8:AA:84:8C:79:EA:B4:DA:0F:98:B2:C5:95:76:B9:F4
    X509v3 Subject Key Identifier: 
	B9:34:CD:A9:4C:D5:A0:FB:0B:3E:99:FD:B3:1A:F3:E9:C5:8E:B1:97

Authority Key Identifierはこのcertificateを保証するDigiCertの(中間)certificateのユニークなキーIDです。そしてSubject Key IdentifierはこのcertificateのユニークなIDです。SonyのWebサーバーから送られるcertificatesは、このSonyのcertificateだけでなく、それを保証するDigiCertの中間certificateと、されにそれを保証する、やはりDigiCertのルートcertificateがチェインされた状態で付いてきます。

X509v3 Subject Alternative Name: 
    DNS:www.sony.net, DNS:ap.pitsquare.jp, DNS:rd1.sony.net, DNS:rd2.sony.net, DNS:sony.net, DNS:www.360ra.info, DNS:www.sony-olympus-medical.com, DNS:www.sony.co.jp, DNS:www.sonybo.co.jp, DNS:www.sonydna.com, DNS:www.sonyglobalsolutions.jp, DNS:www.sonykigyo.jp, DNS:www.sonymobility.com, DNS:www.sonypark.com, DNS:www.sonyprotechnosupport.co.jp, DNS:www.sonystoragemedia.co.jp, DNS:www.sonytc.co.jp, DNS:www.syneco.inc

Subject Alternative Name (SAN)は、このcertificateが認めている、この組織(Sony Global Solutions Inc)のドメイン名一覧です。これらがこの組織のものであることをcertificateは保証しています。

X509v3 Key Usage: critical
    Digital Signature, Key Agreement

Key Usageは、このcertificateの用途を示します。SSL certificateの場合はDigital Signature, Key Agreementまたは類似のもの(Key Encipherment等)が指定されます。Digital Signatureは、certificateに入っているpublicキーが(certificate signing以外に)電子署名の用途でも使われることを意味し、Key Agreementはやはりこのpublicキーでセッション暗号化に使うsecretキーを暗号化することを意味します。

X509v3 CRL Distribution Points: 
    Full Name:
      URI:http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl
    Full Name:
      URI:http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl

CRL Distribution PointsはCertification Revocation List (CRL)の場所を示します。Certificateは一度発行した後にrevoke(取り消す)されることがあるので、取り消されたcertificatesがリストされている場所を示す必要があります。例えば、certificateに含まれるpublicキーに対応するprivateキーが流出したような場合にそのpublicキーを含むcertificate無効化し、このリストに載せます。

    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
	0c:38:1b:fc:e9:54:f9:02:2f:bc:6b:39:ea:9e:ef:c0:fd:f3:
	40:03:dc:17:d2:b2:0a:b6:c9:25:0e:8e:74:23:30:53:01:67:
	ab:ac:71:c8:3b:a1:46:1c:1c:40:4e:c8:51:8e:aa:fe:84:38:
<snip>

SignatureはCA(この場合DigiCert)のサイン(digital signature)であり、この証明書が正しいことを保証するものです。この値は証明書全体(マイナスsignature情報)をハッシュした値をCA自身のprivateキーを使って暗号化したものです。これをこのcertificateにチェインされているCAの(中間)certificateに含まれるpublicキーを使って復号化した値と、別途証明書を指定アルゴリズムでハッシュした値が合致することで、この証明書が改ざんされていないことが確認できます。

ここまでで、この証明書が正しいことをCAの(中間)証明書が保証していることがわかりました。それじゃ、その中間証明書が正しいことは誰が、、、と辿っていくと、最終的にCAのルート証明書に行き着きます。

CAのルート証明書はだれがどうやって保証しているの、というと、証明書だけ見ていてもわかりません。技術的には、CAルート証明書はいわゆる「オレオレ証明書(self-signed certificate)」と同じものです。CAが自分で生成したCA root private keyを使って作成、サインされています。俺が正しいと言ってサインしているから正しい、以上の保証はありません。

ところが実は、ブラウザーはいくつかのCAルート証明書を無批判に信用していて、その信用リストに当該CAルート証明書が入っているかを確認することで、最終的にブラウザーがそのサイトを信用するかどうかを決めているのでした。

仮に私が作成したself-signed certificateしかもたないWebサーバーにhttpsでブラウザーがアクセスに行くと、それはブラウザーの信用リストに(もちろん)入っていないので、Warningが出ます。Warningを無視してアクセスすることは、実はかなり危険なことなのです。

結局私のブラウザーは、この証明書を受け取ったことで、以下がわかりました。

  • セッションキーを暗号化するためのサーバーpublicキー
  • Sony Global Solutions Incが正しいとDigiCertが保証している
  • Sony Global Solutions Incが管理しているDNSドメイン名一覧
  • この証明書自体が正しい(出どころが正しく、改ざんされていない、取り消されていない等)ものとDigiCertが保証している
  • そして、DigiCert(のCAルート証明書)はブラウザーが信用している

5 WebサイトにSSL certificateを用意する

5.1 キーペアとCSRを用意する

まずは公開鍵暗号に使うキーペアを用意します。いろいろなツールが使えますが、openssl や gpg(GnuPG) も使えます。この stackexchangeのページ によると、openssl よりも gpg のほうがより品質の良い乱数を使っているそうです。

作成したキーペアはそのままでは誰も信用してくれません。CAにcertificateを作成してもらって権威付けすることで、初めてブラウザーが信用してくれるようになります。そのためにCSR(Certificate Signing Request)が必要になります。

DigiCertの Knowledge Base を見ると openssl を使った privateキーとCSRの作成方法が書いてあるので、openssl を使ってみます。

openssl req -new -newkey rsa:2048 -nodes -keyout sv.key -out sv.csr

国、州や県、組織名などの情報を聞かれるので入力していくと2つのファイルが生成されます。

  • sv.csr - CSRファイルです。これにはpublic keyの情報が含まれます。
  • sv.key - privateキーです。安全なところに厳重に保管します。CAにも渡してはいけません。

なお、privateキーからpublicキーが生成できます。これ、意外と大事なポイントです。逆はもちろんできません。

openssl pkey -in sv.key -pubout

5.2 SSL certificateを発行してもらう

上で作成したCSRファイル(sv.csr)の中身をコピペしてDigiCert等のCAに証明書を発行依頼します。CAによる調査が行われたあと、問題がなければCAのプライベートキーで署名されたSSL certificateが送られてきます。

5.3 SSL certificateをアップロードする

Webサーバーによってやり方が変わってきますが、WebサーバーやロードバランサーにcertificateをアップロードしてSSLを使えるようにします。

6 ブラウザーからWebサイトにアクセスする

  1. ブラウザーからhttpsを指定してWebサイトにアクセスに行くと、まずブラウザーはサーバーのidnetityをリクエストする
  2. サーバーは自身のSSL certificateを送る
  3. ブラウザーはCertificateが信頼できるか確認する
    • チェインされているルートcertificateの発行元であるCAが信頼しているリストに載っているか
      • たどる際に、Authority Key IdentifierがチェインされているcertificateのSubject Key Identifierと合っているか確認する
    • Certificateは書き換えられていないか
      • CertificateについているCAの署名(Signature Value)を、CAのpublicキーで復号化したものが、このcertificateをハッシュした値と一致すれば書き換えられていない
    • Certificateが有効か(expireしていないか、revokeされていないか等)
  4. ブラウザーはセッションでのやりとりを対称暗号化するsecretキー(セッションキー)を準備し、これをCertificateに含まれるpublicキーを使って暗号化してサーバーに送る
    • 送信経路で覗き見されても、暗号化されているためにsecretキーを取り出すことができない
  5. サーバーは自身のprivateキーを使ってセッションキーを復号化して取り出す
    • 復号化に成功したら、途中で書き換えられていないことがわかる
  6. サーバーは共有できたセッションキーを使って暗号化されたセッションを開始する

7 終わりに

証明書、署名、private keyといったキーワードは耳にしたことがあると思いますが、それらの働きを正しく理解することはかなり大変です。実感を伴って理解するには、opensslなどで何がインプットとなって何がアウトプットとなるのか、といったあたりを実際にコマンドラインを眺めて整理していみるのが早道かと思います。

これらの技術の全ては公開鍵暗号から来ていると理解することで、ひとつずつ確実に理解してゆけるものと思います 。