当前位置: 首页 > 知识库问答 >
问题:

由ASP。网芯

翟默
2023-03-14

我正在尝试将带有ASP.NETCore的cookie的SameCookie属性显式设置为无。

我尝试这样做的方法是像这样设置CookieOptions的属性值:

var options = new CookieOptions
{
    SameSite = SameSiteMode.None
};

(为简洁起见,省略了其他属性)

然而,当我检查服务器响应头时(服务器应该将cookie设置为SameSite=None),我可以看到SameSite被省略了。相反,我可以看到Value、Expires、Path甚至Secure被显式声明。

如果我将C#代码中的SameSite设置为Lax或Strict,我可以看到它显式包含在set-Cookie头中。如果我设置为“无”-我不能。

我确实检查了两个浏览器——火狐和Chrome77(我知道这个版本引入了SameSite的变化)。

有一种方法可以将SameSite=None包含在内。您只需要在CookieOptions的Path属性中添加以下行:

options.Path += "; samesite=None";

然后,可以在响应的 Set-Cookie 标头中找到它。

有没有一种方法可以配置Kestrel(没有用于托管的IIS,裸Kestrel)在头文件中包含SameSite=None,而不必像这样进行攻击?

共有3个答案

潘鸿文
2023-03-14

Charles Chen概述的方法——使用处理程序制作带有SameSite=无Secure集的每个cookie的副本——具有实现不引人注目的优势,并结合了一种与不支持SameSite=无的浏览器兼容的简单方法正确。对于我的情况——支持较旧的. NET版本——这种方法是一种救命稻草,但是当尝试使用Charles的代码时,我遇到了一些问题,使它无法“按原样”为我工作。

以下是更新的代码,它解决了我遇到的问题:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;

namespace SameSiteHttpModule
{
    public class SameSiteModule : IHttpModule
    {
        // Suffix includes a randomly generated code to minimize possibility of cookie copies colliding with original names
        private const string SuffixForCookieCopy = "-same-site-j4J6bSt0";
        private Regex _cookieNameRegex;
        private Regex _cookieSameSiteAttributeRegex;
        private Regex _cookieSecureAttributeRegex;

        /// <inheritdoc />
        /// <summary>
        ///     Set up the event handlers.
        /// </summary>
        public void Init(HttpApplication context)
        {
            // Initialize regular expressions used for making a cookie copy
            InitializeMatchExpressions();

            // This one is the OUTBOUND side; we add the extra cookies
            context.PreSendRequestHeaders += OnPreSendRequestHeaders;

            // This one is the INBOUND side; we coalesce the cookies
            context.BeginRequest += OnBeginRequest;
        }

        /// <summary>
        ///     The OUTBOUND LEG; we add the extra cookie
        /// </summary>
        private void OnPreSendRequestHeaders(object sender, EventArgs e)
        {
            var application = (HttpApplication) sender;
            var response = application.Context.Response;
            var cookieCopies = CreateCookieCopiesToSave(response);
            SaveCookieCopies(response, cookieCopies);
        }

        /// <summary>
        ///     The INBOUND LEG; we coalesce the cookies
        /// </summary>
        private void OnBeginRequest(object sender, EventArgs e)
        {
            var application = (HttpApplication) sender;
            var request = application.Context.Request;
            var cookiesToRestore = CreateCookiesToRestore(request);
            RestoreCookies(request, cookiesToRestore);
        }

        #region Supporting code for saving cookies

        private IEnumerable<string> CreateCookieCopiesToSave(HttpResponse response)
        {
            var cookieStrings = response.Headers.GetValues("set-cookie") ?? new string[0];
            var cookieCopies = new List<string>();

            foreach (var cookieString in cookieStrings)
            {
                bool createdCopy;
                var cookieStringCopy = TryMakeSameSiteCookieCopy(cookieString, out createdCopy);
                if (!createdCopy) continue;
                cookieCopies.Add(cookieStringCopy);
            }

            return cookieCopies;
        }

        private static void SaveCookieCopies(HttpResponse response, IEnumerable<string> cookieCopies)
        {
            foreach (var cookieCopy in cookieCopies)
            {
                response.Headers.Add("set-cookie", cookieCopy);
            }
        }

        private void InitializeMatchExpressions()
        {
            _cookieNameRegex = new Regex(@"
                (?'prefix'          # Group 1: Everything prior to cookie name
                    ^\s*                # Start of value followed by optional whitespace
                )
                (?'cookie_name'     # Group 2: Cookie name
                    [^\s=]+             # One or more characters that are not whitespace or equals
                )            
                (?'suffix'          # Group 3: Everything after the cookie name
                    .*$                 # Arbitrary characters followed by end of value
                )",
                RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);

            _cookieSameSiteAttributeRegex = new Regex(@"
                (?'prefix'          # Group 1: Everything prior to SameSite attribute value
                    ^.*                 # Start of value followed by 0 or more arbitrary characters
                    ;\s*                # Semicolon followed by optional whitespace
                    SameSite            # SameSite attribute name
                    \s*=\s*             # Equals sign (with optional whitespace around it)
                )
                (?'attribute_value' # Group 2: SameSite attribute value
                    [^\s;]+             # One or more characters that are not whitespace or semicolon
                )
                (?'suffix'          # Group 3: Everything after the SameSite attribute value
                    .*$                 # Arbitrary characters followed by end of value
                )",
                RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);

            _cookieSecureAttributeRegex = new Regex(@"
                ;\s*                # Semicolon followed by optional whitespace
                Secure              # Secure attribute value
                \s*                 # Optional whitespace
                (?:;|$)             # Semicolon or end of value",
                RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
        }

        private string TryMakeSameSiteCookieCopy(string cookie, out bool success)
        {
            if (!AddNameSuffix(ref cookie))
            {
                // could not add the name suffix so unable to copy cookie (generally should not happen)
                success = false;
                return null;
            }

            var addedSameSiteNone = AddSameSiteNone(ref cookie);
            var addedSecure = AddSecure(ref cookie);

            if (!addedSameSiteNone && !addedSecure)
            {
                // cookie already has SameSite and Secure attributes so don't make copy
                success = false;
                return null;
            }

            success = true;
            return cookie;
        }

        private bool AddNameSuffix(ref string cookie)
        {
            var match = _cookieNameRegex.Match(cookie);
            if (!match.Success)
            {
                // Could not find the cookie name in order to modify it
                return false;
            }

            var groups = match.Groups;
            var nameForCopy = groups["cookie_name"] + SuffixForCookieCopy;
            cookie = string.Concat(groups["prefix"].Value, nameForCopy, groups["suffix"].Value);
            return true;
        }

        private bool AddSameSiteNone(ref string cookie)
        {
            var match = _cookieSameSiteAttributeRegex.Match(cookie);
            if (!match.Success)
            {
                cookie += "; SameSite=None";
                return true;
            }

            var groups = match.Groups;

            if (groups["attribute_value"].Value.Equals("None", StringComparison.OrdinalIgnoreCase))
            {
                // SameSite=None is already present, so we will not add it
                return false;
            }

            // Replace existing SameSite value with "None"
            cookie = string.Concat(groups["prefix"].Value, "None", groups["suffix"].Value);
            return true;
        }

        private bool AddSecure(ref string cookie)
        {
            if (_cookieSecureAttributeRegex.IsMatch(cookie))
            {
                // Secure is already present so we will not add it
                return false;
            }

            cookie += "; Secure";
            return true;
        }

        #endregion

        #region Supporting code for restoring cookies

        private static IEnumerable<HttpCookie> CreateCookiesToRestore(HttpRequest request)
        {
            var cookiesToRestore = new List<HttpCookie>();

            for (var i = 0; i < request.Cookies.Count; i++)
            {
                var inboundCookie = request.Cookies[i];
                if (inboundCookie == null) continue;

                var cookieName = inboundCookie.Name;

                if (!cookieName.EndsWith(SuffixForCookieCopy, StringComparison.OrdinalIgnoreCase))
                {
                    continue; // Not interested in this cookie since it is not a copied cookie.
                }

                var originalName = cookieName.Substring(0, cookieName.Length - SuffixForCookieCopy.Length);

                if (request.Cookies[originalName] != null)
                {
                    continue; // We have the original cookie, so we are OK; just continue.
                }

                cookiesToRestore.Add(new HttpCookie(originalName, inboundCookie.Value));
            }

            return cookiesToRestore;
        }

        private static void RestoreCookies(HttpRequest request, IEnumerable<HttpCookie> cookiesToRestore)
        {
            // We need to inject cookies as if they were the original.
            foreach (var cookie in cookiesToRestore)
            {
                // Add to the cookie header for non-managed modules
                // https://support.microsoft.com/en-us/help/2666571/cookies-added-by-a-managed-httpmodule-are-not-available-to-native-ihtt
                if (request.Headers["cookie"] == null)
                {
                    request.Headers.Add("cookie", $"{cookie.Name}={cookie.Value}");
                }
                else
                {
                    request.Headers["cookie"] += $"; {cookie.Name}={cookie.Value}";
                }

                // Also add to the request cookies collection for managed modules.
                request.Cookies.Add(cookie);
            }
        }

        #endregion

        public void Dispose()
        {
        }
    }
}

此代码带来的一些问题:

  • 复制的cookie保留了网站正确运行所需的属性,例如PathExpires
  • 恢复cookie时,除了添加到Cookie标头之外,它们还被添加到. NETHttpRequest.Cookies集合中,这是必要的,例如为了避免丢失ASP.NET会话。
  • 在恢复cookie时,避免创建重复的Cookie标头的可能性,这将违反RFC 6265并可能导致应用程序出现问题。

一些部署选项:

    < li >向现有应用程序添加处理程序代码 < li >编译成DLL以部署到应用程序的bin文件夹中 < li >编译成DLL并添加到GAC中

配置(例如web.config):

<system.webServer>
  ...
  <modules>
    <add name="SameSiteModule" type="SameSiteHttpModule.SameSiteModule, CustomSameSiteModule" />

P. S.查尔斯,我是var的粉丝,对不起:)

南门野
2023-03-14

最新版本的现已修复了该问题。NET框架和。网芯。

正如我在另一篇文章中所说的那样https://stackoverflow.com/a/58998232/906046,cookie选项<code>相同的模式。现在没有按预期工作。

蒋嘉颖
2023-03-14

看起来问题是,虽然< code>SameSite枚举有一个< code>None值,该值被解释为不提供< code>SameSite属性的默认值。您可以在< code > SetCookieHeaderValue 的代码中看到这一点,该代码只有< code>Strict和< code>Lax的标记值。

设置同一站点=无;安全 Cookie 您应该自己发送 Set-Cookie 标头。

(旁注:我会尝试为核心整理一个拉取请求以添加适当的支持)

 类似资料:
  • 是否可以在swagger中默认隐藏所有endpoint,并仅显示我用某种属性标记的endpoint?

  • 我创建贝宝Restapi以下步骤1.创建登录ID由developer.paypal.com2.点击我的应用程序3.点击按钮"创建应用程序"创建测试应用程序4.通过单击testapp,我得到了两个api凭据(i)测试凭据(ii)实时凭据(通过单击显示) 我的代码中存在上述api(客户端ID和密码)的问题,代码给出的错误号为401或某个时间为400 我已检查“帐户资格” PayPal付款和登录与Pay

  • 我尝试使用MySQL在Visual Studio 2017asp.netc#web应用程序登录页面,它显示以下错误: 第33行:queryStr=“从webapp.userregistration中选择*,其中username='”usernameTextBox。文本“'和密码='”passwordTextBox。文本第34行:cmd=新MySql。数据MySQL客户端。MySqlCommand(

  • 我试图从JS/Ajax向我的WebAPI发出请求时遇到了问题。在我的解决方案中,我有一个发布在srv02:2400上的Web API,我的网站发布在srv02:2300上 当我导航到页面时http://srv02:2300/all-请求。aspx,页面加载正常,除了应该来自我的API的数据 我得到了一个错误: 但是,如果我把url超文本传输协议://srv02:2400/api/请求/查找/1粘贴

  • 使用。Net Core 3.0<这基本上是作为发送用户帐户确认电子邮件的帐户验证模块<下面是我编写的创建URL并发送到用户电子邮件的代码<要在电子邮件中发送的确认链接使用LinkGenerator库生成,然后与localhost连接以创建完整的URL<电子邮件中发送的URL创建如下,SendAccountConfirmationMail方法用于向用户发送电子邮件。 我成功地收到了带有重定向链接的电

  • 如何获取新ASP中用户的密码。网络身份识别系统?或者如何在不知道当前密码(用户忘记密码)的情况下重置?