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分 | 3 | SSOの本質と落とし穴 |
| 11-15分 | 4 | MFA/FIDO2/パスキー |
| 15-18分 | 5 | ログイン試行制限とレートリミット |
| 18-21分 | 6 | IPアドレス・ジオブロッキング |
| 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 | 企業・大学SSO | XMLベース、IdP/SP分離 | Shibboleth, ADFS |
| OAuth 2.0 | API認可 | 認証ではなく「認可」 | Google API |
| OpenID Connect | Web/モバイル認証 | 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 OTP | △ | ◎ | 低 | SIMスワップ攻撃 |
| 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以下になる。費用対効果は極めて高い。「完璧でないからやらない」は最悪の選択だ。
実装レイヤー
- WAF層(Cloudflare, AWS WAF):最も推奨。攻撃トラフィックを自社網に入れない
- LB/Nginx層:自社運用なら現実的
- アプリ層:最終防衛線、ログ目的なら有効
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層)
- ネットワーク層:VPN必須化/専用ネットワーク
- IP制限:固定IP or 踏み台サーバー経由のみ
- 経路の分離:管理画面用サブドメイン+クライアント証明書
- 認証強化:MFA必須、SSO連携、可能ならFIDO2強制
- 操作監査:全操作ログ+第三者レビュー
この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つの原則
- 認証は「層」で組む ― 単一技術に依存しない
- 単一障害点を避ける ― SSOもMFAも、落ちたときを想定する
- 属人化させない ― 手順書・自動化・監査で再現性を担保
- 経営判断は数字で行う ― 想定被害額 × 発生確率
- 現場で止まらない運用 ― 人が変わっても回る仕組み
経営層へのメッセージ
セキュリティ投資は「コスト」ではなく「事業継続のための保険」である。試験運営現場で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 公式ドキュメント
