しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET でも Cookie Policy への対応を行えるか試した

ASP.NET Core 2.1 で入った Cookie Policy が面白かったのと、ASP.NET というか IIS でも HttpModule を使うことで対応出来そうだったので実装して試すことにしました。

行うことは非常に単純なので、HttpModule を書いたことがあれば大体は想像がつくはずです。

  • トラッキングを許可するクッキーがあるか確認
  • ある場合
    • 何もしない
  • ない場合
    • 確認のメッセージを出す
    • クライアントにクッキーを送信しない

別に Global.asax に書いても良いですが、分けた方が好きなので HttpModule として分けました。ただし DynamicModuleHelper を使って動的に追加するようにしています。

何はともあれ、今回でっち上げたコードは以下のような感じです。難しいことはしていません。

using System;
using System.Web;

using Microsoft.Web.Infrastructure.DynamicModuleHelper;

[assembly: PreApplicationStartMethod(typeof(WebApplication4.CookiePolicyModule), "Register")]

namespace WebApplication4
{
    public class CookiePolicyModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += OnBeginRequest;
            context.PreSendRequestHeaders += OnPreSendRequestHeaders;
        }

        private void OnBeginRequest(object sender, EventArgs e)
        {
            var application = (HttpApplication)sender;

            var cookie = application.Request.Cookies[CookiePolicy.CookieName];

            application.Context.Items[CookiePolicy.CanTrackKey] = cookie?.Value == CookiePolicy.CookieValue;
        }

        private void OnPreSendRequestHeaders(object sender, EventArgs e)
        {
            var application = (HttpApplication)sender;

            if (CookiePolicy.CanTrack)
            {
                return;
            }

            // Clear all cookies
            application.Response.Cookies.Clear();
        }

        public void Dispose()
        {
        }

        public static void Register()
        {
            DynamicModuleUtility.RegisterModule(typeof(CookiePolicyModule));
        }
    }
}
using System.Web;

namespace WebApplication4
{
    public static class CookiePolicy
    {
        public static string CookieName { get; set; } = "ASP.NET_CookiePolicy";

        internal const string CookieValue = "yes";

        public const string CanTrackKey = "CanTrack";

        public static bool CanTrack => (bool?)HttpContext.Current.Items[CanTrackKey] ?? false;

        public static string CreateConsentCookie()
        {
            return $"{CookieName}={CookieValue}; path=/";
        }
    }
}

難しいことはしていないですが、Web.config に HttpModule の追加設定を書くのが面倒だったので、DynamicModuleUtility を使って実行時に HttpModule を追加するようにしました。こっちの方が楽ですが使っていいのかわかってません。

とりあえず Web Forms で画面を作ってブラウザで実行してみます。初回なのでクッキーはありません。

f:id:shiba-yan:20180307004527p:plain:w400

Page_Load でセッションに書き込むようにしたので、通常であればセッション用のクッキーが出力されるはずですが、ブラウザで確認しても存在しないです。ちゃんと HttpModule で削除されています。

f:id:shiba-yan:20180307004641p:plain:w550

accept cookie を押して、専用のクッキーを書き込むとセッションクッキーも書き込まれるようになりました。ちなみに専用のクッキーは JavaScript で書き込む必要があるので少し注意が必要ですね。

f:id:shiba-yan:20180307004653p:plain:w550

ASP.NET Core と同じように ASP.NET / IIS でも実現出来ました。試していませんが IIS の HttpModule として実装しているので、原理的には PHP などのアプリケーションでも同様に動作するはずです。

こういうプライバシーの問題は対応が難しいですね。