TT Lab
はじめる
学ぶ 学習パス コース

企業認証の連携

身分証とカードキー — 認証方式の地形図

TT Labで続きを見る

一言でいうと

SIで認証が難しい理由は、認証が難しいからではなく、すでに認証の仕組みがあるからであり、私たちのシステムはその間に割り込まなければなりません。

なぜSIで認証が難しいのか

新規システムを1つ作るときに、認証は難しくありません。ID/パスワードをDBに入れて終わりです。SIで難しい理由は、すでに認証の仕組みがあるからです。

顧客企業には、たいてい次のようなものがすでにあります。

作るシステムは、この間に入り込む必要があります。そのため、「ログインを付けてください」という一行の要件が、実際には2か月がかりの仕事になります。

混同してはいけない4つ

名前 何か ひとことで例えると
LDAP ユーザー・組織の情報を保持するディレクトリプロトコル 電話帳
SAML 2.0 XMLベースの認証連携(SSO)プロトコル 紙の身分証
OIDC OAuth 2.0の上に載せた認証連携プロトコル デジタル身分証
OAuth 2.0 認可(権限委譲)のフレームワーク ホテルのカードキー

最も重要な区別は、最後の2つです。

OIDC / SAMLは身分証の発行で、OAuth 2.0はホテルのカードキーです。 カードキーは「このカードで305号室とジムのドアを開けられる」と言うだけで、 所持者が誰なのかは教えてくれません。

ここから有名なアンチパターンが生まれます。アクセストークンでログインを判断すること。アクセストークンには、「誰に発行したのか」の検証根拠(aud)がないか、緩いです。別のアプリ向けに発行されたトークンを持ってきて貼り付けると通ってしまう、トークン置換攻撃が可能です。ログインの判断はIDトークンで行う必要があります。

LDAPは認証プロトコルなのか

半分だけ正解です。LDAPはディレクトリ照会プロトコルで、bind操作でパスワード検証ができます。そのため、「LDAP認証」という言葉が成り立ちます。しかしそれは、アプリケーションがパスワードを直接受け取ってLDAPに問い合わせる方式です。つまりSSOではありません。アプリごとにログイン画面が別々にあります。

実務では、次のように組み合わせます。

[사용자] --로그인--> [IdP(Keycloak 등)] --bind/조회--> [AD / LDAP]
     |                      |
     |<---- ID 토큰 --------|
     v
[우리 시스템]  ← 토큰만 검증. 비밀번호를 절대 보지 않는다

このコードブロックの韓国語は、角括弧の中が順にユーザーと私たちのシステムを表し、コメントは、トークンだけを検証し、パスワードは決して見ない、という意味です。

私たちのシステムがパスワードを見ないことが、核心的な利点です。パスワードを見なければ、漏洩事故の当事者になりません。

レガシーヘッダー認証: 韓国の大企業・金融イントラネットの現実

15年前のWebSSO製品(SiteMinder系)は、次のように動作します。Webサーバーにエージェントを入れ、認証が終わるとHTTPヘッダーにユーザー情報を載せてバックエンドのアプリケーションに渡します。

SM_USER: jdoe
SM_USERDN: uid=jdoe,ou=people,dc=example,dc=com
SM_USERGROUPS: hr-staff^payroll-admin

バックエンドのJavaアプリは、フィルターでrequest.getHeader("SM_USER")を読んでログイン処理をします。簡単で、アプリの修正がほとんどなく、そのため数百のアプリがこの方式で接続されています。

問題は明確です。アプリがヘッダーを無条件に信頼するということは、エージェントを迂回してアプリに直接到達できる経路が1つでもあれば、即座に認証バイパスになるということです。

curl -H "SM_USER: ceo" -H "SM_USERGROUPS: payroll-admin" \
     http://hr-app.internal:8080/hr/payroll/list

この1行が通用するシステムが、実際に存在します。そのため、必要な統制が3つあります。

  1. ネットワーク分離: アプリのポートに、ゲートウェイ以外からはアクセスできないようにします
  2. エッジでのヘッダー削除: 外部から入ってきたSM_*ヘッダーを無条件に削除し、新しく設定し直します
  3. ゲートウェイとアプリ間の相互認証: mTLSまたは共有シークレットを使います

そして、これは昔の話ではありません。現代のリバースプロキシ認証(oauth2-proxyなど)も、まったく同じ構造です。ヘッダーで身元を渡すすべての構成に、同じ要求が付いて回ります。

補足として、ヘッダー方式にはパースの落とし穴もあります。SM_USERGROUPSの区切り文字はキャレット(^)です。カンマだと仮定してパースするコードは、グループを1つとして認識してしまい、権限がまるごと消えます。マイグレーションのインベントリを作るときは、ヘッダー名だけでなく値の形式まで調査する必要があります。

何をいつ使うのか

状況 選択
新規のWeb/モバイルで、自分たちでIdPを制御できる OIDC(Authorization Code + PKCE)
相手が大企業/公共機関で、すでにSAMLのIdPがある SAML 2.0
社内アカウント情報の照会・グループ判定だけが必要 LDAP照会(認証はIdPに委譲)
サーバー間通信(バッチ、連携) OAuth 2.0 client_credentials
15年前のアプリ100個をすぐには直せない プロキシベースのヘッダー注入+上記の統制3種

最後の行がSIの現実です。理想的な答えはすべてOIDCですが、アプリを直せない状況で、実際に機能する答えが必要です。そのようなときは、プロキシがSSOを代わりに処理し、アプリにはヘッダーで渡す構成を使います。ただし、上の3つの統制を必ず一緒に設定します。

最後に、バッチとサービスアカウントを忘れてはいけません

SSO移行プロジェクトで、繰り返し起きる事故があります。月末/四半期末にだけ発生する認証失敗です。

原因は、たいてい次のとおりです。夜間バッチや連携プログラムが、人のようにログイン画面を真似して認証を通過していました。人のアカウントだけを移行対象にすると、これを見落とします。そして、月末にだけ動くバッチなので、移行後3週間は何の問題もないまま、ある日起きます。

インベントリ調査に、必ず入れるべき質問があります。

「人ではないもののうち、この認証を通過しているものはありますか」

答えが「ない」なら、十中八九、まだ見つけていないだけです。

現場での姿

「ログインを付けてください」という一行の要件が2か月がかりの仕事になる過程は、たいてい次のように進みます。

まず、どこに接続するかが決まっていません。人事システムが人の元データですが、ログインはADが受け、事実上のゲートウェイはグループウェアで、最近追加したIdPも別にあります。「うちの会社のアカウント」が何を指すのか、担当者ごとに違う答えが返ってきます。

次に、レガシーヘッダー認証に出会います。前段のWebSSO製品がユーザーIDをHTTPヘッダーに載せて渡す方式ですが、15年間動いていて、変えられません。このとき、必ず確認すべきことが1つあります。そのヘッダーを外部から直接入れられるかです。プロキシがヘッダーを上書きしなければ、誰でも他人のIDで入れてしまいます。

最後に、バッチとサービスアカウントが抜け落ちます。人のアカウントだけを設計してサービスインしたあと、夜間バッチがどんな資格で接続するかを、そのときになって決めることになります。