【问题标题】:ASP.NET requestValidation 4.5 and WIFASP.NET requestValidation 4.5 和 WIF
【发布时间】:2012-04-01 23:03:45
【问题描述】:

我有一个 ASP.NET MVC 应用程序,它启用了 Windows Identity Foundation 身份验证,并使用 ADFS 作为 STS。 该应用程序现在位于带有 MVC 4 的 .NET 4.5 上。 当我将 ASP.NET requestValidation 从 2.0 更改为 4.5 时,我收到此错误:

A potentially dangerous Request.Form value was detected from the client 
(wresult="<t:RequestSecurityTo...").

我猜这是来自 ADFS 的重定向。 我怎样才能解决这个问题?

【问题讨论】:

    标签: asp.net wif


    【解决方案1】:

    升级您的应用程序以使用框架中包含的 WIF 4.5:http://msdn.microsoft.com/en-us/library/jj157089.aspx

    将 RequestValidation 设置为 4.5 模式:

    <httpRuntime targetFramework="4.5" requestValidationMode="4.5" />
    

    WIF 4.5 与 ASP.NET 4.5 中的请求验证完美配合。

    【讨论】:

    • 这个!如果你像我一样浏览网页,你会发现将 requestValidationMode 设置为 2.0 或 的想法,或者编写自己的验证器。这是不必要的!我所需要的只是将 targetFramework 设置为 4.5(我什至没有设置 requestValidationMode)并且它起作用了。干杯!
    • 我喜欢正确而简单的修复!非常感谢分享!
    【解决方案2】:

    Eugenio 引导我走向正确的方向。但他所指的示例在 ASP.NET 4.5 中不再适用。 正如我已经评论过他的回答,这导致了堆栈溢出。这是因为 requestvalidation 现在在请求数据时完成。因此,验证在 WSFederationMessage.CreateFromFormPost 请求数据时完成。这会触发我们的 requestvalidator。这个 requestvalidator 再次调用 WSFederationMessage.CreateFromFormPost 等等。 在对 WIF 代码进行了一些挖掘之后,我现在有了一个稍微修改过的 requestvalidator,它正在工作。我们使用 CreateFromNameValueCollection 代替 CreateFromFormPost(CreateFromFormPost 也使用它),但现在我们可以使用 Request.Unvalidated.Form 来提供它。

    public class RequestValidator : System.Web.Util.RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;
            if (requestValidationSource == RequestValidationSource.Form &&
                collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
            {
                if (WSFederationMessage.CreateFromNameValueCollection(WSFederationMessage.GetBaseUrl(context.Request.Url), context.Request.Unvalidated.Form) as SignInResponseMessage != null)
                {
                    return true;
                }
            }
            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }
    }
    

    【讨论】:

    • 谢谢@Jaap,你的回答拯救了我的一天。我们在 4.0 站点的不同场景中遇到了堆栈溢出。如果缓存的 STS url 是它,就会发生这种情况。我改变了上面的功能来修复它。与上面的唯一区别是获取未验证表单对象的方式,因为 Request.Unvalidated.Form 在 4.0 中不直接可用。 var unvalidatedRequestFormValues = System.Web.Helpers.Validation.Unvalidated(context.Request).Form;
    • 对于 .net 4.5 上的任何人,请查看 @klings 答案,只需在 web.config 的 httpRuntime 元素中将 targetFramework 设置为 4.5。
    • @ctb,国王的回答对我也不起作用。我有与上面类似的代码,但适用于 .Net 4.0,因此与 Vishal 提到的相同。我的代码从 .Net 4.0 迁移到 .Net 4.6,这里的答案对我有用。
    【解决方案3】:

    是的,在您的情况下,这是从 STS (ADFS) 发回的 SAML 令牌。您可以按照 Garrett 的建议禁用验证,或者更好的是,您可以提供一个能够理解 SAML 令牌的适当验证器,这很容易做到。

    查看其他问题/答案:Potentially dangerous Request.Form in WSFederationAuthenticationModule.IsSignInResponse

    【讨论】:

    • .NET 4.5 在这方面可能有什么变化吗?如果我实现了那个 requestvalidator,当 STS 重定向回来时,我会得到一个堆栈溢出异常。
    • 当我删除对 WSFederationMessage.CreateFromFormPost 的调用时,它正在工作(但当然不太安全)。我猜 stackoverflow 是由于 CreateFromFormPost 再次触发验证器造成的?
    • 我记得我在某处读到过,表单值仅在您请求时才被验证,现在在 ASP.NET 4.5 中。所以我猜现在当 WIF 读取表单值时会触发验证。这会触发验证,而验证又会触发 WIF 再次读取,依此类推。所以我认为这个示例对于 ASP.NET 4.5 不再有效。还有其他方法可以验证 wresult 表单参数的值吗?
    【解决方案4】:

    我们遇到了同样的问题,但我们的验证器需要继续针对 4.0 构建,以便它可以在 4.0 或 4.5 环境中使用,因此我们无法使用 Jaap 发布的解决方案。我们的解决方案是在 HttpContext.Items 中放置一个标记,让我们知道验证已经在进行中,这样当触发嵌套验证时,我们可以简单地让它通过。

    
    public class WifRequestValidator : RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;
    
            if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
            {
                if(AlreadyValidating(context))
                {
                    return true; // Allows us to bypass check that happens as a result of trying to use context.Request.Form
                }
    
                StartValidating(context);
                if (IsWsFedSigninResponse(context))
                {
                    return true;
                }
                EndValidating(context);
            }
    
            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }
    
        private static bool AlreadyValidating(HttpContext context)
        {
            return context.Items["__ApprendaRequestValidatorInProgress"] != null;
        }
    
        private static void StartValidating(HttpContext context)
        {
            context.Items["__ApprendaRequestValidatorInProgress"] = new object();
        }
    
        private static bool IsWsFedSigninResponse(HttpContext context)
        {
            return WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage != null;
        }
    
        private static void EndValidating(HttpContext context)
        {
            context.Items["__ApprendaRequestValidatorInProgress"] = null;
        }
    }
    

    【讨论】:

      【解决方案5】:

      注意,在 4.5 请求验证模式下,如果您的 asp.net 服务器端代码在 siginin 期间(即发布 SAML 令牌时)使用 Request 对象,您可能还需要做一些额外的工作。 默认情况下,即使打开了 4.5 请求验证模式,在发布 SAML 令牌时也会抛出 Request.Params。

      【讨论】:

        猜你喜欢
        • 2016-03-14
        • 1970-01-01
        • 1970-01-01
        • 2013-07-21
        • 2017-11-06
        • 2013-05-16
        • 1970-01-01
        • 1970-01-01
        • 2014-05-30
        相关资源
        最近更新 更多