Desenvolvimento - ASP. NET
Definido páginas HTTPS com rapidez e segurança
Este artigo mostra uma maneira rápida e fácil de controlar a troca entre os protocolos HTTP e HTTPS com rapidez e segurança.
por Vinicius TutuyAtualmente é indispensável o uso do HTTPS em páginas onde há trafego de dados confidenciais. Dependendo do tamanho do sistema, essa tarefa não é muito rápida. Vou mostrar como construir um módulo (HttpModule) para controlar a troca entre os protocolos HTTP e HTTPS com rapidez e segurança.
O módulo funciona da seguinte forma:
- Quando chega uma requisição o módulo verifica se o protocolo é HTTP ou HTTPS.
- Caso seja HTTP ele verifica se a página está configurada para responder pelo HTTPS e redireciona o usuário para a página utilizando o protocolo seguro, caso contrário continua com a requisição normalmente.
- Caso seja HTTPS ele verifica se a página está configurada para responder pelo HTTPS e continua com a requisição normalmente, caso contrário redireciona o usuário para o protocolo HTTP para evitar tráfego excessivo de dados.
Após esta breve explicação da idéia, vamos aos códigos.
Desenvolvimento do Projeto
Primeiramente crie um novo projeto do tipo Class Library.
Criado o projeto, vamos desenvolver as classes que serão utilizadas como elementos nas configurações do Web.Config.
Pagina.cs
public class Pagina : ConfigurationElement { internal Pagina(): base() {}
internal Pagina(string nome) : this() { Nome = nome; }
[ConfigurationProperty("nome", IsRequired = true, Options = ConfigurationPropertyOptions.IsKey)] public virtual string Nome { get { return this["nome"] as string; } set { this["nome"] = value; } } } |
ColecaoPaginas.cs
public class ColecaoPaginas : ConfigurationElementCollection { protected override string ElementName { get { return "paginas"; } }
public Pagina this[int indice] { get { return BaseGet(indice) as Pagina; } }
public new Pagina this[string nome] { get { return BaseGet(nome.ToLower()) as Pagina; } }
protected override object GetElementKey(ConfigurationElement elemento) { return (elemento != null) ? (elemento as Pagina).Nome.ToLower() : null; }
protected override ConfigurationElement CreateNewElement() { return new Pagina(); } } |
Secao.cs
public class Secao : ConfigurationSection { [ConfigurationProperty("paginas")] public ColecaoPaginas Paginas { get { return this["paginas"] as ColecaoPaginas; } } } |
A parte de configuração já está pronta, agora vem à parte que realmente importa.
A classe Modulo.cs é uma classe que implementa IHttpModule. Está classe será responsável por receber todas as requisições e redirecionar o usuário para o protocolo correto, quando necessário.
Modulo.cs
public class Modulo : IHttpModule { private struct Prefixos { public const string Inseguro = "http://"; public const string Seguro = "https://"; }
public void Dispose() {}
public void Init(HttpApplication context) { if (context != null) { Secao secao = WebConfigurationManager.GetSection("paginasSeguras") as Secao; if (secao != null) { context.Application["PaginasSeguras"] = secao; context.AcquireRequestState += new EventHandler(Application_ProcessRequest); } } }
private void Application_ProcessRequest(Object source, EventArgs e) { HttpApplication context = source as HttpApplication; if (context != null) { Secao secao = context.Application["PaginasSeguras"] as Secao; ProcessarRequest(secao, context.Context); } }
private void ProcessarRequest(Secao secao, HttpContext context) { string novaUrl = ProcurarPagina(secao, context);
if (!string.IsNullOrEmpty(novaUrl)) context.Response.Redirect(novaUrl, true); }
private string ProcurarPagina(Secao secao, HttpContext context) { if (secao == null) return "";
string cloneUri = context.Request.Url.AbsoluteUri.Clone() as string; int indice = cloneUri.IndexOf("?"); string queryString = indice == -1 ? "" : cloneUri.Substring(indice); if (indice != -1) cloneUri = cloneUri.Substring(0, indice);
if (!cloneUri.EndsWith(".aspx")) return null;
string resultado = null; if (cloneUri.StartsWith(Prefixos.Inseguro)) { resultado = SelecionarPagina(cloneUri, queryString, secao); } else if (cloneUri.StartsWith(Prefixos.Seguro)) { string pagina = SelecionarPagina(cloneUri, queryString, secao);
if (string.IsNullOrEmpty(pagina)) resultado = cloneUri.Replace(Prefixos.Seguro, Prefixos.Inseguro) + queryString; }
return resultado; }
private string SelecionarPagina(string uri, string queryString, Secao secao) { if (String.IsNullOrEmpty(uri)) return null;
for (int i = 0; i < secao.Paginas.Count; i++) { string urlSegura = secao.Paginas[i].Nome; if (String.IsNullOrEmpty(urlSegura)) continue;
if (urlSegura[0] == "~") urlSegura = VirtualPathUtility.ToAbsolute(urlSegura);
if (uri.ToLower().EndsWith(urlSegura.ToLower())) return uri.Replace(Prefixos.Inseguro, Prefixos.Seguro) + queryString; }
return null; } } |
Agora só falta configurar o Web.Config para começar a validar as requisições, e redirecionar o usuário para o protocolo correto (Obs: As tags necessárias para o funcionamento do módulo estão em negrito).
Web.config
<?xml version="1.0"?> <configuration> <configSections> <section name="paginasSeguras" type="PaginasSeguras.Secao" /> </configSections> <paginasSeguras> <paginas> <add nome="~/DadosPessoais.aspx"></add> <add nome="~/Login.aspx"></add> </paginas> </paginasSeguras> <system.web> <compilation debug="true"/> <authentication mode="Windows"/> <httpModules> <add name="ModuloSeguro" type="PaginasSeguras.Modulo" /> </httpModules> </system.web> </configuration> |
Obrigado e até a próxima
Vinicius Tutuy