简体   繁体   中英

HTTPS with URL rewriting is not working on appharbor

I have built an application on asp.net 3.5 which is hosted on AppHarbor . The problem is that on HTTPS URL rewriting is not working. The following is the code to run some of the pages on SSL:

string CurrentUrl = Request.Url.ToString();
string sPath = System.Web.HttpContext.Current.Request.Url.AbsolutePath;      
System.IO.FileInfo oInfo = new System.IO.FileInfo(sPath);
string sRet = oInfo.Name;       
string sDir = oInfo.Directory.Name;     
pageName = sRet;
if (sRet == "Register.aspx" || sRet == "Login.aspx" || sRet == "Post.aspx" || sRet == "ChangePassword.aspx" || sRet == "ChangeUserStatus.aspx" || sRet == "Verification.aspx" || sRet == "ContactInfo.aspx" || sRet == "Find.aspx" || sRet == "MyAccount.aspx" || sRet == "MyEmailAddresses.aspx" || sRet == "Load.aspx" || sRet == "MyPostedLoads.aspx" || sRet == "MySubmittedBids.aspx" || sRet == "MySavedAddresses.aspx" || sRet == "MyCarriers.aspx" || sRet == "MyPotentialLoads.aspx" || sRet == "MyFreightAlarms.aspx" || sRet == "MyFreightAlarmsPreferences.aspx" || sRet == "MyAddress.aspx" || sRet == "GetUserComments.aspx" || sRet == "MyCreditCard.aspx" || sRet == "MyWallet.aspx" || sRet == "InvoiceMe.aspx" || sRet == "MyShippers.aspx" || sRet == "MyCoWorkers.aspx" || sRet == "MyACH.aspx" || sRet == "RouteMap.aspx" || sRet == "Pricing.aspx" || sRet == "PricingPayment.aspx" || sRet == "PaymentProcessed.aspx")
{
    string NewUrl = "";

    if (!Request.IsSecureConnection && !string.Equals(HttpContext.Current.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.OrdinalIgnoreCase))
    {
        NewUrl = Regex.Replace(CurrentUrl,
                               @"^https?(://[^/:]*)(:\d*)?", 
                               "https$1", 
                               RegexOptions.IgnoreCase);

        Response.Redirect(NewUrl);
    }
}

And the rule for URL rewrite on web.config:

<rewrite>
  <rules>
    <rule name="Rewrite with .aspx" stopProcessing="true">
      <match url="^([^\.]+)$" />
      <action type="Rewrite" url="{R:1}.aspx" />
    </rule>
    <rule name="Redirect .aspx page requests" stopProcessing="true">
      <match url="(.+)\.aspx" />
      <action type="Redirect" url="{R:1}" />
    </rule>
  </rules>
</rewrite>

The problem is the that page remains in an indefinite loop and can not redirect properly.

RequireHttpsAttribute: If you're using the built-in RequireHttpsAttribute to ensure that a controller action always uses HTTPS you will experience a redirect loop. The reason is that SSL is terminated at the load balancer level and RequireHttps doesn't recognize the X-Forwarded-Proto header it uses to indicate that the request was made using HTTPS.

The "meat" is in bold.

See: AppHarbor SSL FAQ - specifically the Troubleshooting section.

It's the same issue if you have an SSL concentrator or similar device in front of your web server(s). It's quite common in "cloud hosting" environments....

Hth....

Like EdSF mentioned, the problem you are experiencing is because the SSL (HTTPs) is at the load-balancer level. Meaning, all requests that come into your ASP.NET application will be HTTP.

So in your application running on AppHarbor, the following will always be true:

Request : https://mysite.com/about
---------------------------------------------------------------------------------
-> Request.Url.Scheme // http
-> Request.Url.AbsoluteUri // http://mysite.com:port/about
-> Request.issecure // false

You rewrite rules are relying on the protocal/scheme to be https and it never will be, causing an infinite loop.

The way to check for HTTPS in your ASP.NET application running on AppHarbor would be the following:

string.Equals(Request.Headers["X-Forwarded-Proto"], 
              "https", 
              StringComparison.InvariantCultureIgnoreCase);

I also host my web application on AppHarbor and needed a better solution so I created the SecurePages project ( NuGet - GitHub ). This project allows you to configure secure/https URLs with string literals as well as regex. It also forces all other URLs to use HTTP. You can also register custom predicate delegates that act as HTTPs request matching rules. So you could register one for AppHarbor to check the headers:

//Secure a page    
secureUrls.AddUrl("/Register.aspx");

//Secure any page under /cart/*
secureUrls.AddRegex(@"(.*)cart", RegexOptions.IgnoreCase);

//Register a custom HTTPs match rule for AppHarbor
SecurePagesConfiguration.RegisterCustomMatchRule(
                c => string.Equals(c.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase));

Secure pages also supports Unit Testing and local browser testing with IIS Express.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM