FC2ブログ

記事一覧

クッキーの新しい属性 SameSite に対応する方法 | asp.net


今回は2019年標準となりましたクッキーの新しい属性である SameSite の対応方法を3通りご紹介したいと思います。
2019年12月10日に Windows Update (KB4533013)が配信されました。その内容は2016年ドラフト標準から2019年 IETF 標準に変更された SameSite 属性に関するセキュリティ更新となっています。2020年2月4日には Chrome の新しいバージョン:80 により、完全に SameSite 属性が必須となるように移行されます。従来の asp.net では SameSite に完全に対応することが難しく、.Net Framework のバージョンを上げる方法、またはリフレクションを使用してクッキーを書き換える方法、またはHTTPヘッダーを操作したりする方法があるようです。


aspnet_samesite.png


前提条件
・Windows 10 v1903 以降 / Windows Server 2012 以降
・Visual Studio 2013 Professional 以降
・VB.NET
・.Net Framework 4.7.2 以降



対応する理由

異なるドメイン間(クロスサイト)環境においてクッキーの情報を読み取って動作するように構築されている場合、今まではクッキーの情報が正しく読み取れていましたが、今後は SameSite の設定がデフォルト Lax となり、読み取ることができなくなります。そのために、正しく動作しなくなる恐れがあります。この仕様変更はクッキーをクロスサイトリクエストフォージェリ(CSRF)の脆弱性から保護する為と言われています。
※Windows Update (KB4533013) が当たっていない環境では SameSite=None となります。当たっている環境では SameSite=Lax と表示されます。



設定値について

設定値は None < Lax < Strict の順番に制限が強くなっていきます。Chrome のデフォルトは Lax となるようです。よって、現状のシステムの仕様を変更できない場合は、Noneに設定することが必須になってくるケースが多いと思います。

System.Web.SameSiteMode
Public Enum SameSiteMode 
'Unspecified = -1 'Enumとしては設定がありませんが、値としては存在します。
None = 0
Lax = 1
Strict = 2
End Enum

※.Net Framework 4.7.2 以降で上記 Enum が使用可能です。

【Microsoft 公式ページ】
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.samesitemode?view=netframework-4.8



方法1.Net Framework の更新

.Net Framework 4.6 以前では System.Web.HttpCookie クラスに SameSite プロパティが存在しません。よって、プロジェクトの .Net Framework バージョンを 4.7.2 以降に更新する必要があります。

Imports System.Web
Namespace Views
Public Class TestPage
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

If Not IsPostBack Then

Dim cookie As New HttpCookie() With {
.HttpOnly = True,
.Secure = True,
.SameSite = System.Web.SameSiteMode.None
}
HttpContext.Current.Response.SetCookie(cookie)

End If
End Sub

End Class
End Namespace


【参考URL】
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.httpcookie?view=netframework-4.8



セッションIDについて

セッションIDは通常クッキー(ASP.Net_SessionId)に保存されています。そのセッションも SameSite を設定する必要がある場合があります。その場合は、SessionIdManager をオーバーライドして、セッションIDを割り振るタイミングでSameSite を設定すればよいと思います。
CustomSessionIdManager は以下のURLにてご紹介しています。
https://itblogdsi.blog.fc2.com/blog-entry-345.html



例外ブラウザのサポート方法

iPhone iOS 12 または macOS Mojave 10.14 の safari ブラウザでは、SameSite=None を SameSite=Strict と解釈してしまう不具合が存在します。その為、以下の様にブラウザを判別してSameSiteを設定する必要があります。

UserAgent の条件分岐方法
''' <summary>
''' SameSite属性に不具合のあるブラウザを判別する
''' </summary>
''' <param name="userAgent"></param>
''' <returns></returns>
Public Shared Function DisallowsSameSiteNone(ByVal userAgent As String) As Boolean

If userAgent.Contains("CPU iPhone OS 12") OrElse
userAgent.Contains("iPad; CPU OS 12") Then
Return True
End If

If userAgent.Contains("Macintosh; Intel Mac OS X 10_14") AndAlso
userAgent.Contains("Version/") AndAlso
userAgent.Contains("Safari") Then
Return True
End If

If userAgent.Contains("Chrome/5") OrElse
userAgent.Contains("Chrome/6") Then
Return True
End If

Return False
End Function

【参考URL】
https://docs.microsoft.com/ja-jp/aspnet/samesite/system-web-samesite#supporting-older-browsers


使用方法
''' <summary>
''' セッションクッキーにSameSite属性を設定する
''' </summary>
Public Shared Sub SetSameSiteMode()

Dim section As Object = ConfigurationManager.GetSection("system.web/sessionState")
Dim sss As System.Web.Configuration.SessionStateSection = DirectCast(section, System.Web.Configuration.SessionStateSection)
Dim cookieName As String = "ASP.Net_SessionId"
If Not sss Is Nothing AndAlso
String.IsNullOrEmpty(sss.CookieName) = False Then
cookieName = sss.CookieName
End If
Dim item As String = HttpContext.Current.Response.Headers.Item("Set-Cookie")
Dim mode As String = "SameSite=" + SameSiteMode.None.ToString()
If String.IsNullOrEmpty(item) = False Then
If DisallowsSameSiteNone(HttpContext.Current.Request.UserAgent) Then
mode = String.Empty '"Unspecified"
End If
item = item.Replace("SameSite=Lax", mode)
HttpContext.Current.Response.Headers.Set("Set-Cookie", item)
End If
End Sub



方法2.Global.asaxでの対応

SameSite によりクッキーの読み取りが制限されてしまうと新しいセッションとみなされて、セッションがリスタートすることがあります。毎度 Global.asax のSession_Start イベントが発生したりします。そこで Global.asax にてリクエストが開始されたタイミングでクッキーの SameSite 属性を変更してしまう方法でも対応が可能です。

Global.asax
Public Class Global_asax
Inherits HttpApplication

Private Sub Application_BeginRequest(sender As Object, e As EventArgs) Handles Me.BeginRequest

Dim section As Object = ConfigurationManager.GetSection("system.web/sessionState")
Dim sss As System.Web.Configuration.SessionStateSection = DirectCast(section, System.Web.Configuration.SessionStateSection)
Dim cookieName As String = "ASP.Net_SessionId"
If Not sss Is Nothing AndAlso
String.IsNullOrEmpty(sss.CookieName) = False Then
cookieName = sss.CookieName
End If
Dim cookie As HttpCookie = HttpContext.Current.Request.Cookies(cookieName)
If Not cookie Is Nothing AndAlso
String.IsNullOrEmpty(cookie.Value) = False Then
Me.SetSameSite(cookie)
HttpContext.Current.Response.SetCookie(cookie)
End If

End Sub

Enum SameSiteMode

Undefined = -1
None = 0
Lax = 1
Strict = 2

End Enum

Private Sub SetSameSite(ByVal cookie As HttpCookie)

Dim t As Type = cookie.GetType()
Dim pi As System.Reflection.PropertyInfo = t.GetProperty("SameSite")
If DisallowsSameSiteNone(HttpContext.Current.Request.UserAgent) Then
pi.SetValue(cookie, Convert.ToInt32(SameSiteMode.Undefined))
Else
pi.SetValue(cookie, Convert.ToInt32(SameSiteMode.None))
End If

End Sub

End Class

※ .Net Framework 4.7 未満でも対応できるように、SameSiteMode を独自に定義しています。リフレクションを使用することでアクセスできないプロパティの値を変更しています。



方法3.Web.configでの対応

Web.config で IIS URL Rewrite Module を使用して、レスポンスヘッダーを "SameSite=Lax" から "SameSite=None" に書き換えることができます。この方法でも .Net Framework 4.7.2 に上げる必要はありませんが、意図しない詳細な仕様変更には対応ができない点と、一律でクッキーの SameSite 属性を変更することでクッキーを CSRF から保護することが難しくなる点に注意が必要でしょう。
また、iOS12 / macOS Mojave 10.14 / Chrome5 / Chrome6 の場合に限り、UserAgent を判別して、SameSite を取り除く必要があります。

Web.config
  <system.webServer>
<rewrite>
<outboundRules>
<clear />
<rule name="AddSameSite" preCondition="WithoutSameSite">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
<action type="Rewrite" value="{R:0}; SameSite=None" />
<conditions>
</conditions>
</rule>
<preConditions>
<preCondition name="WithoutSameSite">
<add input="{RESPONSE_Set_Cookie}" pattern="." />
<add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=Lax" negate="true" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>



検証方法

Chrome80 がまだリリースされていない状態の場合は、URLに Chrome://flags と入力した画面で以下の項目の設定を有効にすることで Chrome80 をシミュレートすることができます。その上で asp.net の動作を確認するようにしましょう。
以下の項目を Enabled に設定して、Chrome を再起動します。
・SameSite by default cookies
・Cookies without SameSite must be secure

aspnet_samesite_02.png






最後までお読みいただきありがとうございます。
いかがでしたでしょうか。他にも asp.net に関連する記事を投稿しておりますのでよろしければご参考くださいませ。



関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。