Files
cpp-httplib/docs-src/pages/ja/cookbook/t04-mtls.md
yhirose bef278e0d2 Fix docs pages that no longer match the code
Samples that did not compile or run as shown:
- res.user_data.get<T>() inside a generic lambda needs the `template`
  keyword; use explicit parameter types (tour 09, cookbook s15).
- listen() on a Unix domain socket fails with port 0 (tour 09, s22).
- "*.dev.local" is not a NO_PROXY pattern (c16).
- ssl_backend_error() holds a verify result, not an ERR_get_error()
  value, after a verification failure; decode each with the matching
  OpenSSL function (c18).
- The content provider's `length` is everything that remains, so the
  sample read the whole file in one call (s05).

Statements corrected:
- Client keep-alive is off by default; c14 is rewritten around
  set_keep_alive(true).
- Mounted files are looked up before GET handlers (tour 04, s04).
- Params keep insertion order, and to_string(Error::Connection) reads
  "Could not establish connection" (tour 02).
- A chunked provider ends with sink.done(), and post_routing_handler
  runs before the response is sent (tour 09).
- Timeouts surface as Error::Read; Error::Timeout comes from the stream
  API (c17). The max timeout cuts off the wait for the response only
  (c13). The progress callback needs Content-Length (c11).
- Encoding selection follows q-values, then Brotli, gzip, Zstd (s08),
  and the client compresses with the first of those it was built with
  (c15).
- stop() cuts a provider-driven response short (s19); a rejected
  content_reader already gets 400 or 413 (s07); user_data values must be
  copyable (s12); Client accepts a client certificate too (t04);
  on_message() is the fallback for every unhandled event and 204/403/404
  end reconnection (e04); the pong timeout takes two to three intervals
  and ends a waiting read() (w02).

In the LLM app tutorial, an uncaught exception does not crash the
server, so say what it does instead. Drop the server and client timeout
settings whose stated purpose, covering inference and download time,
they do not serve: those timeouts bound a single socket wait. Update
the llama.cpp server layout in chapter 7.
2026-10-08 20:39:13 -04:00

3.7 KiB
Raw Blame History

title, order, status
title order status
T04. mTLSを設定する 46 draft

通常のTLSはサーバー証明書だけを検証しますが、mTLS(mutual TLS、相互TLS)ではクライアントも証明書を提示し、サーバーがそれを検証します。API間通信のゼロトラスト化や、社内システムの認証でよく使われるパターンです。

サーバー側の設定

SSLServerのコンストラクタ第3、第4引数に、クライアント証明書を検証するためのCA証明書を渡します。

httplib::SSLServer svr(
  "server-cert.pem",    // サーバー証明書
  "server-key.pem",     // サーバー秘密鍵
  "client-ca.pem",      // クライアント証明書を検証するCA
  nullptr               // CAディレクトリ(省略)
);

svr.Get("/", [](const httplib::Request &req, httplib::Response &res) {
  res.set_content("authenticated", "text/plain");
});

svr.listen("0.0.0.0", 443);

この設定だと、クライアント証明書がclient-ca.pemで署名されていない接続はハンドシェイクの段階で拒否されます。ハンドラまで到達した時点で、クライアントはすでに認証済みです。

メモリ上のPEMで設定する

httplib::SSLServer::PemMemory pem{};
pem.cert_pem = server_cert.data();
pem.cert_pem_len = server_cert.size();
pem.key_pem = server_key.data();
pem.key_pem_len = server_key.size();
pem.client_ca_pem = client_ca.data();
pem.client_ca_pem_len = client_ca.size();

httplib::SSLServer svr(pem);

環境変数やシークレットマネージャから読み込む場合はこちらが便利です。

クライアント側の設定

クライアント側では、SSLClientのコンストラクタにクライアント証明書と秘密鍵を渡します。

httplib::SSLClient cli("api.example.com", 443,
                       "client-cert.pem",
                       "client-key.pem");

auto res = cli.Get("/");

証明書と鍵のパスだけなら、httplib::Client cli("https://api.example.com", "client-cert.pem", "client-key.pem")のようにClientにも渡せます。秘密鍵にパスワードがある場合はSSLClientを使い、第5引数で渡します。

クライアント側にも同じPemMemory構造体があり、メモリ上のPEMからクライアント証明書を設定できます。

httplib::SSLClient::PemMemory pem{};
pem.cert_pem = client_cert.data();
pem.cert_pem_len = client_cert.size();
pem.key_pem = client_key.data();
pem.key_pem_len = client_key.size();

httplib::SSLClient cli("api.example.com", 443, pem);

auto res = cli.Get("/");

WebSocketクライアント(wss://)でmTLSを使う場合はW05. wss接続でTLSを設定するを参照してください。

ハンドラからクライアント情報を取得する

ハンドラの中で、どのクライアントが接続してきたかを確認したいときはreq.peer_cert()を使います。詳しくはT05. サーバー側でピア証明書を参照するを参照してください。

用途

  • マイクロサービス間通信: サービスごとに証明書を発行して、証明書で認証する
  • IoTデバイスの管理: デバイスに証明書を焼き込み、APIへのアクセス制御に使う
  • 社内VPNの代替: 公開されているエンドポイントに証明書認証をかけて、社内リソースへ安全にアクセスさせる

Note: クライアント証明書の発行と失効管理は、普通のパスワード認証より運用コストが高いです。内部PKIを回すか、ACME(Let's Encryptなど)系のツールで自動化する体制が必要です。