現場のエンジニア諸君、日々のアラート対応とデプロイで疲弊していないか?
今日は「パスワードさえ強固にすればいい」という幻想を捨ててもらう。ID/パスワードが漏洩するのは、もはや「防げない前提の事故」だ。重要なのは、「漏れたIDが使われた瞬間に、いかにして無力化するか」という出口戦略に他ならない。
今回は、Entra ID(旧Azure AD)の条件付きアクセス(Conditional Access)を用い、攻撃者が喉から手が出るほど欲しがる「セッションの乗っ取り」すら跳ね返す、実戦的な防御策を解説する。
なぜ「リスクベース認証」が必要なのか:攻撃者の視点
昨今の攻撃者は、フィッシングでセッションCookieを盗み取る「AiTM(Adversary-in-the-Middle)」攻撃を多用している。多要素認証(MFA)を突破するこの手法に対し、従来の「場所とパスワード」だけの防御は紙の盾だ。
攻撃者は、あなたの会社の社内ネットワークIPを偽装し、盗んだセッションを使って深夜にログインを試みる。このとき、「デバイスが準拠しているか」「サインインリスクは高くないか」を動的に評価する条件付きアクセスが組まれていなければ、防御側はなすすべもなく侵入を許す。
実践:条件付きアクセスの設計指針
条件付きアクセスは「誰が、どこで、何を使って、どのリスク状態で」アクセスしているかを判断するロジックだ。以下のポリシーを構成することで、攻撃者のコストを跳ね上げろ。
1. 必須の防御レイヤー:リスクベースの強制MFA
「サインインリスク」が中以上の場合、たとえID/パスワードが正しくても、必ずMFAを再要求する。
- 割り当て: 全ユーザー
- 対象アプリ: 全クラウドアプリ
- 条件:
- サインインリスク: 「高」「中」
- デバイスプラットフォーム: すべて
- アクセス制御: 「アクセスの許可」→「多要素認証を要求する」
2. コンプライアンスによる防御
未管理のデバイスからのアクセスを拒否または制限する。
- 条件: デバイスの状態「準拠しているとしてマーク済み」を必須とする。
- これにより、Intuneで管理されていない私物端末からのアクセスを遮断し、攻撃者がバックドアとして利用する「個人のPC」を排除できる。
エンジニアのための自動化:Graph APIによる監視コード
GUIでの設定は基本だが、運用の「冪等性」を保つにはコードによる管理が必要だ。Azure ADのポリシー状態を定期的にチェックするPythonスクリプト例を置いておく。
# 必要ライブラリ: pip install msgraph-sdk
from msgraph import GraphServiceClient
from azure.identity import DefaultAzureCredential
# 認証情報の取得
credential = DefaultAzureCredential()
client = GraphServiceClient(credential)
async def check_conditional_access_policies():
# 現在設定されている条件付きアクセスルールを取得して出力する
policies = await client.conditional_access.policies.get()
for policy in policies.value:
print(f"ポリシー名: {policy.display_name}")
print(f"状態: {policy.state}")
# もしポリシーが無効化されていたら警告を出す(運用監視の自動化)
if policy.state == "disabled":
print(f"【警告】ポリシー {policy.display_name} が無効になっています!")
# 実際の運用では、これをGitHub ActionsやAzure Functionsで定期実行し、
# ポリシーが改ざんされたらSlackにアラートを飛ばす仕組みにするのが鉄則。
Webアプリ側で実装すべき「ラストワンマイル」の防御
条件付きアクセスでネットワークを固めても、アプリ側のコードが甘ければ意味がない。特にセッション管理は盲点だ。例えば、PHPでセッションを扱う際、php.iniの設定だけで満足していないか?
<?php
// セッションクッキーを強固にするための設定
// これを怠ると、セッションハイジャックが容易になる
ini_set('session.cookie_httponly', 1); // JSからのセッションID読み取りを不可にする
ini_set('session.cookie_secure', 1); // HTTPS接続のみでクッキーを送信
ini_set('session.use_strict_mode', 1); // 攻撃者が生成したセッションIDの拒否
session_start();
// さらに、IPアドレスやユーザーエージェントをセッションに紐付け、
// 変化した場合は強制的に破棄するロジックを実装せよ
if (!isset($_SESSION['user_agent'])) {
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
} elseif ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
session_regenerate_id(true); // セッションIDを再生成して無効化
session_destroy();
}
?>
最後に:防御は「多層」でなければならない
諸君、条件付きアクセスは万能ではない。攻撃者は常に「ポリシーの穴」を探している。だからこそ、システムを設計する際は「ゼロトラスト」を合言葉にしろ。
1. Entra IDの条件付きアクセスで、怪しいアクセスを入り口で弾く。
2. Intuneでデバイスを管理し、箱の中身をクリーンに保つ。
3. アプリケーションコードで、セッションの寿命と整合性を厳格に管理する。
これら全てを組み合わせて初めて、寝ている間に会社のデータが流出するような最悪の事態を防げる。泥臭い作業だが、これがプロのエンジニアの仕事だ。明日から自分の管理する環境のポリシーを再確認してくれ。健闘を祈る。
コメント