4
votes

I have an ASP.NET MVC application with Windows Identity Foundation authentication enabled with ADFS as STS. The application is now on .NET 4.5 with MVC 4. When I change the ASP.NET requestValidation from 2.0 to 4.5, I get this error:

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

I guess this is the redirect from ADFS. How can I fix this?

5

5 Answers

18
votes

Upgrade your application to use WIF 4.5 included in the framework: http://msdn.microsoft.com/en-us/library/jj157089.aspx

Set RequestValidation to 4.5 mode:

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

WIF 4.5 plays nicely with the request validation in ASP.NET 4.5.

5
votes

Eugenio guided me to the right direction. But the sample he is refering to is not working anymore in ASP.NET 4.5. As I already commented on his answer, it is resulting in a stackoverflow. This is because requestvalidation is now done when data is requested. So the validation is done when WSFederationMessage.CreateFromFormPost requests the data. This triggers our requestvalidator. And this requestvalidator calls WSFederationMessage.CreateFromFormPost again and so on. After some digging in the WIF code, I have now a slightly modified requestvalidator which is working. Instead of CreateFromFormPost we use CreateFromNameValueCollection (which is also used by CreateFromFormPost), but now we can feed it with 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);
    }
}
3
votes

Yes, this is the SAML token posted back from the STS (ADFS) in your case. You can disable validation as Garrett suggests or better yet, you can supply a proper validator that understands SAML tokens, which is very easy to do.

See this other question/answer: Potentially dangerous Request.Form in WSFederationAuthenticationModule.IsSignInResponse

0
votes

We had the same problem, but needed for our validator to continue to be built against 4.0 so that it can be used in either 4.0 or 4.5 environments so we couldn't use the solution that Jaap posted. Our solution was to drop a marker in HttpContext.Items to let us know that a validation is already in progress so that when the nested validation is triggered we can simply let it pass through.


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;
    }
}
0
votes

Note, with 4.5 request validation mode you may still have some additional work to do if your asp.net server side code uses the Request object during siginin (i.e. when SAML token is posted). By default, use of Request.Params will throw when SAML token is posted even with 4.5 request validation mode turned on.