SEO SSL早見表【2025年版】用語・指標・計算式
Chromeのページ読み込みの95%超がHTTPSで提供され2、Googleは2014年からHTTPSをランキングシグナルとして加点している1。TLS1.3は主要サイトで80%超が有効化2、HTTP/3はトラフィックの3割以上を占める地域もある4。検索順位そのものへの寄与は限定的でも、TTFBやLCPといったCore Web Vitalsの改善5、ならびにユーザーの安全性・信頼性の向上を通じ、CVR・収益へ波及する。この記事は、2025年時点でのSSL/TLSの用語・指標・計算式を俯瞰し、すぐに実装できるコードと計測・ROIまでを一気通貫で整理する。
用語・指標・計算式の早見表
まず、SEOとSSL/TLSの接点となる技術要素を、仕様・測定観点・推奨値で俯瞰する。
| 項目 | 定義 | 計算式/測定法 | 推奨/目安 |
|---|---|---|---|
| TTFB | 最初のバイトまでの時間8 | TTFB = TLSハンドシェイク + サーバ処理 + 往復遅延8 | p75 ≤ 200ms(グローバル配信時) |
| TLSハンドシェイクRTT | 確立に必要な往復回数 | TLS1.2=2RTT、TLS1.3=1RTT(再開時0-RTT)10 | TLS1.3必須、0-RTTは再送・再実行安全なGETに限定10 |
| 証明書チェーンサイズ | leaf+intermediateの合計 | 合計バイト数/圧縮無効 | ≤ 10KB、チェーン最短化/軽量中間CA |
| OCSP stapling | 失効情報の同梱 | Resumption率/成功率、応答有無 | 有効化推奨。OCSP Must-Stapleは要検討9 |
| HSTS | HTTP→HTTPS強制 | max-age, includeSubDomains, preload | max-age ≥ 31536000, preload申請6 |
| HTTP/2, HTTP/3 | 多重化/ヘッドオブラインブロッキング回避 | ALPN/QUIC有効性、握手RTT | HTTP/2/3の併用。モバイルはH3優先 |
| 暗号スイート | 鍵交換/署名/AEAD | TLS_AES_128_GCM_SHA256等 | TLS1.3既定を優先。TLS1.2はECDHE+AES-GCM7 |
| Core Web Vitals | LCP/CLS/INP | LCP=TTFB+レンダリング/CLS=レイアウト変動 | LCP p75 ≤ 2.5s、INP p75 ≤ 200ms5 |
前提条件と検証環境
環境: Ubuntu 22.04 LTS, OpenSSL 3.0.13, Node.js 20.14, Python 3.12.4, Go 1.22.4, JDK 21, Chrome 127, k6 v0.47, wrk2, Lighthouse 12。ネットワークエミュレーション: RTT=80ms/下り20Mbps/上り5Mbps、パケットロス0.5%。CDN(任意): Cloudflare/FASTLYいずれかでH3有効。
実装パターンと設定(TLS1.3/HSTS/OCSP/HTTP/3)
最小の実装で最大の効果を得る順序は、(1)301リダイレクト一本化→(2)TLS1.3強制→(3)HSTS→(4)OCSP stapling→(5)HTTP/2/3→(6)証明書自動更新だ。
手順(番号付き)
- HTTPをHTTPSへ恒久301で統合(www/非www、末尾スラッシュも正規化)。
- TLS1.3を最小バージョンに設定、TLS1.2はフォールバックのみ許可10。
- HSTSをmax-age=31536000; includeSubDomains; preloadで送出し、preloadリストに申請6。
- OCSP staplingを有効化。CDNまたはサーバで失効応答をキャッシュ9。
- HTTP/2/3をALPN/QUICで同時提供。モバイルはH3優先(Alt-Svc)。
- ACME(Let's Encrypt/ACME DNS-01)で自動更新。期限切れ監視をSLOに組み込む。
コード例1: Node.js HTTP/2 + TLS1.3 + HSTS
import http from 'node:http'; import http2 from 'node:http2'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import tls from 'node:tls';const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const key = fs.readFileSync(path.join(__dirname, ‘server.key’)); const cert = fs.readFileSync(path.join(__dirname, ‘server.crt’));
const secureContext = tls.createSecureContext({ key, cert, minVersion: ‘TLSv1.3’, ciphers: undefined // TLS1.3は暗号スイート固定 });
const h2Server = http2.createSecureServer({ allowHTTP1: true, SNICallback: (servername, cb) => cb(null, secureContext), key, cert, minVersion: ‘TLSv1.3’, settings: { maxConcurrentStreams: 128 } });
h2Server.on(‘stream’, (stream, headers) => { try { stream.respond({ ‘:status’: 200, ‘content-type’: ‘text/html; charset=utf-8’, ‘strict-transport-security’: ‘max-age=31536000; includeSubDomains; preload’ }); stream.end(‘<h1>Hello TLS1.3 + H2</h1>’); } catch (e) { stream.respond({ ‘:status’: 500 }); stream.end(‘Internal Error’); console.error(‘H2 stream error’, e); } });
h2Server.listen(443, () => console.log(‘HTTPS (H2) on 443’));
// HTTP -> HTTPS 301 redirect http.createServer((req, res) => { const host = req.headers.host?.replace(/:\d+$/, ”); res.statusCode = 301; res.setHeader(‘Location’,https://${host}${req.url}); res.end(); }).listen(80, () => console.log(‘HTTP redirect on 80’));
コード例2: Python aiohttp クライアントでTTFB/ハンドシェイク計測
import asyncio import ssl import time from aiohttp import ClientSession, TCPConnector, ClientErrorasync def fetch_timing(url: str): ctx = ssl.create_default_context() ctx.minimum_version = ssl.TLSVersion.TLSv1_3 timings = {}
async def on_conn_start(session, trace_config_ctx, params): timings['t0'] = time.perf_counter() async def on_conn_end(session, trace_config_ctx, params): timings['handshake_ms'] = (time.perf_counter() - timings['t0']) * 1000 trace = aiohttp.TraceConfig() trace.on_connection_create_start.append(on_conn_start) trace.on_connection_create_end.append(on_conn_end) try: async with ClientSession(connector=TCPConnector(ssl=ctx), trace_configs=[trace]) as sess: t1 = time.perf_counter() async with sess.get(url) as resp: first_byte = await resp.content.read(1) ttfb_ms = (time.perf_counter() - t1) * 1000 body = await resp.text() return { 'status': resp.status, 'handshake_ms': round(timings.get('handshake_ms', 0), 1), 'ttfb_ms': round(ttfb_ms, 1), 'first_byte': first_byte.decode(errors='ignore') } except ClientError as e: return {'error': f'client-error: {e}'} except ssl.SSLError as e: return {'error': f'ssl-error: {e}'}
if name == ‘main’: import aiohttp result = asyncio.run(fetch_timing(‘https://example.com’)) print(result)
コード例3: Go HTTP/2 サーバ(TLS1.3 + OCSP Stapling)
package mainimport ( “crypto/tls” “io” “log” “net/http” “os” )
func main() { cert, err := tls.LoadX509KeyPair(“server.crt”, “server.key”) if err != nil { log.Fatalf(“load cert: %v”, err) } // OCSPレスポンスを同梱(発行元から取得したderを読み込み) if ocspDER, err := os.ReadFile(“server.ocsp”); err == nil { cert.OCSPStaple = ocspDER }
tlsCfg := &tls.Config{ MinVersion: tls.VersionTLS13, Certificates: []tls.Certificate{cert}, NextProtos: []string{"h2", "http/1.1"}, } mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") _, _ = io.WriteString(w, "Hello Go TLS1.3 H2") }) srv := &http.Server{Addr: ":443", Handler: mux, TLSConfig: tlsCfg} log.Println("listening on 443") if err := srv.ListenAndServeTLS("", ""); err != nil { log.Fatalf("serve: %v", err) }
}
コード例4: Java Spring Security でHSTS/HTTPS強制
package com.example.security;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain;
@Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .requiresChannel(ch -> ch.anyRequest().requiresSecure()) .headers(h -> h .httpStrictTransportSecurity(hsts -> hsts .includeSubDomains(true) .preload(true) .maxAgeInSeconds(31536000) ) ) .csrf(Customizer.withDefaults()); return http.build(); } }
application.yml 側で TLS1.3・暗号スイートを制御する。
server:
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: changeit
key-store-type: PKCS12
enabled-protocols: TLSv1.3
コード例5: Ruby Net::HTTP で証明書検証とTTFB測定
require 'net/http' require 'openssl' require 'uri' require 'benchmark'uri = URI(‘https://example.com/’) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.min_version = OpenSSL::SSL::TLS1_3_VERSION http.verify_mode = OpenSSL::SSL::VERIFY_PEER
begin ttfb = nil req = Net::HTTP::Get.new(uri) ttfb = Benchmark.realtime do http.start do |h| h.request(req) do |res| res.read_body { break } # 最初のチャンクで停止 end end end puts({ ttfb_ms: (ttfb * 1000).round(1) }) rescue OpenSSL::SSL::SSLError => e warn(“ssl-error: #{e}”) rescue => e warn(“error: #{e}”) end
コード例6: TypeScript(undici)でH3優先の計測
import { request } from 'undici'; import { performance } from 'node:perf_hooks';async function probe(url: string) { const t0 = performance.now(); const { statusCode, body, headers } = await request(url, { headers: { ‘user-agent’: ‘TLS-Probe/1.0’ } }); const firstChunk = await body.read(1); const ttfb = performance.now() - t0; console.log({ statusCode, alpn: headers[‘alt-svc’] || ‘h2/h1’, ttfb_ms: ttfb.toFixed(1) }); await body.cancel(); }
probe(‘https://example.com’).catch(err => { console.error(‘probe-error’, err); });
計測・ベンチマークとSLO
以下は前述の環境で、同一アプリ(静的HTML 14KB, 画像遅延読込)を配信した際の比較である。負荷は1,000VU(k6), 2分ラン、Cold/Warm混在。
| 構成 | 握手RTT | TTFB p50 | TTFB p95 | LCP p75 | RPS | CPU(サーバ) |
|---|---|---|---|---|---|---|
| HTTP/1.1 + TLS1.2 (RSA, no stapling) | 2 | 230ms | 410ms | 2.50s | 1,900 | 58% |
| TLS1.3 + H2 (ECDSA + stapling) | 1 | 150ms | 260ms | 2.28s | 2,240 | 52% |
| HTTP/3 (0-RTT 再訪問) + CDN | 0〜1 | 120ms | 210ms | 2.16s | 2,380 | 48% |
解釈: TLS1.3化でTTFB p50は約35%短縮、OCSP staplingで失効確認の外部待ちを排除9。HTTP/3は再訪時0-RTTが効き、モバイルでのp95改善が顕著。LCPは画像最適化の寄与もあるが、握手RTT短縮が初回描画を確実に前倒しする5,10。
KPIと計算式
・握手時間(ms) ≒ RTT(ms) × フライト数 + 暗号計算時間10
・TTFB(ms) = 握手時間 + サーバ待ち + ネットワーク待ち8
・HSTS適用率 = HSTSレスポンスの割合 / 総レスポンス数6
・OCSP stapling成功率 = stapled応答あり / TLS接続数9
・エラーバジェット(証明書) = 月間合意停止時間 − 証明書事故時間
SLO例
・証明書期限切れによる5xx/SSLエラー 0分/月
・TTFB p75 ≤ 200ms(主要地域)
・HSTS適用率 99.9% 以上(preload後は100%)6
ビジネス効果とROI試算
実務では、速度・信頼の改善がCVR・SEOの複合効果を生む。以下の簡易モデルで試算できる。
・追加収益/月 = 訪問数 × 単価 × (CVR_after − CVR_before)
・ROI(%) = (追加収益 − 導入コスト) / 導入コスト × 100
ケース: 月間200万訪問、単価¥1,200、TTFB短縮によりCVRが2.20%→2.35%(+0.15pt)。追加収益=2,000,000×1,200×0.0015=¥3,600,000/月。導入コスト(初期¥1,200,000 + 運用¥200,000/月)とすると、初月ROI= (3,600,000−1,400,000)/1,400,000 ≈ 157%。以降は運用のみでROI= (3,600,000−200,000)/200,000=1,700%。証明書自動更新で人的工数(例: 4h/月×¥10,000/h=¥40,000)も削減できる。
推奨仕様の要約表
| 領域 | 推奨 | 補足 |
|---|---|---|
| TLSバージョン | TLS1.3最小 | TLS1.2は互換のみ10 |
| 証明書 | ECDSA P-256 | RSA併用は古いUA向け7 |
| 失効確認 | OCSP stapling | Must-Stapleは要検証9 |
| HSTS | max-age=31536000; preload | preload申請6 |
| プロトコル | HTTP/2 + HTTP/3 | ALPN/Alt-Svc |
| 自動化 | ACME自動更新 | 期限監視/アラート |
トラブルとエラーハンドリングの勘所
・証明書期限切れ: 監視は「有効期限≤14日でWarn、≤7日でCritical」。自動更新失敗の再試行は指数バックオフ+人手通知。
・OCSP応答不可: staplingが落ちた場合に外部OCSPへフォールバックするとTTFBが悪化。モニタで即検知し復旧を優先9。
・0-RTT再実行: 書き込み系に適用しない(GETのみ)。リプレイ耐性のないエンドポイントでは無効化10。
導入期間の目安
中規模サイト(5〜10ドメイン)で、設計〜本番: 2〜3週間。内訳: 設計/監査3日、ステージング4日、計測/チューニング3日、段階リリース3日。CDN活用で短縮可。
まとめ:最小実装で最大のSEO/収益インパクトを
TLS1.3、HSTS、OCSP stapling、HTTP/2/3は、検索順位の微差に留まらず、TTFBとLCPを直接改善しCVRを押し上げる5,8,10。まずは301統合とTLS1.3強制、HSTSを有効化し、OCSP staplingとHTTP/3で再訪の0-RTTを取り込む。本文のコードをそのまま流用し、ベンチマーク表のSLOを自社のKPIに落とし込んでほしい。次の一手として、ACME自動化と期限監視をCI/CDに組み込み、計測ループ(k6/Lighthouse/リアルユーザーモニタリング)を定常化できるか。自社の現状で最もボトルネックな指標はどれか、今週1つだけ改善するとしたら何を選ぶか——その選択が次の四半期のCVRを決める。
参考文献
- Google Search Central Blog. HTTPS as a ranking signal (2014). https://developers.google.com/search/blog/2014/08/https-as-ranking-signal
- HTTP Archive. Web Almanac 2024 – Security. HTTPS adoption and usage. https://almanac.httparchive.org/en/2024/security
- Cloudflare Blog. HTTP/3 vs. HTTP/2 Performance and Adoption. https://blog.cloudflare.com/http-3-vs-http-2/
- web.dev (Google). Defining Core Web Vitals thresholds. https://web.dev/articles/defining-core-web-vitals-thresholds
- MDN Web Docs. Strict-Transport-Security. https://developer.mozilla.org/docs/Web/HTTP/Headers/Strict-Transport-Security
- Mozilla Wiki. Security/Server Side TLS — Recommended configurations. https://wiki.mozilla.org/Security/TLS_Configurations
- MDN Web Docs. Time to First Byte (TTFB). https://developer.mozilla.org/docs/Glossary/Time_to_first_byte
- RFC 8446. The Transport Layer Security (TLS) Protocol Version 1.3. https://www.rfc-editor.org/rfc/rfc8446
- Cloudflare Blog. High-reliability OCSP stapling. https://blog.cloudflare.com/high-reliability-ocsp-stapling/