Desenvolvimento - WIF

Validando a postagem do WIF

Quando estamos utilizando um STS para autenticar uma aplicação ASP.NET (ambiente passivo), somos redirecionados para a aplicação autenticadora, nos identificamos e caso seja um usuário válido, o token será criado e postado para a aplicação (relying party) que requisitou. Essa aplicação utilizará o WIF para extrair as informações do token, validá-las e deixá-las disponíveis para serem utilizadas.

por Israel Aéce



Quando estamos utilizando um STS para autenticar uma aplicação ASP.NET (ambiente passivo), somos redirecionados para a aplicação autenticadora, nos identificamos e caso seja um usuário válido, o token será criado e postado para a aplicação (relying party) que requisitou. Essa aplicação utilizará o WIF para extrair as informações do token, validá-las e deixá-las disponíveis para serem utilizadas.

O token é serializado em formato XML, contendo todas as informações de infraestrutura (envolvendo os artefatos de segurança) e as claims. Como o conteúdo da serialização é extenso, o STS envia isso através do body de uma requisição HTTP, que é realizada através do método POST, e é aqui que o problema reside.

Por questões de segurança, o ASP.NET não permite postar requisições que contenham em seu corpo tags, para evitar problemas de cross-site scripting (XSS). Como o WIF posta uma mensagem com conteúdo XML, o ASP.NET barra logo nos primeiros estágios da requisição. Uma solução que existe desde as primeiras versões do ASP.NET, é desligar essa verificação na página que recebe a requisição com o token do WIF. Para isso basta definir o atributo ValidateRequest da diretiva @Page para False.

Desligando essa verificação, iremos conseguir receber o token do WIF, mas abriremos uma porta para que pessoas maliciosas possam explorar e, consequentemente, danificar a nossa aplicação. Felizmente na versão 4.0 do ASP.NET a Microsoft permitiu que se customize essa validação, criando um validador próprio que podemos analisar a requisição, e mesmo que ela esteja postando tags, não quer dizer que ela seja maliciosa, assim como é o caso do token do WIF.

Para criar um validador customizado, devemos criar uma classe que herde da classe RequestValidator. Essa classe fornece um método virtual chamado IsValidRequestString, que deve ser sobrescrito na classe derivada, que determinará se a requisição é válida ou não. Esse método recebe vários parâmetros, que fornecem todas as informações necessárias para criarmos a regra de validação. Entre esses parâmetros temos o contexto da requisição (HttpContext), uma string que representa o valor a ser validado, que trabalha em conjunto com o um parâmetro do tipo RequestValidationSource, que especifica qual dado da requisição está sendo validado (Forms, QueryStrings, Headers, Cookies, etc.).

Como precisamos saber se a requisição trata-se de um token gerado pelo WIF, ele próprio traz métodos que permitem a criação de uma mensagem (RSTR) a partir do conteúdo de uma requisição HTTP. Sendo assim, se o conteúdo da postagem for válido e representa um token, então quer dizer que a requisição contém tags, mas são tags que correspondem a uma espécie de informação que sabemos como lidar, ou seja, não é maliciosa. O exemplo abaixo ilustra como efetuar esta implementação, recorrendo a tipos que o WIF fornece:

public class ValidadorDoToken : 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))
{
SignInResponseMessage message =
WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage;

if (message != null)
{
return true;
}
}

returnbase.IsValidRequestString(context, value, requestValidationSource,
collectionKey, out validationFailureIndex);
}
}

Como todas as informações da requisição são passadas para o validador, note que a condicional verifica se estamos recebendo o body da requisição, e como o body pode ter vários campos, estamos interessados apenas naquele campo que corresponde ao token serializado que é representado pelo campo wresult.

O ASP.NET MVC também impõe este mesmo tipo de validação, que felizmente recorre a este mesmo validador, ou seja,podemos criar um único e utilizar por qualquer tipo de projeto, WebForms ou MVC. Apenas é necessário tomar cuidado quando você decora a ação (método) com o atributo ValidateInputAttribute. A finalidade deste atributo é justamente permitir a validação da requisição, mas na versão 4.0 do ASP.NET, a adição deste validador customizado fez comaquele atributo seja executado depois do validador, que por sua vez, roda logo no evento BeginRequest.
Israel Aéce

Israel Aéce - Especialista em tecnologias de desenvolvimento Microsoft, atua como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. Como instrutor Microsoft, leciona sobre o desenvolvimento de aplicações .NET. É palestrante em diversos eventos Microsoft no Brasil e autor de diversos artigos que podem ser lidos a partir de seu site http://www.israelaece.com/. Possui as seguintes credenciais: MVP (Connected System Developer), MCP, MCAD, MCTS (Web, Windows, Distributed, ASP.NET 3.5, ADO.NET 3.5, Windows Forms 3.5 e WCF), MCPD (Web, Windows, Enterprise, ASP.NET 3.5 e Windows 3.5) e MCT.