社内のポータルや業務システムを開くと、パスワードを聞かれずにそのまま入れることがあります。プロキシを通ってインターネットに出るときも、利用者は何も入力していないのに、プロキシの側では「だれが通ったか」が記録されています。これを支えているのが統合 Windows 認証です。Windows にサインインしたときの情報を使い、Kerberos や NTLM で Web サーバやプロキシに自分を証明します。
「フォワードプロキシとリバースプロキシの違い」の記事では、プロキシが 407 という応答で認証を求め、PC が認証情報を付けて送り直す流れを紹介しました。この記事では、その中身を詳しく見ていきます。Web サーバ(401)とプロキシ(407)で、Kerberos と NTLM がどのように HTTP のヘッダに乗って流れるのかを図で説明し、HTTP の SPN、ブラウザが自動でサインインする条件、よくあるトラブルの調べ方までをまとめます。
- HTTP の認証のしくみと、401(Web サーバ)と 407(プロキシ)の違い
- Negotiate で Kerberos と NTLM がどのように流れるか
- HTTP の SPN の決まり方と、IIS でチケットを開くアカウント
- ブラウザが自動でサインインする条件と、よくあるトラブルの調べ方
統合 Windows 認証とは
統合 Windows 認証(Integrated Windows Authentication、IWA)は、Windows にサインインした利用者の資格情報を使って、HTTP の認証を自動で済ませるしくみです。IIS では「Windows 認証」という名前で設定します。
ブラウザは、Kerberos や NTLM の処理を自分では行いません。Windows の SSPI という窓口を呼び出し、Negotiate に Kerberos と NTLM のどちらを使うかを選ばせます。チケットや応答のデータは LSASS が作り、ブラウザはそれを HTTP のヘッダに入れて送るだけです。SSPI と Negotiate の役割は「LSASS・SSPI・Negotiateとは?」の記事で説明しています。
利用者から見ると「パスワードを聞かれない」だけですが、裏では HTTP の要求と応答が何回かやり取りされています。まずは、その土台になる HTTP の認証のしくみから見ていきます。
HTTP の認証のしくみ:401 と 407
HTTP の認証は、「断る → 方式を伝える → 答えを付けて送り直す」という流れで進みます。認証を求めるのが Web サーバかプロキシかで、使う番号とヘッダの名前が変わります。
| 項目 | Web サーバ | プロキシ |
|---|---|---|
| 断るときの番号 | 401 Unauthorized | 407 Proxy Authentication Required |
| 方式を伝えるヘッダ | WWW-Authenticate | Proxy-Authenticate |
| 答えを入れるヘッダ | Authorization | Proxy-Authorization |
| ヘッダの行き先 | 途中のプロキシは書き換えず、Web サーバまで届ける | 認証を求めたプロキシが使い、その先へは送らない |
方式を伝えるヘッダには、「Negotiate」「NTLM」「Basic」などの方式の名前が入ります。複数の方式に対応しているときは、ヘッダを複数並べて返します。クライアントは、その中から使える方式を選んで答えます。
Web サーバの認証とプロキシの認証は、別々に行われます。プロキシの認証を通ったあとに、Web サーバでもう一度認証を求められることもあります。
Basic は、ユーザー名とパスワードを base64 にしてヘッダに入れる方式です。base64 は暗号ではないので、HTTP のままではパスワードがそのまま読めてしまいます。Basic を使うなら TLS(HTTPS)が必須です。Negotiate(Kerberos・NTLM)はパスワードそのものを送りませんが、HTTP の本文までは守らないので、Web サイトは HTTPS で公開するのが基本です。
Negotiate の流れ:Kerberos のとき
統合 Windows 認証では、サーバは「Negotiate」という方式を伝えます。Negotiate は、HTTP の上で Kerberos や NTLM を使うための方式で、RFC 4559 に書かれています。Kerberos を使えるときの流れは次のとおりです。
- ブラウザは、まず認証のヘッダを付けずに要求を送ります。WEB01 は 401 と「WWW-Authenticate: Negotiate」を返します。
- ブラウザは、URL から SPN(ここでは HTTP/web01.corp.example.com)を組み立て、SSPI を通して DC にサービスチケットを頼みます。
- もらったチケットを base64 にして「Authorization: Negotiate …」に入れ、同じ要求を送り直します。
- WEB01 は、自分の鍵でチケットを開いて利用者を確かめ、ページを返します。
Kerberos では、Web サーバはチケットを自分の鍵で確かめられるので、NTLM のように認証のたびに DC へ答えを確かめてもらう必要はありません。チケットの中には利用者の所属グループ(PAC)も入っているので、Web サーバはその情報でアクセスを許すかどうかを決められます。Kerberos そのものの流れは「Kerberos(ケルベロス)認証とは?」の記事で説明しています。
Negotiate の流れ:NTLM のとき
SPN が見つからないなど Kerberos を使えないときは、Negotiate の中で NTLM が選ばれます。NTLM は3通のメッセージでやり取りするので、HTTP の往復も増えます。
NTLM では、Web サーバはチャレンジへの答えが正しいかを自分では確かめられず、DC に問い合わせます(パススルー認証)。NTLM のしくみは「NTLM認証とは?」の記事で説明しています。
NTLM は「接続」に結び付く
HTTP はふつう、要求ごとに独立しています。しかし NTLM の3通は、同じ TCP 接続の上で行う必要があります。2通目のチャレンジは、その接続に結び付けて覚えられているからです。途中で接続が切れたり、別の接続に移ったりすると、NTLM は最初からやり直しになります。Keep-Alive で接続を保つことが前提の方式です。
認証が済んだあとも、IIS は既定でその接続を「認証済み」として扱い、同じ接続の次の要求では NTLM をくり返しません。
ヘッダを見て Kerberos か NTLM かを見分ける
開発者ツールやパケットキャプチャで Authorization ヘッダを見ると、どちらが使われたかが分かります。中身は base64 なので、先頭の文字に特徴があります。
| Authorization ヘッダの先頭 | 意味 |
|---|---|
Negotiate YII… など Y で始まる | SPNEGO の形のトークン。Kerberos のチケットが入っていることが多い |
Negotiate TlRMTVNTUAAB… | NTLM の1通目(中身は「NTLMSSP」で始まる) |
Negotiate TlRMTVNTUAAD… | NTLM の3通目(チャレンジへの答え) |
「TlRMTVNTUAA」は、「NTLMSSP」という文字列を base64 にしたものです。これが見えたら NTLM が使われています。
プロキシでの統合 Windows 認証(407)
プロキシの認証も、使うヘッダが変わるだけで、流れは Web サーバと同じです。HTTPS のサイトを見るときは、ブラウザがプロキシに CONNECT を送り、その段階で認証を求められます。
ここで大事なのは、チケットはプロキシのためのものだということです。SPN は、開こうとしているサイト(www.example.com)ではなく、ブラウザに設定されたプロキシの名前から作られます。図6なら HTTP/proxy01.corp.example.com です。そのため、次の点がそろっている必要があります。
- PAC ファイルやプロキシの設定で、プロキシを FQDN(名前)で指定している
- その名前の SPN(HTTP/proxy01.corp.example.com)が、プロキシが使うアカウントに登録されている
- プロキシ製品の側に、そのアカウントの鍵(キータブなど)が設定されている
プロキシを IP アドレスで指定すると、Windows は既定で Kerberos を使わず、NTLM に戻ります。プロキシの SPN、DNS の名前、ブラウザの許可リストが同じ名前を指していることを確かめてください。プロキシ側の設定方法は製品ごとに違うので、製品の手順に従います。
NTLM(Negotiate の中の NTLM も含む)は複数回の往復で認証するので、そのあいだプロキシは 407 と次のトークンを返します。407 が出ているだけで失敗とは限りません。同じ 407 がくり返され、やり取りが先に進まないときが失敗です。
プロキシを挟んで Web サーバに認証するとき
HTTP のサイト(暗号化なし)をプロキシ経由で開き、その Web サーバが統合 Windows 認証を求める場合は、プロキシの動きにも注意が必要です。NTLM は接続に結び付くので、プロキシは「PC からプロキシへの接続」と「プロキシから Web サーバへの接続」を1対1で結び付けておかなければなりません。
プロキシが途中で Web サーバへの接続を張り直すと、NTLM の3通が別々の接続に分かれて失敗します。また、認証済みの Web サーバへの接続を別の PC の要求に使い回すと、Web サーバはその PC を最初の利用者として扱ってしまいます。RFC 4559 も、プロキシは認証済みの接続を別のクライアントと共有してはいけないとしています。HTTPS(CONNECT)なら、通り道は PC とサイトのあいだの TLS なので、この問題は起きにくくなります。
HTTP の SPN
Kerberos を使うには、ブラウザが組み立てた SPN と、AD に登録された SPN が一致している必要があります。ブラウザ(Edge の既定)は、次の順番で SPN を決めます。
| 決まり | 内容 |
|---|---|
| サービスの種類 | http でも https でも HTTP/ |
| 別名(CNAME) | DNS で CNAME をたどり、本当の名前(A レコードの名前)で SPN を作る。Edge では「DisableAuthNegotiateCnameLookup」を有効にすると、入力した名前のまま使う |
| ポート番号 | 既定では付けない。Edge では「EnableAuthNegotiatePort」を有効にすると、80・443 以外のポートを SPN に入れる |
| IP アドレス | 既定では Kerberos を使わず、NTLM に戻る |
Web サーバ1台を、そのサーバの名前(web01.corp.example.com)で開く場合は、SPN の登録はいりません。コンピューターアカウントには「HOST/web01…」が自動で登録されていて、HOST の SPN が HTTP の SPN の代わりになるからです。SPN の書き方と HOST の代わりの決まりは「SPNとは?」の記事で説明しています。
SPN の登録が必要になるのは、サーバ名とは別の名前(A レコードの portal.corp.example.com など)で公開するときや、複数台のサーバをロードバランサでまとめるときです。同じ SPN を2つ以上のアカウントに登録すると、どちらの鍵でチケットを作るかが決まらず、認証が失敗します(KRB_AP_ERR_MODIFIED)。登録の前に setspn -Q で重複がないかを確かめ、登録には重複を調べてくれる setspn -S を使います。
IIS でチケットを開くアカウント
チケットは、SPN の持ち主のアカウントの鍵で暗号化されています。IIS の側で、だれの鍵でチケットを開くかが SPN の持ち主と合っていないと、Kerberos は失敗します。
IIS の Windows 認証は、既定でカーネルモード(http.sys)で処理されます。カーネルモードでは、チケットをコンピューターアカウントの鍵で開きます。サーバ1台を既定のアプリケーションプール(ApplicationPoolIdentity)で動かすなら、これでうまくいきます。
複数台の Web サーバで同じ名前を公開するときは、SPN を共通のサービスアカウント(例:svc-web)に登録し、各サーバのアプリケーションプールをそのアカウントで動かします。このときは useAppPoolCredentials を true にして、アプリケーションプールの資格情報でチケットを開くようにします。false のままだと、カーネルモードがコンピューターアカウントの鍵で開こうとして失敗します。Microsoft は、カーネルモード自体を無効にするより、useAppPoolCredentials を使う方法を勧めています。
ブラウザが自動でサインインする条件
ブラウザは、どのサイトにも自動で Windows の資格情報を渡すわけではありません。社外のサイトに勝手に資格情報を渡さないように、自動でサインインする相手を絞っています。Edge と Chrome は、次のように判断します。
ポリシー「AuthServerAllowlist」を設定していないときは、ブラウザがイントラネットのサーバかどうかを判定し、イントラネットと判定したサーバにだけ自動で応えます。Edge は Windows の「ローカル イントラネット」ゾーンの設定を参考にしますが、プロキシの設定など、ほかの情報も使って判定します。
AuthServerAllowlist を設定すると、ゾーンの設定は参照されず、リストに書いたサーバと、プロキシからの要求にだけ自動で応えます。PC ごとの違いが出にくいので、グループポリシーで設定するのが確実です。
| Edge のポリシー | 内容 |
|---|---|
| AuthServerAllowlist | 統合 Windows 認証で自動に応えるサーバ。カンマ区切りで、* も使える(例:*.corp.example.com) |
| AuthNegotiateDelegateAllowlist | 資格情報の委任(Kerberos の委任)を許すサーバ |
| AuthSchemes | 使う方式(basic・digest・ntlm・negotiate) |
| DisableAuthNegotiateCnameLookup | SPN を作るときに CNAME をたどらない |
| EnableAuthNegotiatePort | 80・443 以外のポートを SPN に入れる |
グループポリシーの場所は コンピューターの構成 ›› ポリシー ›› 管理用テンプレート ›› Microsoft Edge ›› HTTP 認証 です(Edge の管理用テンプレートを取り込んだ場合)。Google Chrome にも同じ名前のポリシー(AuthServerAllowlist など)があります。
1台の PC だけ確かめたいときは、インターネット オプション ›› 詳細設定 の「統合 Windows 認証を使用する」と、インターネット オプション ›› セキュリティ ›› ローカル イントラネット ›› サイト を見ます。
IIS で統合 Windows 認証を使う
IIS では、既定のインストールに Windows 認証の機能が入っていません。次の順番で設定します。
- サーバー マネージャーで、
Web サーバー (IIS) ›› Web サーバー ›› セキュリティ ›› Windows 認証の役割サービスを追加する - IIS マネージャーでサイトを選び、
認証で「匿名認証」を無効、「Windows 認証」を有効にする - 「Windows 認証」の
プロバイダーで、Negotiate が上、NTLM が2番目に並んでいることを確かめる
Windows 認証には、次のような設定があります。
| 設定 | 既定 | 内容 |
|---|---|---|
| providers | Negotiate、NTLM | 401 で返す方式とその順番。Negotiate を消すと Kerberos を使えない |
| useKernelMode | true | カーネルモード(http.sys)で認証する。チケットはコンピューターアカウントの鍵で開く |
| useAppPoolCredentials | false | true にすると、チケットをアプリケーションプールの資格情報で開く |
| extendedProtection の tokenChecking | None | 拡張保護(チャネルバインディング)。None/Allow/Require。IIS マネージャーでは Off/Accept/Required |
拡張保護(Extended Protection)は、HTTPS の TLS の通り道と Windows 認証を結び付けて、認証の中継を防ぐしくみです。ブラウザと IIS が同じ TLS を見ていることが前提なので、ロードバランサやプロキシが途中で TLS を終わらせて張り直していると、チャネルバインディングが一致せず、パスワードを何度も聞かれます。その構成では、IIS の flags に Proxy を付け、公開する名前の SPN を指定して、SPN で確かめる形にします。考え方は「Windows認証とTLS」の記事で説明しています。
大きなチケットで 400 になる
所属するグループがとても多い利用者だけ、社内サイトを開くと「HTTP 400 – Bad Request (Request Header too long)」になることがあります。原因は、Kerberos のチケットが大きくなりすぎて、ヘッダの上限を超えたことです。
Kerberos のチケットには、PAC として所属グループの SID が入ります。グループが多いほどチケットは大きくなり、ヘッダに入れるときは base64 にするので、さらに約 4/3 倍になります。IIS の手前にある http.sys は、1つのヘッダの大きさ(MaxFieldLength)と、要求の行とヘッダの合計(MaxRequestBytes)に上限を持っていて、既定はどちらも 16384 バイトです。これを超えると、IIS に届く前に http.sys が 400 を返します。
直し方は、まず利用者の所属グループを減らすことです。すぐに減らせないときは、IIS サーバのレジストリ HKLM\System\CurrentControlSet\ に MaxFieldLength と MaxRequestBytes を作り、上限を上げます。Microsoft は、チケットの大きさを T バイトとして「4/3 × T + 200」を目安にしています。上限を上げると http.sys が使うメモリが増え、攻撃にも弱くなるので、必要以上に大きくしないでください。変更後は HTTP サービスと IIS の再起動が必要です。
http.sys が断った要求は、IIS のログではなく %windir%\System32\LogFiles\HTTPERR のログに記録されます。理由の欄に RequestLength や FieldLength が出ていれば、この問題です。
よくあるトラブルと調べ方
何度もパスワードを聞かれる
正しいパスワードを入れても聞かれ続け、最後に 401 になる場合は、次の順番で確かめます。
- 自動サインインの対象か:
edge://policyで AuthServerAllowlist を確かめる。設定していなければ、サイトがローカル イントラネットに入っているかを見る - チケットをもらえているか:PC で
klistを実行し、HTTP/サーバ名 のチケットがあるかを見る。なければ SPN の登録を確かめる - SPN が重複していないか:
setspn -Xやsetspn -Qで調べる - チケットを開くアカウントが合っているか:SPN をサービスアカウントに付けたなら、useAppPoolCredentials が true か
- 拡張保護と TLS の終端:途中で TLS を終わらせる機器があるか
PC のシステムのイベントログに、Kerberos のエラー(KRB_AP_ERR_MODIFIED など)が出ていないかも確かめます。調べ方の全体は「Windows認証の調べ方」の記事にまとめています。
407 が止まらない(プロキシ)
- どのプロキシに向いているか:PAC の
FindProxyForURLが、想定どおりのプロキシを返しているか。画像やスクリプトなど、ページの一部だけ失敗するときは、それらの URL も確かめる - プロキシの SPN:
klistで HTTP/プロキシ名 のチケットがあるか。プロキシを IP で指定していないか - 方式:プロキシが返す方式が、Edge の AuthSchemes で許されているか
- 記録を取る:
edge://net-exportで1回分の失敗を記録し、同じ 407 がくり返されているかを見る
Basic 認証を HTTP のままプロキシに使うと、資格情報が守られずに流れます。Edge には HTTP で Basic を許すポリシー(BasicAuthOverHttpEnabled)がありますが、回避策として本番で有効にするのは避け、プロキシとの通り道を守る方向で直します。
つながるが NTLM になる
パスワードは聞かれないものの、Authorization ヘッダが「TlRMTVNTUAA」で始まっているなら、Kerberos ではなく NTLM が使われています。SPN が見つからないと、Negotiate は黙って NTLM に戻るので、気づきにくい問題です。IP アドレスで開いていないか、SPN が登録された名前で開いているかを確かめます。NTLM の利用を減らしていく流れの中では、このような「気づかない NTLM」を見つけて直すことが大切です。
確認に使うコマンド
PC01(コマンドプロンプト):持っている Kerberos のチケットを表示する
klist
PC01(コマンドプロンプト):Web サーバの SPN でチケットをもらえるかを試す
klist get HTTP/portal.corp.example.com
PC01(PowerShell):Windows の資格情報を使って Web サーバに要求を送る
Invoke-WebRequest -Uri https://portal.corp.example.com/ -UseDefaultCredentials
DC01(コマンドプロンプト・管理者):SPN がどのアカウントに登録されているかを調べる
setspn -Q HTTP/portal.corp.example.com
DC01(コマンドプロンプト・管理者):重複している SPN を探す
setspn -X
DC01(コマンドプロンプト・管理者):重複を確かめてから、サービスアカウントに SPN を登録する
setspn -S HTTP/portal.corp.example.com CORP\svc-web
WEB01(コマンドプロンプト・管理者):サイト「Portal」で、アプリケーションプールの資格情報でチケットを開くようにする
%windir%\system32\inetsrv\appcmd.exe set config "Portal" -section:system.webServer/security/authentication/windowsAuthentication /useAppPoolCredentials:"True" /commit:apphost
WEB01(コマンドプロンプト・管理者):http.sys のヘッダの上限が設定されているかを確かめる
reg query "HKLM\System\CurrentControlSet\Services\HTTP\Parameters"
WEB01(PowerShell・管理者):http.sys が断った要求のうち、長さが原因のものを探す
Select-String -Path "$env:windir\System32\LogFiles\HTTPERR\*.log" -Pattern "RequestLength|FieldLength"
reg query で MaxFieldLength や MaxRequestBytes が表示されなければ、既定値(16384 バイト)のままという意味です。
まとめ
| 項目 | ひとことで |
|---|---|
| 統合 Windows 認証 | Windows のサインイン情報で、Kerberos・NTLM を使って HTTP の認証を自動で済ませる |
| 401 と 407 | Web サーバは 401・WWW-Authenticate・Authorization、プロキシは 407・Proxy-Authenticate・Proxy-Authorization |
| Kerberos | チケットを Authorization: Negotiate に入れて1回送り直すだけ。サーバは自分の鍵でチケットを確かめる |
| NTLM | 3通のやり取りを同じ TCP 接続の上で行う。サーバは DC に問い合わせる |
| HTTP の SPN | HTTP/名前。CNAME は本当の名前に置き換え、ポートは付けない。プロキシは FQDN で指定する |
| IIS | カーネルモードはコンピューターの鍵で開く。サービスアカウントの SPN なら useAppPoolCredentials を true に |
| ブラウザ | AuthServerAllowlist のサーバか、イントラネットと判定したサーバにだけ自動で応える |
| 400 エラー | グループが多くチケットが大きい。グループを減らすか、http.sys の上限を上げる |
統合 Windows 認証は、利用者からは「何も聞かれない」ことしか見えませんが、裏では 401 や 407 と、Kerberos・NTLM のやり取りが組み合わさっています。うまくいかないときは、「どの名前で SPN を作ったか」「だれの鍵でチケットを開くか」「ブラウザが自動で応える相手か」の3つに分けて確かめると、原因を絞り込みやすくなります。
- RFC 4559:SPNEGO-based Kerberos and NTLM HTTP Authentication in Microsoft Windows(IETF)
- RFC 9110:HTTP Semantics(IETF)、RFC 7235:HTTP/1.1 Authentication(IETF)
- Authentication in WinHTTP(Microsoft Learn)
- Troubleshoot Kerberos failures in Internet Explorer(Microsoft Learn)
- Troubleshooting Kerberos single sign-on issues(Microsoft Learn)
- Microsoft Edge repeatedly prompts for proxy credentials(Microsoft Learn)
- Microsoft Edge identity support and configuration(Microsoft Learn)
- AuthServerAllowlist(Microsoft Learn)、DisableAuthNegotiateCnameLookup、EnableAuthNegotiatePort
- Windows Authentication <windowsAuthentication>(Microsoft Learn)
- Windows Extended Protection <extendedProtection>(Microsoft Learn)
- HTTP 400 Bad Request (Request Header too long) responses to HTTP requests(Microsoft Learn)
- Http.sys registry settings for Windows(Microsoft Learn)
- setspn(Microsoft Learn)
- Kerberos clients allow IPv4 and IPv6 address hostnames in SPNs(Microsoft Learn)
- Proxy Servers and WinRM(Microsoft Learn)
- Chrome Enterprise policy list:AuthServerAllowlist(Google)
コメント