0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[解決][ASP.NET Core 5]CookieOptions.HttpOnly=falseを指定してもcookieがhttponlyになる現象

Last updated at Posted at 2022-09-14

現象

CookieOptions.HttpOnly = false が適用されず、ブラウザにhttponly属性が付与されたset-cookieが返る為、JavaScriptからcookieが取得できない。

環境

ASP.NET Core 5

そもそもの目的

  • AntiForgery用のリクエスト・トークンを非同期通信(ajax)の際にも更新したい。
  • その為に、XSRF-TOKENをcookieとして返却し、それをJavaScript側で読み取ってリクエスト・ヘッダー('X-XSRF-TOKEN')に追加する仕組みを作った。これはAngularやaxiosがサポートしているものと同じ仕組みである。
  • しかし、なぜかJavaScript側でcookieの取得に失敗する。
  • ネットワーク状態を確認すると、XSRF-TOKENにhttponly属性が付加されていた。
  • サーバ側では、CookieOptions.HttpOnly = false は指定している。
  • 何が起きているのか?(この記事の主旨)

原因

サーバ側で以下のように指定されていた為、CookieOptionsの指定に関係なく、cookieの戻り値が強制的にhttponlyになっていた。

services.Configure<CookiePolicyOptions>(options => options.HttpOnly = HttpOnlyPolicy.Always)

主なソースコード

AntiforgeryCookieResultFilter
    public class AntiforgeryCookieResultFilter : ResultFilterAttribute
    {
        /// <summary>Antiforgeryリクエストトークン用のcookie名</summary>
        public static string RequestTokenCookieName => "XSRF-TOKEN";    // AngularのXSRFサポート機能に準拠

        /// <summary>Antiforgeryリクエストトークン用のリクエストヘッダ名</summary>
        public static string RequestTokenHeaderName => "X-XSRF-TOKEN";  // AngularのXSRFサポート機能に準拠

        private IAntiforgery antiforgery;
        public AntiforgeryCookieResultFilter(IAntiforgery antiforgery)
        {
            this.antiforgery = antiforgery;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            if (context.Result is ViewResult || context.Result is JsonResult)
            {
                // Antiforgery用のクッキートークンを生成してクッキーに保存する
                var tokens = antiforgery.GetAndStoreTokens(context.HttpContext);

                // Antiforgery用のリクエストトークンをクッキーに保存する
                context.HttpContext.Response.Cookies.Append(RequestTokenCookieName, tokens.RequestToken, new CookieOptions() { 
                    HttpOnly = false,
                    Secure = true,
                    SameSite = SameSiteMode.Strict
                });
            }
        }
    }
Startup.cs
	// (略)

	services.AddMvc(options => {
		// 既存の処理
		...
		
		// ここでAntiforgeryCookieResultFilterをグローバル登録する
		options.Filters.Add<Filters.AntiforgeryCookieResultFilter>();
	}

	// AntiForgeryの設定
	services.AddAntiforgery(options => 
	{
		// AntiForgeryリクエスト・ヘッダの指定
		options.HeaderName = Filters.AntiforgeryCookieResultFilter.RequestTokenHeaderName;
	});

原因となった箇所

Startup.cs

	// CookiePolicy Middleware の設定
	services
	    .Configure<CookiePolicyOptions>(x => {
	    	// 常にHttpOnlyをtrueにする
	        x.HttpOnly = HttpOnlyPolicy.Always;	// ★この箇所が原因で、全てのCookie指定がHttpOnly=trueで上書きされていた
	    });

上記を以下のように変更することで、HttpOnlyの個別指定が有効になった。

Startup.cs

	// CookiePolicy Middleware の設定
	services
	    .Configure<CookiePolicyOptions>(x => {
	    	// HttpOnlyのポリシー指定なし
	        x.HttpOnly = HttpOnlyPolicy.None;
	    });

もちろん、この変更を行う前に「そもそもなぜHttpOnlyPolicy.Alwaysが指定されていたのか」をよく調査する必要がある。
この変更によって、それまでそのシステムの他の部分で設定していたクッキーについてもこのクッキーポリシーに従うようになる為、HttpOnlyの指定を省略していた箇所があるのであれば、適切にHttpOnly = trueを指定する必要があるかを判断し、個別に指定する必要がある。

補足

上記のクッキーポリシーをHttpOnlyPolicy.Alwaysにしつつ、任意の箇所だけ個別に HttpOnly = false にする方法があるのであれば知りたいが、いろいろ調べたり試したりしたところではどのようにしても HttpOnlyPolicy.Always が優先されてしまい、falseで上書きすることはできなかった。

ネットを見ると、「HttpOnly=falseにしても、勝手にhttponly属性がついてしまう」と嘆いている投稿が散見されるので、そういう人たちの一助になれば幸いである。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?