Skip to content

MS_ASPNETCookieSharing

nishi_74322014 edited this page Aug 21, 2026 · 4 revisions

ASP.NET でSessionCookie、Cookie認証Ticketを共有する方法

概要

  • VSソリューション プロジェクトの構成検討
    にも書いたように、プロジェクト分割したいケースがある。

  • ASP.NET アプリケーションの P 層部分のプロジェクトを分割すると、
    SessionCookie と、Cookie 認証 Ticket が共有できなくなり、
    ≒ Session が分割され、SSO もできない状態になる。

  • 必要に応じて、

    • SessionCookie
    • Cookie 認証 Ticket

    を共有する設定が必要になる。

補足(3 つの層で別々の設定が要る): 「共有できない」と一言で言っても、
実際には独立した 3 つの問題が重なっている。
どれか 1 つでも欠けると共有できない。

# 揃えるもの
1 ブラウザに届くか Cookie の DomainPath(+ SameSite
2 同じ Cookie を見るか Cookie の名前
3 中身を復号できるか machineKey(暗号鍵・検証鍵)
4 (Session のみ)データを共有できるか Session の格納先(StateServer / SQL Server)

「設定したのに共有できない」の原因はほぼ 3 番である。

詳細

SessionCookie

下記の処置を施せば、Session を共有可能と思われる(未検証)。

SessionCookie

  • SessionCookie を共有するサイトのドメインを指定する。
  • SessionCookie 名を一致させる(既定値は ASP.NET_SessionId で一致している)。

Sessionデータ

  • 当然、InProc モードでは NG なので、StateServer モードを選択する。
  • machineKey を設定する(同一マシンなら不要?)。
  • アプリケーション名を設定する(設定処理は Global.asax などに実装)。
<system.web>
  <!-- Cookieを共有するサイトのドメインを指定 -->
  <httpCookies domain=".your.site"/>
  <!-- セッション StateServerにセッション保存、セッションクッキー名の指定、タイムアウト指定 -->
  <sessionState
    cookieless="UseCookies"
    cookieName="ASP.NET_SessionId"
    mode="StateServer"
    regenerateExpiredSessionId="false"
    stateConnectionString="tcpip=10.1.1.1:42424"
    timeout="30">
  </sessionState>
  <!-- machineKeyを設定 -->
  <machineKey
    validationKey="..."
    decryptionKey="..."
    validation="SHA1" decryption="AES" />
</system.web>
<appSettings>
  <!-- アプリケーション名を設定 -->
  <add key="ApplicationName" value="appName" />
</appSettings>

移行メモ: 元の掲載では mode="StateServer" の行頭に
全角スペースが混入していたため、半角に直した。

補足(「同一マシンなら不要?」への答え): 同一マシンでも必要である。

ASP.NET は既定(machineKeyAutoGenerate,IsolateApps)で、
アプリケーションごとに異なる鍵を自動生成する。
IsolateApps がまさに「アプリ間で鍵を分ける」指定である。
したがって同じサーバー上の別アプリでも復号できない。

さらに、machineKey を明示しないと、

  • アプリケーション プールのリサイクル
  • 再デプロイ

のたびに鍵が変わり、Session / 認証チケットが失効する
(「時々ログアウトする」の典型的な原因)。

補足(ApplicationName が要る理由): StateServer /
SQLServer モードでは、Session の格納キーに
アプリケーション パス(/App1, /App2)が含まれる
このため、SessionID が同じでも別アプリのデータは見えない。

Global.asaxApplication_Start で、リフレクションにより
AppDomainAppDomainAppId(アプリケーション名)を
強制的に同じ値に書き換える、という手法が使われてきた。
公式にサポートされた方法ではない点は理解しておく必要がある。

// 参考: よく紹介される書き換え(非公式・自己責任)
var appName = "/" + ConfigurationManager.AppSettings["ApplicationName"];
var runtime = typeof(HttpRuntime).GetField("_theRuntime",
    BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
typeof(HttpRuntime).GetField("_appDomainAppId",
    BindingFlags.NonPublic | BindingFlags.Instance)
    .SetValue(runtime, appName);

補足(Session を共有すべきかどうか): 技術的には可能だが、
アプリ間で Session を共有する設計は避けるのが望ましい

  • StateServer単一障害点であり、冗長化できない
    (落ちると全アプリの Session が消える)
  • シリアライズ可能な型しか置けない
  • どのアプリがどのキーを使うかの取り決めが暗黙になり、
    結合度が上がる

共有したいのが「ログイン状態」だけなら、
Session ではなく認証チケット(次節)を共有する方が筋がよい。
共有したいのが業務データなら、
DB や分散キャッシュ(Redis)に明示的に置く方が管理しやすい。

Cookie認証Ticket

また、Forms 認証の Cookie 認証 Ticket については、

  • Cookie 認証 Ticket 名だけ一致させておけば共有できる
    (既定値で一致していると思う)。

  • ドメイン

    • 単一サイト内ならドメイン指定を省略出来るが、明記することも出来る。
    • ドメイン間(サブ・ドメイン間)で共有するには、
      EnableCrossAppRedirectstrue に設定する。
<authentication mode="Forms" >
  <!-- The name, protection, and path attributes must match
       exactly in each Web.config file. -->
  <forms loginUrl="login.aspx"
    name=".ASPXFORMSAUTH"
    protection="All"
    path="/"
    domain="contoso.com"
    timeout="30" />
</authentication>

移行メモ(補足): 「Ticket 名だけ一致させておけば共有できる」は
不正確である。上のコメント(The name, protection, and path attributes\ must match exactly in each Web.config file.)が示す通り、
name / protection / path の 3 つを一致させたうえで、
さらに machineKey を一致させる必要がある。

Forms 認証チケットは machineKey で暗号化・署名されているため、
鍵が違えば「Cookie は届くが復号できず、未認証扱い」になる。

補足(EnableCrossAppRedirects の役割): この設定は
「Cookie を共有する」ためのものではなく、
ReturnUrl として別アプリケーションの URL へのリダイレクトを許可する
ためのものである(既定は false で、外部 URL へは飛ばさない)。

つまり、

目的 設定
チケットをサブドメイン間で共有 domain=".contoso.com"先頭のドット
チケットを復号できるようにする 同一の machineKey
ログイン後に別アプリへ戻す EnableCrossAppRedirects="true"

となる。上の例の domain="contoso.com" は、
サブドメイン間で共有したいのであれば
**.contoso.com(先頭にドット)**とするのが確実である。

なお EnableCrossAppRedirects="true"
オープン リダイレクタの入口になりうる。
遷移先 URL は必ず許可リストで検証すること。

補足(現在の環境で追加で必要になること): 上記は
SameSite 属性が存在しない時代の記述である。現在は次も要る。

項目 現在の要件
requireSSL="true" HTTPS 前提。Cookie に Secure を付ける
SameSite 同一サイト内なら Lax で足りる。別サイトから POST で戻るなら None(+ Secure 必須)
HttpOnly Forms 認証チケットは既定で付与される
validation SHA1 ではなく HMACSHA256 以上にする
decryption AES(既定の Auto でも可)

上の設定例の validation="SHA1"
現在の基準では不十分なので、HMACSHA256 に変更する。

ASP.NET Core の場合

補足: ASP.NET Core には machineKey が無く、
Data Protection API が同じ役割を担う
ASP.NET Core における 認証を参照)。
アプリ間で認証 Cookie を共有するには次の 3 点を揃える。

builder.Services.AddDataProtection()
    // ① 鍵リングを共有ストアに置く(ファイル共有 / Blob / Redis)
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\share\keys"))
    // ② アプリケーション名を一致させる(machineKey の IsolateApps 相当)
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(o =>
{
    // ③ Cookie 名とドメインを一致させる
    o.Cookie.Name = ".AspNet.SharedCookie";
    o.Cookie.Domain = ".contoso.com";
    o.Cookie.SameSite = SameSiteMode.Lax;
    o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

SetApplicationName を揃え忘れるのが定番の失敗である
(既定でアプリごとに鍵が分離されるため、
machineKeyIsolateApps と同じ現象が起きる)。

Session も同様に、InProc ではなく
**分散キャッシュ(Redis / SQL Server)**に置いたうえで、
Session Cookie 名を揃える。

参考

SessionCookie

Cookie認証Ticket

Microsoft Learn

コードログ


Tags: 移行, .NET開発, ASP.NET, 認証基盤

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally