我无法将 AntiforgeryToken 传递到外部项目端点

问题描述 投票:0回答:1

我有以下结构:

  • 项目 A:具有附加功能的 Duende Identity Server
  • 项目 B:使用项目 A 进行身份验证的 Web 客户端

两个项目都在使用:

  • AuthorizeFilter
    默认需要授权请求。
  • AutoValidateAntiforgeryTokenAttribute
    默认需要 AntiforgeryToken。

到目前为止,所有交互都运行良好。

我需要在

Project B
中创建一个虚拟授权端点,该端点调用
Project A
中的端点来创建自定义令牌。

在项目 A 中,我的虚拟端点是(完整代码):

    [Route("ProjectAController/RequestToken")]
    [HttpPost]
    public async Task<IActionResult> RequestToken()
    {
        string antiForgeryInputValue = String.Empty;
        string antiForgeryCookieValue = String.Empty;
        string antiForgeryCookieKey = String.Empty;
        var identityPath = _configuration["ProjectA_Link"];

        bool getFromIdentityServer = true;
        if (getFromIdentityServer)
        {
            using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
            {
                var response = await accountClient.GetAsync($"{identityPath}/Account/Login");
                var content = await response.Content.ReadAsStringAsync();
                IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
                var rawAntiForgeryCookie = cookies.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
                var match = Regex.Match(content, "name=\"__RequestVerificationToken\" type=\"hidden\" value=\"(.*?)\"");
                if (match.Success)
                    antiForgeryInputValue = match.Groups[1].Value;
                var cookieAnti = SetCookieHeaderValue.Parse(rawAntiForgeryCookie);
                antiForgeryCookieValue = cookieAnti.Value.ToString();
                antiForgeryCookieKey = cookieAnti.Name.ToString();
            }
        }
        else
        {
            var antiForgeryHeaderTokenKey = Request.Form.FirstOrDefault(f => f.Key.StartsWith("__RequestVerificationToken")).Key;
            antiForgeryInputValue = Request.Form[antiForgeryHeaderTokenKey].ToString();
            antiForgeryCookieKey = Request.Cookies.Keys.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
            antiForgeryCookieValue = Request.Cookies[antiForgeryCookieKey];
        }

        var cookieDommainBaseAddress = new Uri(_configuration["ProjectA_Link"]);
        var container = HttpContext.RequestServices.GetService<CookieContainer>();
        container.Add(cookieDommainBaseAddress, new Cookie("idsrv", Request.Cookies["idsrv"]));
        container.Add(cookieDommainBaseAddress, new Cookie("idsrv.session", Request.Cookies["idsrv.session"]));
        container.Add(cookieDommainBaseAddress, new Cookie(antiForgeryCookieKey, antiForgeryCookieValue));

        using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
        {
            var dataToPost = new List<KeyValuePair<string, string>>() { { new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryInputValue) } };
            var content = new FormUrlEncodedContent(dataToPost);

            var result = await accountClient.PostAsync($"{identityPath}/Authentication/GenerateToken", content);
            result.EnsureSuccessStatusCode();
            if (result.IsSuccessStatusCode)
            {
                var contentResult = await result.Content.ReadAsStringAsync();
                var tokenGeneration = JsonSerializer.Deserialize<TokenGenerationResult>(contentResult, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
                if (tokenGeneration != null)
                    return RedirectToAction("AuthStatus", new { referenceToken = tokenGeneration.ReferenceToken, refreshToken = tokenGeneration.RefreshToken });
            }
        }

        return RedirectToAction("AuthStatus");
    }

我正在尝试从本节中的

ProjectA/Account/Login
表单获取防伪 Cookie 和防伪令牌:

            if (getFromIdentityServer)
            {
                using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
                {
                    var response = await accountClient.GetAsync($"{identityPath}/Account/Login");
                    var content = await response.Content.ReadAsStringAsync();
                    IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
                    var rawAntiForgeryCookie = cookies.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
                    var match = Regex.Match(content, "name=\"__RequestVerificationToken\" type=\"hidden\" value=\"(.*?)\"");
                    if (match.Success)
                        antiForgeryInputValue = match.Groups[1].Value;
                    var cookieAnti = SetCookieHeaderValue.Parse(rawAntiForgeryCookie);
                    antiForgeryCookieValue = cookieAnti.Value.ToString();
                    antiForgeryCookieKey = cookieAnti.Name.ToString();
                }
            }

为了测试其他可能性,我从当前请求中获取防伪 Cookie 和防伪令牌

Project B
,在这部分中:

            else
            {
                var antiForgeryHeaderTokenKey = Request.Form.FirstOrDefault(f => f.Key.StartsWith("__RequestVerificationToken")).Key;
                antiForgeryInputValue = Request.Form[antiForgeryHeaderTokenKey].ToString();
                antiForgeryCookieKey = Request.Cookies.Keys.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
                antiForgeryCookieValue = Request.Cookies[antiForgeryCookieKey];
            }

在这两种情况下,我都在

result.EnsureSuccessStatusCode();
上遇到错误。 如果从
Project A login page
获取防伪数据,错误是:

[23:55:39信息] Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter 防伪令牌验证失败。提供的防伪令牌适用于与当前用户不同的基于声明的用户。 Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException:提供的防伪令牌适用于与当前用户不同的基于声明的用户。 在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateTokens(HttpContext httpContext,AntiforgeryTokenSet antiforgeryTokenSet) 在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext) 在 Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext 上下文)

如果我尝试从

Project B, current request
获取防伪数据,错误是:

[00:33:27 信息] Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter 防伪令牌验证失败。防伪令牌无法解密。 Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException:无法解密防伪令牌。 ---> System.Security.Cryptography.CryptographyException:有效负载无效。有关更多信息,请访问 http://aka.ms/dataprotectionwarning 在 Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(字节 * pbCiphertext,UInt32 cbCiphertext,字节 * pbAdditionalAuthenticatedData,UInt32 cbAdditionalAuthenticatedData) 在 Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment

1 ciphertext, ArraySegment
1 extraAuthenticatedData) 在 Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData,布尔值allowOperationsOnRevokedKeys,UnprotectStatus&状态) 在 Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) 在Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(字符串serializedToken) --- 内部异常堆栈跟踪结束 --- 在Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(字符串serializedToken) 在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.DeserializeTokens(HttpContext httpContext、AntiforgeryTokenSet antiforgeryTokenSet、AntiforgeryToken& cookieToken、AntiforgeryToken& requestToken) 在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateTokens(HttpContext httpContext,AntiforgeryTokenSet antiforgeryTokenSet) 在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext) 在 Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext 上下文)

asp.net-core cookies httpclient antiforgerytoken duende-identity-server
1个回答
0
投票

一个站点无法解密另一个站点的防伪令牌,因为该令牌是使用数据保护 API 加密的。我在我的博客文章中对此进行了描述: https://nestenius.se/2023/11/22/exploring-what-is-inside-the-asp-net-core-cookies/

如果两个站点具有相同的数据保护 API 加密密钥,则两个站点都能够解密彼此的令牌。

数据保护 API 取决于表单内的令牌和相应的防伪 cookie。两者都必须存在才能发挥作用。

但主要问题是,当您想要进行服务间通信时,为什么还要费心防伪呢?您可以简单地使用一些 API 密钥或其他方式来保护通信。

© www.soinside.com 2019 - 2024. All rights reserved.