Skip to content
154 changes: 91 additions & 63 deletions src/web-server/tls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,82 @@ apache/nginx のハンズオンの際のものが残っているのであれば
以下のように`docker pull`をしたあと、ハンズオン用のコンテナを立ち上げてログインしてください。

```shell-session
$ docker pull python:3.8.17-bookworm
3.8.17-bookworm: Pulling from library/python
d52e4f012db1: Pull complete
7dd206bea61f: Pull complete
2320f9be4a9c: Pull complete
6e5565e0ba8d: Pull complete
d3797e13cc41: Pull complete
9d8ab9ac5a7d: Pull complete
43ed38f1d568: Pull complete
164b4060be55: Pull complete
Digest: sha256:2ee706fa11ec6907a27f1c5116e9749ad1267336b3b0d53fc35cfba936fae32e
Status: Downloaded newer image for python:3.8.17-bookworm
docker.io/library/python:3.8.17-bookworm
$ docker run --rm -itd --name test-debian -p 8080:80 -p 8082:82 -p 8088:88 -p 8089:89 -p 8443:443 -p 8444:444 python:3.8.17-bookworm /bin/bash
$ docker pull python:latest
latest: Pulling from library/python
f32f49ce655a: Pull complete
8a7504cd2818: Pull complete
b53089dca505: Pull complete
8d6d44b254da: Pull complete
0a4465cc9f09: Pull complete
c965dce520b3: Pull complete
61719a06ef52: Pull complete
Digest: sha256:250e5c97be05e1eb2272fbdbd810dfd638f9012e1e6f65c99390ad3239943a08
Status: Downloaded newer image for python:latest
docker.io/library/python:latest

$ docker run --rm -itd --name test-debian -p 8080:80 -p 8082:82 -p 8088:88 -p 8089:89 -p 8443:443 -p 8444:444 python:latest /bin/bash
a0da070e286fd52ebb323e5faff9c960014bfcd8eb1e509cb5a12daa9fb9a85e
$ docker exec -it test-debian /bin/bash
root@a0da070e286f:/#
```

<details>

<summary>動作確認済みバージョン</summary>

```shell-session
root@eacb8fc335e0:/# uname -a
Linux eacb8fc335e0 6.8.0-90-generic #91~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov 20 15:20:45 UTC 2 x86_64 GNU/Linux
root@eacb8fc335e0:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.5
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@eacb8fc335e0:/# python --version
Python 3.14.5
root@eacb8fc335e0:/#
```

</details>

nginxをインストールします。

```shell-session
root@a0da070e286f:/# apt update
Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
Get:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8906 kB]
Get:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [4732 B]
Get:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [48.0 kB]
Fetched 9210 kB in 3s (3184 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
10 packages can be upgraded. Run 'apt list --upgradable' to see them.

root@a0da070e286f:/# apt install -y apache2 apache2-dev nginx neovim
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
apache2-bin apache2-data apache2-utils autopoint bsdextrautils debhelper dh-autoreconf dh-strip-nondeterminism dwz gettext gettext-base groff-base intltool-debian iproute2
libapr1-dev libaprutil1-dbd-sqlite3 libaprutil1-dev libaprutil1-ldap libarchive-cpio-perl libarchive-zip-perl libatm1 libbpf1 libcap2-bin libdebhelper-perl
libfile-stripnondeterminism-perl libgpm2 libldap-dev libldap2-dev liblua5.3-0 libmail-sendmail-perl libmnl0 libpam-cap libpipeline1 libsctp-dev libsctp1 libsodium23
root@0e82a6ed6aae:/# apt update
Hit:1 http://deb.debian.org/debian trixie InRelease
Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9671 kB]
Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [5412 B]
Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [176 kB]
Fetched 9944 kB in 1s (7832 kB/s)
25 packages can be upgraded. Run 'apt list --upgradable' to see them.
root@0e82a6ed6aae:/# apt install -y apache2 apache2-dev nginx telnet neovim
Installing:
apache2 apache2-dev neovim nginx telnet

~~~略~~~

Setting up libapr1-dev (1.7.2-3) ...
Setting up libaprutil1-dev (1.6.3-1) ...
Setting up debhelper (13.11.4) ...
Setting up apache2-dev (2.4.57-2) ...
Processing triggers for libc-bin (2.36-9) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
root@a0da070e286f:/#
Setting up libapr1-dev (1.7.5-1) ...
Setting up libaprutil1-dev (1.6.3-3+b1) ...
Setting up debhelper (13.24.2) ...
Setting up apache2-dev (2.4.67-1~deb13u2) ...
Processing triggers for libc-bin (2.41-12+deb13u3) ...
Processing triggers for hicolor-icon-theme (0.18-2) ...
root@0e82a6ed6aae:/#
```

以下のコマンドでバージョンが表示されれば成功です。

```shell-session
root@a0da070e286f:/# nginx -v
nginx version: nginx/1.22.1
root@0e82a6ed6aae:/# nginx -v
nginx version: nginx/1.26.3
```

### nginx の初期設定
Expand Down Expand Up @@ -137,7 +153,7 @@ SSL/TLSは通信路の暗号化として汎用性のあるものとなってお

プロトコルとまではなっていなくても、mysqlなどでもレプリケーションの経路を暗号化するために用いられていたりもします。

では、そのSSL/TLS の概要と歴史について、はIPAの資料がよくまとまっているため、そちらの2章1節を読むのがよいでしょう。
SSL/TLS の概要と歴史についてIPAの資料がよくまとまっているため、そちらの2章1節を読むのがよいでしょう。
ざっくりというと、公開鍵暗号を用いて共通鍵を共有し、その共通鍵を用いて以後の経路の暗号化を行う、というものになります。

[TLS 暗号設定ガイドライン](https://www.ipa.go.jp/security/crypto/guideline/ssl_crypt_config.html)
Expand Down Expand Up @@ -173,7 +189,7 @@ TLSは公開鍵暗号と共通鍵暗号の組み合わせという話をしま
- この証明書を用いたサイトの管理組織
- 有効期間
- この証明書の有効期間
- 昔は5年ものなどもありましたが、2025年現在では約13か月(398日)が最長とされています。詳しくは後述
- 昔は5年ものなどもありましたが、年々商用証明書の有効期限は短縮されています。詳しくは後述します。
- 主体者代替名、サブジェクトの代替名、サブジェクトの別名、Subject Alternative Names(SANs)
- いくつか項目がありますが、このうち重要なのはDNS名。この証明書が有効であるサイトを示しています。
- 複数存在しうる
Expand Down Expand Up @@ -337,10 +353,9 @@ Modulus=FB1908BE2B1567D1B8B7EE99DF3480CE2EDF57EC73ADD08AE2FA37A833321C84CF49D6D3

```sh
server {
listen 443 default_server;
listen [::]:443 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;

ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;

Expand Down Expand Up @@ -485,27 +500,29 @@ CA/Bフォーラムで長らく話題になっていたのが、証明書の最
- 1か月 + 1か月の半分 + 1日

ここまで短くなると、手動で更新し続けることは困難となります。
各証明局側も自動化の対応が進んでいくと思われるので、
それに合わせて自動化していく必要が出てくるでしょう。

そこで、証明書更新について[ACMEプロトコル](https://tools.ietf.org/html/rfc8555)を利用して自動化することができます。
動作の概要は[Let's Encryptのページ](https://letsencrypt.org/ja/how-it-works/)がわかりやすいです。

- **[ACMEクライアント](https://letsencrypt.org/ja/docs/client-options/)**
- 証明書を自動取得する際にクライアントサーバー側で動作するソフトウェアです。
Certbot や Lego 、cert-manager など多数のクライアントがあります。
- **[チャレンジ](https://letsencrypt.org/ja/docs/challenge-types/)**
- 証明書が証明しようとしているドメイン名が自身のものであることを自動的に確認するために「チャレンジ」を行います。
HTTP プロトコルを利用する HTTP-01 や、 DNS プロトコルを利用する DNS-01, DNS-PERSIST-01 がありあます。

### 詳細な暗号設定

TLSの設定としては、主に、プロトコルのバージョン、暗号スイート、証明書、に何を使うかが大事になります。

#### protocol を設定してみる(check3)

プロトコルについては、既にTLSv1.1 までは2021に禁止扱いになっていたりします
プロトコルについては、既にTLSv1.1 までは主要なブラウザやOSで禁止扱いになっていたりします

nginx だと`ssl_protocols`で設定します。
サーバー側で受け入れる TLS バージョンは、nginx だと`ssl_protocols`で設定します。

まずは、デフォルトの状態で接続を確認してみましょう。TLSv1.2で接続できています。

::: tip
nginx上ではデフォルトで後述設定の通りTLSv1, 1.1 が有効に見えますが、接続できないようです。
そのため、ここでは差異が見えるようわざとTLSv1.2 で試してみています。
:::

```sh
root@34cfcf7b6f05:/# curl -vvv -k --tls-max 1.2 https://localhost:443
* Trying 127.0.0.1:443...
Expand Down Expand Up @@ -534,7 +551,7 @@ Hello Bootcamp!!
```


では、/etc/nginx/nginx.conf に設定があるので、書き換えてみましょう
では、/etc/nginx/nginx.conf に設定があるので、TLSv1.2 は受け入れないように書き換えてみましょう
書き換えたら再起動して反映させます。


Expand All @@ -545,7 +562,7 @@ root@34cfcf7b6f05:/# vim /etc/nginx/nginx.conf
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE <= ここからTLSv1 TLSv1.1 TLSv1.2 を消してみる
ssl_protocols TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1 <= ここから TLSv1.2 を消してみる
ssl_prefer_server_ciphers on;

##
Expand Down Expand Up @@ -630,7 +647,10 @@ root@34cfcf7b6f05:/# service nginx restart
::: tip
ssl\_ciphers の設定部分は、openssl ciphers の引数に渡すことで、この設定で使えるcipher の一覧を表示させることができます。
今回は列挙した形ですが、!EXP のようにブラックリスト的な書き方もできるため、よくわからなくなったらこのように実際に設定されるものを確認するとよいでしょう。

```
openssl ciphers -v "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305"
```
:::

`openssl ciphers`の一覧から適当なものを選んで接続してみて、nginx.confで設定したものは接続でき、設定しなかったものは接続できないことを確認してください。
Expand Down Expand Up @@ -667,6 +687,7 @@ curl: (35) OpenSSL/3.0.9: error:0A000410:SSL routines::sslv3 alert handshake fai

ECDSAは暗号の特性上、短い鍵長でも高いセキュリティ強度を保つことができます。
RSAであれば2048bit、ECDSAであれば256bit のものを使うのがよいでしょう。
(量子コンピューターが実用化した場合はプロトコルや鍵長を見直す必要があります。詳しくは後述します。)

ここでは、試しにECDSAの秘密鍵を用いて証明書を作って使用してみます。
openssl コマンドで、ECDSAの秘密鍵も生成可能です。
Expand Down Expand Up @@ -708,10 +729,9 @@ root@34cfcf7b6f05:/# vim /etc/nginx/sites-enabled/default
(中略)

server {
listen 443 default_server;
listen [::]:443 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;

ssl on;
ssl_certificate /etc/nginx/ssl/ecdsa.crt; # <= ここを書き換え
ssl_certificate_key /etc/nginx/ssl/ecdsa.key; # <= ここを書き換え

Expand Down Expand Up @@ -741,3 +761,11 @@ mozilla の推奨暗号スイートも参考になります。
今回のcipher設定についてはmozilla のintermediate のものを利用しています。
[こちら](https://ssl-config.mozilla.org/)で対応する設定を出力してくれるのも便利です。

安全とされる設定は技術進化や技術革新によって変化していきます。
最新の推奨設定を把握し、必要に応じて暗号スイートをより強固なものにすることが大切です。

特に、量子コンピューターが実用化した時は 2048bit RSA や 256bit ECDSA ですら短時間で突破されてしまう可能性があります。

量子コンピューターによる暗号解読に対して安全だと考えられる暗号アルゴリズムを「耐量子暗号」 (PQC: Post-Quantum Cryptography) と呼びます。
現在のところ、量子コンピューターは公開鍵暗号アルゴリズムへの脅威となっている一方で、多くの共通鍵暗号やハッシュ関数は量子コンピュータからの攻撃に対して比較的安全と考えられています。
耐量子暗号アルゴリズムについても研究・議論が続いており、こちらも定期的に確認するとよいでしょう。