2010-01-19 15 views
6

Estoy usando Request.IsSecureConnection para verificar SSL y redirigir cuando corresponda. Cuando ejecuto mi sitio web asp.net en la nube de Rackspace, el servidor se ejecuta detrás de un clúster SSL, por lo que IsSecureConnection siempre devuelve falso. Lo mismo se aplica para verificar si la URL contiene "https: //", siempre es falsa, verifica el puerto, etc. Por lo tanto, el sitio web se queda atascado en un gran bucle de redirección.Verificar SSL cuando está alojado en Rackspace (Mosso) Cloud

¿Hay alguna otra manera de verificar SSL y redirigir cuando corresponda? ¿Alguien que haya hecho esto en la nube de Rackspace?

Public Class SecurityAwarePage 
    Inherits Page 

    Private _requireSSL As Boolean = False 

    Public Property RequireSSL() As Boolean 
     Get 
      Return _requireSSL 
     End Get 
     Set(ByVal value As Boolean) 
      _requireSSL = value 
     End Set 
    End Property 

    Private ReadOnly Property IsSecure() As Boolean 
     Get 
      Return Request.IsSecureConnection 
     End Get 
    End Property 

    Protected Overrides Sub OnInit(ByVal e As System.EventArgs) 
     MyBase.OnInit(e) 

     PushSSL() 
    End Sub 

    Private Sub PushSSL() 
     Const SECURE As String = "https://" 
     Const UNSECURE As String = "http://" 

     If RequireSSL AndAlso Not IsSecure Then 
      Response.Redirect(Request.Url.ToString.Replace(UNSECURE, SECURE)) 
     ElseIf Not RequireSSL AndAlso IsSecure Then 
      Response.Redirect(Request.Url.ToString.Replace(SECURE, UNSECURE)) 
     End If 

    End Sub 

End Class 
+0

No tiene nada que ver con la pregunta, pero usted tiene mi aprecio de usar const para cadenas simples como 'http' y 'https'. –

Respuesta

5

Aunque es difícil comprobar si SSL está comprometida una forma de evitar el problema es forzar SSL.

Desde el RackspaceCloud Support knowledge base:

Puede URL en web.config volver a escribir:

<configuration> 
<system.webServer> 
    <rewrite> 
    <rules> 
     <rule name="Redirect to HTTPS" stopProcessing="true"> 
     <match url=".*" /> 
     <conditions> 
      <add input="{HTTP_CLUSTER_HTTPS}" pattern="^on$" negate="true" /> 
      <add input="{HTTP_CLUSTER-HTTPS}" pattern=".+" negate="true" /> 
     </conditions> 
     <action type="Redirect" url="https://{HTTP_HOST}{SCRIPT_NAME}" redirectType="SeeOther" /> 
     </rule> 
    </rules> 
    </rewrite> 
</system.webServer> 
</configuration> 

Puede forzar SSL en ASP.NET:

<%@ Page Language="C#" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 

<script runat="server"> 
    protected void Page_Load(object sender, System.EventArgs e) 
    { 
    if(Request.ServerVariables["HTTP_CLUSTER_HTTPS"] != "on") 
    { 
     if(Request.ServerVariables.Get("HTTP_CLUSTER-HTTPS") == null) 
     { 
     string xredir__, xqstr__; 

     xredir__ = "https://" + Request.ServerVariables["SERVER_NAME"]; 
     xredir__ += Request.ServerVariables["SCRIPT_NAME"]; 
     xqstr__ = Request.ServerVariables["QUERY_STRING"]; 

     if (xqstr__ != "") 
      xredir__ = xredir__ + "?" + xqstr__; 

     Response.Redirect(xredir__); 
     } 
    } 
    Response.Write("SSL Only"); 
    } 
</script> 

<html> 
<head id="Head1" runat="server"> 
    <title>SSL Only</title> 
</head> 
<body> 
</body> 
</html> 
+0

Gracias, busqué en los archivos de ayuda y no me encontré con eso. Mirando hacia atrás, supongo que habría sido inteligente hacer un bucle en la colección ServerVariables y ver qué había allí. –

+0

Tengo curiosidad, ¿es "HTTP_CLUSTER-HTTPS" un error tipográfico? Tienes uno con dos guiones bajos, y uno con guiones bajos y un guion. –

+0

Las reglas de reescritura [link] (http://learn.iis.net/page.aspx/465/url-rewrite-module-configuration-reference/#Rule_action) reemplazan guiones con guiones bajos, por lo que probablemente no importen. Parece que funciona exactamente como se muestra aquí o con ambos guiones bajos de mi experiencia directa. – philw

5

me encontré con este mismo problema con Rackspace Cloud y terminé resolviéndolo implementando manualmente un método de extensión Request.IsSecureConnection() y reemplazando el RequireHttpsAttribute del framework por el mío. Con suerte, alguien más encontrará esto útil también.

/// <summary> 
/// Replaces framework-provided RequireHttpsAttribute to disable SSL requirement for local requests 
/// and properly enforce SSL requirement when used with Rackspace Cloud's load balancer 
/// </summary> 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 
public class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) { 
     if (filterContext == null) { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (filterContext.HttpContext.Request.IsLocal) 
      return; 

     if (!filterContext.HttpContext.Request.IsSecureConnection()) { 
      HandleNonHttpsRequest(filterContext); 
     } 
    } 

    protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext) { 
     // only redirect for GET requests, otherwise the browser might not propagate the verb and request 
     // body correctly. 

     if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { 
      throw new InvalidOperationException("The requested resource can only be accessed via SSL."); 
     } 

     // redirect to HTTPS version of page 
     string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; 
     filterContext.Result = new RedirectResult(url); 
    } 

} 

public static class Extensions { 
    /// <summary> 
    /// Gets a value which indicates whether the HTTP connection uses secure sockets (HTTPS protocol). Works with Rackspace Cloud's load balancer 
    /// </summary> 
    /// <param name="request"></param> 
    /// <returns></returns> 
    public static bool IsSecureConnection(this HttpRequestBase request) { 
     const string rackspaceSslVar = "HTTP_CLUSTER_HTTPS"; 

     return (request.IsSecureConnection || (request.ServerVariables[rackspaceSslVar] != null || request.ServerVariables[rackspaceSslVar] == "on")); 
    } 

    /// <summary> 
    /// Gets a value which indicates whether the HTTP connection uses secure sockets (HTTPS protocol). Works with Rackspace Cloud's load balancer 
    /// </summary> 
    /// <param name="request"></param> 
    /// <returns></returns> 
    public static bool IsSecureConnection(this HttpRequest request) { 
     const string rackspaceSslVar = "HTTP_CLUSTER_HTTPS"; 

     return (request.IsSecureConnection || (request.ServerVariables[rackspaceSslVar] != null || request.ServerVariables[rackspaceSslVar] == "on")); 
    } 
} 
+0

entonces, ¿por qué es necesario implementar un reemplazo para la clase RequireHttpsAttribute? – Corgalore

+0

@Corgalore Bueno, porque no puedo simplemente reemplazar HttpRequest.IsSecureConnection (una propiedad), que es lo que está comprobando el requisito RequireHttpsAttribute. Hice una * extensión * en HttpRequest llamada IsSecureConnection() (un método). Por lo tanto, mi reemplazo RequireHttpAttribute comprueba mi extensión en su lugar. –

Cuestiones relacionadas