講義資料 Webサイトの守り方

Webサイトの守り方 ― 認証・アクセス制御の全体設計

〜SSO・MFA・IP制限・管理画面防御まで、30分で「構造で勝つ」セキュリティ講義〜


0. はじめに(講義のゴール)

【ロジカル】

セキュリティを語るとき、多くの現場が「どの製品を入れるか」から議論を始める。

これは構造的に誤りである。

ファイアウォール一つ、MFA一つ、WAF一つ。それぞれは強力な道具だが、単独では必ず破られる。

重要なのは、それらをどう積み重ね、どう連動させるかという設計思想である。

本講義のスコープと前提

  • 対象:大学・試験運営現場のICT担当者、および意思決定を担う経営層
  • 前提:基本的なWeb技術(HTTP、Cookie、TLS)の理解
  • ゴール:30分後に、自組織のWebサイト防御を「構造図」として描けること

講義タイムテーブル(30分の内訳)

時間セクションテーマ
0-3分1攻撃者視点で守りを設計する
3-8分2認証の基礎 ― ID/PW・NIST準拠
8-11分3SSOの本質と落とし穴
11-15分4MFA/FIDO2/パスキー
15-18分5ログイン試行制限とレートリミット
18-21分6IPアドレス・ジオブロッキング
21-24分7管理画面の多層防御
24-26分8-9セッション管理・WAF活用
26-28分10監査ログ・インシデント対応
28-30分11-12ゼロトラストとまとめ

1. 攻撃者視点で守りを設計する

【クリティカル】

「うちは大した情報を持っていないから狙われない」

――この発言を、私はこの10年で数百回聞いてきた。そして、そう言った組織の約3割が、その後3年以内に何らかのインシデントを経験している。

「なぜそれを守るのか」という問いから始める

セキュリティ設計の出発点は、製品選定ではなく問いの設定である。

  • 何を守るのか(資産の特定)
  • 誰から守るのか(脅威アクターの特定)
  • どこが弱いのか(脆弱性の特定)

この3つが揃って初めて、リスクが定量化される。リスク = 資産価値 × 脅威の発生確率 × 脆弱性の深刻度である。

「うちは狙われない」の構造的誤り

現代の攻撃の大半は機械的・無差別である。攻撃者はGoogleで検索するように、脆弱なサーバーを自動スキャンしている。あなたの組織を「個別に狙う」のではなく、「たまたま脆弱だったから侵入する」のだ。

つまり、狙われるかどうかではなく、入りやすいかどうかが問題なのである。

多層防御(Defense in Depth)の図解┌─────────────────────────────────────────┐
│     運用層 :        監査ログ・教育・Runbook │
├─────────────────────────────────────────┤
│    アプリ層 :         認証・認可・入力検証 │
├─────────────────────────────────────────┤
│     認証層 :         MFA・SSO・パスワード強度 │
├─────────────────────────────────────────┤
│ ネットワーク層 :         WAF・IP制限・TLS │
└─────────────────────────────────────────┘

一つの層が破られても、次の層で止める。これが構造で勝つということだ。


2. 認証の基礎 ― パスワードはなぜ弱いか

【ロジカル】

ID/パスワード認証の限界

パスワード認証は1960年代に発明された技術であり、設計当初からネットワーク経由の攻撃を想定していない

それを現代のインターネットで使い続けていること自体が、構造的負債である。

主な攻撃手法:

  • ブルートフォース:総当たり
  • 辞書攻撃:よく使われる単語リストで試行
  • クレデンシャルスタッフィング:他サイトから漏れたID/PWを流用
  • パスワードリスト攻撃:流出DBを使った効率的攻撃

NIST SP 800-63B における最新ガイドライン

2017年以降、NISTは従来の常識をひっくり返した。皆さんの組織のパスワードポリシー、まだ古い常識のままではないだろうか。

古い常識NIST最新ガイドライン
90日ごとに変更定期変更は推奨しない
大文字・数字・記号必須複雑性要件は不要
8文字以上最低8文字、推奨は長いパスフレーズ
ヒント機能ありヒント禁止
漏洩パスワードDBとの照合必須

なぜ定期変更が「不要」になったのか。強制的な定期変更は、ユーザーに「Password1!」→「Password2!」という安易な変更を促し、かえって弱くなることが研究で明らかになったからである。

実装:bcryptによる安全なハッシュ化

# パスワードハッシュ化の例(bcrypt)
import bcrypt

# 登録時
password = "correct horse battery staple"
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

# 検証時
if bcrypt.checkpw(password.encode(), hashed):
    print("認証成功")

断言する:MD5やSHA-1で生パスワードを保存している組織は、即刻bcrypt、Argon2、scryptへ移行すべきである。これは「検討事項」ではなく「最低条件」だ。


3. SSO(シングルサインオン)の本質

【ロジカル】

SSOとは何か/何ではないか

SSOは「一度ログインすれば複数サービスを使える仕組み」だが、それは結果に過ぎない。本質は、認証責務をIdP(Identity Provider)に集約し、各サービス(SP)から認証ロジックを取り除くことにある。

主要プロトコル比較表

プロトコル用途特徴採用例
SAML 2.0企業・大学SSOXMLベース、IdP/SP分離Shibboleth, ADFS
OAuth 2.0API認可認証ではなく「認可Google API
OpenID ConnectWeb/モバイル認証OAuth上に構築Google, Microsoft
Kerberos社内ADチケットベースActive Directory

クリティカルな注意:OAuth 2.0は「認可」のプロトコルであって、認証ではない。「OAuthでログイン」と表現するのは厳密には誤りで、認証用途ならOpenID Connectを使うべきだ。

IdP/SPの責務分離

  • IdP:誰であるかを証明する(認証)
  • SP:何ができるかを決める(認可)

この分離が崩れると、各SPがバラバラに認証を実装し、MFAの有無や強度がサービスごとに違うという最悪の状態になる。

SSOのリスク:単一障害点

SSO導入の最大のリスクは、IdPが落ちれば全サービスが止まることだ。だからこそ、IdPは:

  • 冗長化必須
  • 高可用性設計(99.95%以上)
  • フォールバック認証経路の準備

大学現場でのShibboleth/学認

国内大学の多くは学認(GakuNin)フェデレーションに参加している。これは大学間SSO基盤であり、適切に設定すれば研究者の利便性とセキュリティを両立できる。導入していない大学は、まず参加検討から始めるべきだ。


4. 多要素認証(MFA)と二要素認証(2FA)

【ロジカル】

「知識・所有・生体」3要素の整理

認証の3要素は以下のとおりである。

  • 知識(Something you know):パスワード、PIN
  • 所有(Something you have):スマホ、ハードウェアキー
  • 生体(Something you are):指紋、顔、虹彩

2FAは「2つの異なる要素」、MFAは「2つ以上の要素」。つまり2FAはMFAの部分集合だ。「パスワード+秘密の質問」は同じ知識要素なので、2FAではない。この点を誤解している現場は驚くほど多い。

各方式の比較

方式強度利便性コスト弱点
SMS OTPSIMスワップ攻撃
TOTP(Google Authenticator等)端末紛失、フィッシング可
プッシュ通知(Duo, MS Authenticator)MFA疲労攻撃
FIDO2 / WebAuthn / パスキー◎◎中〜高端末依存
ハードウェアキー(YubiKey)◎◎紛失リスク

なぜFIDO2が最強なのか

FIDO2/WebAuthnは、公開鍵暗号方式 × ドメインバインディングを採用している。これにより:

  • パスワードがそもそも存在しない(漏洩しようがない)
  • フィッシングサイトでは認証が成立しない(ドメインが違うと鍵が動かない)
  • サーバー側に秘密情報が保存されない

断言する:今後パスワードはFIDO2/パスキーに置き換わる。経営層は「いつ移行するか」を今から議論すべきだ。

MFA疲労攻撃とアダプティブMFA

攻撃者がプッシュ通知を連続送信し、ユーザーがうっかり承認するのを待つ攻撃。2022年のUber侵害の主要因である。

対策はアダプティブMFA

  • 普段と違うIPからのアクセス → MFA要求
  • 同一拠点からの通常アクセス → MFAスキップ可
  • 海外IP・深夜帯 → 強い認証要求

リスクベースで認証強度を動的に変える――これが現代のMFAだ。


5. ログイン試行回数の制限とレートリミット

【クリティカル】

アカウントロック vs レートリミット

「5回失敗でアカウントロック」

――よく見る設定だが、これは攻撃者へのプレゼントになり得る。なぜなら、攻撃者が任意のユーザーIDで5回わざと失敗させれば、正規ユーザーを締め出すDoS攻撃が成立するからだ。

正しい設計は:

  • IPベースのレートリミット(攻撃元を絞る)
  • ユーザーベースの指数的バックオフ(失敗ごとに待ち時間を倍に)
  • ロックではなく遅延(応答時間を伸ばすことで自動化を妨害)

実装パターン

  • 固定窓:1分間に5回まで(実装簡単、境界で2倍叩ける弱点)
  • スライディングウィンドウ:直近60秒で5回まで(推奨)
  • トークンバケット:バースト許容しつつ平均レート制御

CAPTCHA・reCAPTCHA v3・hCaptchaの位置づけ

CAPTCHAは「最初に出す」のではなく「怪しいときに出す」のが現代流。

reCAPTCHA v3はスコアベースで、ユーザー体験を損なわずにBotを弾ける。

Nginx設定例

# Nginx でのレートリミット例
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

server {
  location /login {
    limit_req zone=login burst=3 nodelay;
    limit_req_status 429;
    proxy_pass http://backend;
  }
}

アプリケーション層(Flask-Limiter)

# Flask-Limiter 例
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(app, key_func=get_remote_address)

@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
    ...

レートリミットは「ネットワーク層」と「アプリ層」の両方に入れる。片方だけでは、迂回経路が必ず存在する。


6. IPアドレス制限(ジオブロッキング含む)

【ラテラル】

許可リスト方式 vs 拒否リスト方式

  • 許可リスト:指定IP以外を全拒否(高セキュリティ、運用負荷高)
  • 拒否リスト:問題IPだけ拒否(運用楽、抜け穴多い)

管理画面なら許可リスト一択。一般公開ページなら拒否リスト+WAF。

国別IP制限(GeoIP)の有効性と限界

「日本以外からのアクセスを全部ブロックすれば安全」――半分正しく、半分誤りだ。

正しい点

  • 攻撃ノイズの大半(ボット、自動スキャン)は海外IPから来る
  • ログがクリーンになり、本当に怪しいものが見えやすくなる

誤りな点

  • VPN・Tor・住宅プロキシで容易に回避される
  • 国内のクラウドVMから攻撃されれば素通り

結論:ゼロにはならないが、ノイズは1/10以下になる。費用対効果は極めて高い。「完璧でないからやらない」は最悪の選択だ。

実装レイヤー

  1. WAF層(Cloudflare, AWS WAF):最も推奨。攻撃トラフィックを自社網に入れない
  2. LB/Nginx層:自社運用なら現実的
  3. アプリ層:最終防衛線、ログ目的なら有効

Nginx + GeoIP2 設定例

# 日本IP以外を拒否(GeoIP2モジュール)
map $geoip2_data_country_iso_code $allowed_country {
  default no;
  JP yes;
}

server {
  if ($allowed_country = no) {
    return 403;
  }
}

学校での試験実践例

指定IPのみを許可する運用は極めて有効だ。例えば大学の試験開始時間に許可IPリストを動的に更新し、終了後に元に戻す。これにより、外部からの不正受験・なりすましのリスクを大幅に削減できる。

これは現場で実際に効いている手法である。


7. 管理画面(/admin等)へのアクセス制限

【クリティカル】

「管理画面は隠す」は対策ではない

/admin/secret-admin-x7k9 に変える――これを「セキュリティ対策」と呼ぶ現場が今もある。これは対策ではなく気休めだ

攻撃者は数秒でディレクトリを発見する。

セキュリティ・バイ・オブスキュリティ(隠蔽による安全)は、多層防御の一部としてのみ意味を持つ。それ単体では何の防御にもならない。

多層防御の具体例(5層)

  1. ネットワーク層:VPN必須化/専用ネットワーク
  2. IP制限:固定IP or 踏み台サーバー経由のみ
  3. 経路の分離:管理画面用サブドメイン+クライアント証明書
  4. 認証強化:MFA必須、SSO連携、可能ならFIDO2強制
  5. 操作監査:全操作ログ+第三者レビュー

この5層が揃って初めて、管理画面は「現実的に守られている」と言える。

Nginx設定例(クライアント証明書 + IP制限)

# 管理画面のクライアント証明書 + IP制限
location /admin {
  allow 203.0.113.0/24;
  deny all;

  ssl_verify_client on;
  ssl_client_certificate /etc/nginx/ca.crt;

  proxy_pass http://admin-backend;
}

ラテラル発想:「管理画面そのものをWebに置かない」

ここで発想を飛ばそう。そもそも管理画面をWebに公開する必要があるのか?

  • SSH踏み台 + CLI運用:Webを介さず、SSH経由でしか管理できない設計
  • ZTNA(Zero Trust Network Access):Cloudflare Access、Tailscale等で、認証済みデバイスからしか到達できない経路を作る
  • Bastion Host:AWS Systems Manager Session Manager等、ブラウザを介さない管理経路

「Webで管理する」のは便利だが、便利さは攻撃面の広さと裏返しだ。便利さと安全のトレードオフを意識的に選ぶ――これが構造で勝つ思考である。


8. セッション管理とCookieの守り

【ロジカル】

認証を突破されなくても、セッションを盗まれれば終わりだ。ログイン後の防御も同じくらい重要である。

セッションIDの必須要件

  • 128bit以上のエントロピー(推測不能)
  • サーバー側でランダム生成(クライアント入力を信用しない)
  • ログイン成功時に必ず再生成(セッション固定化対策)
  • 適切な有効期限(アイドルタイムアウト+絶対タイムアウト)

Cookie属性の必須3点セット

Set-Cookie: SESSIONID=xxx; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600
  • Secure:HTTPS経由のみ送信
  • HttpOnly:JavaScriptから読めない(XSS対策)
  • SameSite=Strict|Lax:CSRF対策

この3点が揃っていないCookieは、現代では不合格である

ログアウト設計

  • サーバー側でセッション無効化(クライアント削除だけでは不十分)
  • 全端末ログアウト機能(パスワード変更時など)
  • セッションテーブルにユーザーIDを持ち、一括失効可能にする

9. WAF・CDN・Bot対策の活用

【ラテラル】

自前で守る vs 外部サービスに任せる

「セキュリティは内製すべき」

――半分正しいが、半分は思考停止だ。

  • Cloudflare:DDoS、WAF、Bot対策を月数千円から
  • AWS WAF:AWS環境なら統合容易
  • Akamai:大規模・高要件向け

これらは世界中の攻撃データを学習している。自社単独では絶対に到達できない検知精度を持つ。

「自社で頑張らない」という選択

自社のセキュリティ担当が3人しかいない組織が、Cloudflareの数千人のセキュリティチームと張り合う必要はない。任せられる部分は任せ、自社は自社にしかできないこと(業務ロジックの守り)に集中する

――これがラテラル思考だ。

Bot Management

  • 良性Bot:Googlebot、Bingbot(許可)
  • 悪性Bot:スクレイパー、攻撃Bot(拒否)
  • 中間:価格比較サイト等(ポリシー判断)

User-Agentだけでなく、振る舞いベースで判定するのが現代流である。


10. 監査ログとインシデント対応

【ロジカル】

ログに何を残すべきか(5W1H)

  • When:タイムスタンプ(NTP同期必須)
  • Who:ユーザーID、IPアドレス、User-Agent
  • What:操作内容、対象リソース
  • Where:エンドポイント、サーバー
  • Why:可能なら理由(管理画面ならコメント欄)
  • How:成功/失敗、応答コード

改ざん防止

ログは攻撃者が最初に消そうとする証拠だ。だからこそ:

  • WORM(Write Once Read Many)ストレージ
  • 外部SIEM転送(Splunk、Elastic、Datadog)
  • アクセス権の分離(管理者でも消せない設計)

インシデント対応のRACI

事件が起きてから「誰が判断するか」を議論していては遅い。事前に決めておくのだ。

  • Responsible:実際に対応する人
  • Accountable:最終責任者(経営層)
  • Consulted:相談先(法務、広報)
  • Informed:報告先(顧客、監督官庁)

Runbook化

「起きてから慌てない仕組み」――それがRunbookだ。最低限、以下のシナリオは文書化しておくこと:

  • 不正ログイン検知時
  • DDoS発生時
  • 個人情報漏洩疑い時
  • ランサムウェア感染時

現場で止まらない運用とは、人が変わっても同じ品質で対応できることを意味する。


11. ゼロトラストへの移行(次の30分の予告)

【ラテラル】

「社内=安全」の終焉

従来のセキュリティは「境界防御」――社内ネットワークは安全、社外は危険、という前提だった。クラウド・リモートワーク・BYODの時代、この前提は完全に崩壊した

BeyondCorpの考え方

Googleが提唱したゼロトラストの中核思想:

  • すべてのアクセスを認証・認可する
  • ネットワーク位置を信頼しない
  • IDとデバイスが新しい境界である

大学・試験運営におけるゼロトラスト

  • 学外からのアクセスでも、社内同等の利便性
  • 学内ネットワークでも、認証なしでは何もできない
  • デバイス証明書+ユーザー認証+振る舞い分析

これは次の30分で詳しく解説するテーマだが、今日のうちに「方向性」だけ覚えておいてほしい


12. まとめ ―

【ロジカル】

5つの原則

  1. 認証は「層」で組む ― 単一技術に依存しない
  2. 単一障害点を避ける ― SSOもMFAも、落ちたときを想定する
  3. 属人化させない ― 手順書・自動化・監査で再現性を担保
  4. 経営判断は数字で行う ― 想定被害額 × 発生確率
  5. 現場で止まらない運用 ― 人が変わっても回る仕組み

経営層へのメッセージ

セキュリティ投資は「コスト」ではなく「事業継続のための保険」である。試験運営現場で1日のシステム停止が起きれば、損害は数千万円規模になる。月数十万円のWAF費用は、その保険として極めて合理的だ。

現場担当者へのメッセージ

完璧を目指して動けなくなるな。今日できる1つを積み上げる。レートリミットを1行追加する、MFAを管理者だけでも有効化する、ログを外部に転送する――小さな積み重ねが、構造を作る。


30分後のアクションチェックリスト

  • [ ] 管理画面のIP制限・MFA・監査ログの3点が揃っているか確認
  • [ ] パスワードポリシーをNIST SP 800-63B準拠に更新
  • [ ] レートリミットを /login および /api/* に設定
  • [ ] FIDO2/パスキー導入の検討開始(まず管理者から)
  • [ ] インシデント対応Runbookの存在と最新性を確認
  • [ ] Cookie3属性(Secure/HttpOnly/SameSite)の設定確認
  • [ ] 外部WAF(Cloudflare等)の導入検討
  • [ ] 監査ログの外部SIEM転送設定

参考文献

  • NIST SP 800-63B Digital Identity Guidelines
  • OWASP Top 10 (2021)
  • OWASP Authentication Cheat Sheet
  • 総務省「クラウドサービス利用のための情報セキュリティマネジメントガイドライン」
  • IPA「安全なウェブサイトの作り方」
  • FIDO Alliance 公式ドキュメント



HOMEへ戻る