Friday, July 20, 2012

WCF REST com Characteres especiais na URI


Suponha uma aplicação que consome serviços WCF REST, e que por algum motivo, precisa passar como chave characteres especiais, por exemplo:

Serviço - http://servico.com/Produtos/{key1}/{key2}

Vamos chamar o serviço da seguinte maneira: http://servico.com/Produtos/Livro/SN#908762

Repare que o número de série do livro sendo pedido contém o character especial '#' .

Usamos o código abaixo para consumir o serviço:

public void BuscarProduto()
{
               var factory = Services.Factory.Produtos();              
                factory.Get(p.Tipo, p.ID);

}

public static class Factory
    {
        private static  string GetUri(string serviceKey)
        {

            return  System.Configuration.ConfigurationManager.AppSettings[serviceKey];
        }
        public static IProdutos Produtos()
        {
            string uri = GetUri("RESTServiceProdutos");
            var factory = new WebChannelFactory<WcfRestServicesLayer.Administrativo.Usuarios.IProdutos>(new Uri(uri));

            return factory.CreateChannel();
         
        }
    }


 Se algum dos charcteres %,&,*,:,<,>,+,#, /, ?,\  estiver contido na chave no momento em que o método factory.Get for executado, o ASP.NET retorna um erro 400 Bad Request ou 404 Not Found

Existem vários motivos para isso acontcer, mas o motivo principal é a politica de segurança do asp.net.  O asp.net está na verdade se defendendo de possíveis tentativas de injeção de código e ataques ao seu serviço. 

Permitir estes characteres nas chaves é possível sim, mas não é recomendado pois deixaria o seu serviço vulnerável.

Para permitir os characteres especiais temos os passos abaixo:

Para permitir os chars %,&,*,:,<, e > insira no arquivo web.config:

<httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0"/> 
<pages validateRequest="false"/>

Para permitir o char +  adicione

<system.webServer> 
  <security> 
    <requestFiltering allowDoubleEscaping="true" /> 
  </security> 
</system.webServer>
 
Para liberar o char #, ?, / e \ é necessário escrever alguma espécie de Parser (conversor)
 e adicioná-lo ao construtor do seu serviço e depois modificar o web.config

Abaixo segue um exemplo de parser escrito pelo Peter Tian (http://social.msdn.microsoft.com/profile/peter%20qian%20-%20msft/?ws=usercard-hover)
Ele própio não recomenda a utilizção deste código, é apenas uma prova de conceito e pode danificar seus servidores de produção.

public Produtos()
{
    string uri = HttpContext.Current.Request.Url.OriginalString; 
    StringBuilder replaceUri = new StringBuilder();

    bool inquote = false; 
    for (int i = 0; i < uri.Length; ++i) 
    { 
        switch (uri[i]) 
        { 
            case '\'': 
                replaceUri.Append(uri[i]); 
                inquote = !inquote; 
                break; 
            case '#': 
            case '\\': 
            case '/': 
            case '?': 
                if (inquote) 
                { 
                    replaceUri.AppendFormat("%{0:X}", (int)uri[i]); 
                } 
                else 
                { 
                    replaceUri.Append(uri[i]); 
                } 

                break; 
            default: 
                replaceUri.Append(uri[i]); 
                break; 
        } 
    }
}

<configSections> 
    <section name="uri" type="System.Configuration.UriSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 
</configSections> 
<uri> 
    <schemeSettings> 
        <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes"/> 
        <add name="https" genericUriParserOptions="DontUnescapePathDotsAndSlashes"/> 
    </schemeSettings> 
</uri>


Antes de tentar aplicar os work-around mencionados acima, você deveria rever a arquitetura da sua aplicação. A recomendação é que não existam characteres especiais na URI, por medidas de segurança.


No comments:

Post a Comment