Forum Moderators: phranque

Message Too Old, No Replies

Rule for specific page(s) not rewritting to https

https, ssl, http, combining rules, mod_rewrite

         

elbowlobstercowstand

8:25 am on Jan 23, 2007 (gmt 0)

10+ Year Member



First, let it be known that I saw it snow (floaty and fluffy type of snow) in Scottsdale, Arizona for the second time in my life... weird.

Second, let it be known that I am a mod_rewrite hack, just learning, and I thought I had the basics understood, until... I tried to redirect people trying to login to my site (https) to a secure login (https). Here are the rules I thought would work, but are getting me nowhere. (Jim/jdMorgan, I have read many of your awesome posts but can't seem to put 2 and 27 together):

RewriteEngine on
Options +FollowSymLinks
RewriteBase /

#redirect them to https.
#rule_source_is:http://joseph.randomnetworks.com/archives/2004/07/22/redirect-to-ssl-using-apaches-htaccess/
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^login\.php$
RewriteRule (.*) [%{HTTP_HOST}%{REQUEST_URI}...]

I also tried:

%{REQUEST_FILENAME} login.php

and various other shotgun attempts. In the end, I would like to be able to list out a handful of files that redirect/rewrite into https. Something like:

RewriteCond %{REQUEST_URI} ^(login.php¦edit_billing.php)$

so all my sensitive pages would be ssl. Additionally, as a bonus, I would love to do the inverse for my non-ssl pages... like if someone travels from a https page to, lets say, index.php, I would like it to revert to http again. I would prefer to not have to use seperate directories for the files, but am definitely willing to append some encoding like "_secure.php" to file names to make the rules work. Looking forward to being humbled...

jdMorgan

7:46 pm on Jan 23, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You haven't told us what URLs you used to test the code, or what the results were, so it's a bit difficult to offer any opinions.

You can indeed make a list of pages to be redirected from HTTP to HTTPS. Then it is a simple matter to negate the regular-expressions pattern you used to do that for use in redirecting non-HTTPS pages back to HTTP. Taking your example, this would be

^(login\.php¦edit_billing\.php)$
and
!^(login\.php¦edit_billing\.php)$

You may want to try using

RewriteCond %{SERVER_PORT} ^443$
and
RewriteCond %{SERVER_PORT} !^443$
instead of
RewriteCond %{HTTPS} on [NC]
and
RewriteCond %{HTTPS} off [NC]


# Redirect secure pages to HTTPS if requested with HTTP
RewriteCond %{HTTPS} !^443$
RewriteRule ^(login\.php¦edit_billing\.php)$ https://www.example.com/$1 [R=301,L]
#
# Redirect non-secure pages to HTTP if requested by HTTPS
RewriteCond %{HTTPS} ^443$
RewriteCond %{REQUEST_URI} !^/(login\.php¦edit_billing\.php)$
RewriteRule (.*) http://www.example.com/$1 [R=301,L]

Note that the %{REQUEST_URI} pattern must contain a leading slash as shown.

Replace all broken pipe "¦" characters above with solid pipe characters before use; Posting on this board modifies the pipe characters.

Jim

elbowlobstercowstand

10:24 am on Jan 24, 2007 (gmt 0)

10+ Year Member



Wow... thank you SO MUCH! I updated my .htaccess file with your code and at first things weren't working right... until I modified it with the alternate that you suggested. Here is what ended up working for me (thanks to you):

# Redirect secure pages to HTTPS if requested with HTTP
RewriteCond %{SERVER_PORT}!^443$
RewriteRule ^(login\.php¦edit_billing\.php)$ [example.com...] [R=301,L]
#
# Redirect non-secure pages to HTTP if requested by HTTPS
RewriteCond %{SERVER_PORT} ^443$
RewriteCond %{REQUEST_URI}!^/(login\.php¦edit_billing\.php)$
RewriteRule (.*) http://www.example.com/$1 [R=301,L]

The %{SERVER_PORT} was the trick... and how you knew to suggest that alternate is beyond me.

Thanks again Jim for your expertise, time, and promptness... you just took a major weight off my shoulders for a looming deadline. I'll be sure to learn from your code...

elbowlobstercowstand

9:18 pm on Jan 24, 2007 (gmt 0)

10+ Year Member



Problem: I am using the above code and it seems to be working great, however (and possibly NOT related), I'm getting the old "broken padlock symbol" in firefox (meaning the page is not completely secure: https/ssl). I notice this is due to an externally referenced style sheet (although referenced through a relative url) like so:

<link rel="stylesheet" type="text/css" href="mystylesheet.css" media="screen" />

and that sheet contains this relative background image in the body:

body {
background: url("images/image.gif") repeat-x 0 0;
}

The image loads fine, but for some reason only loads in http: ... I haven't fully looked into this yet and will post something once I find out about it, but until then, feel free to toss in your suggestions.

elbowlobstercowstand

10:23 pm on Jan 24, 2007 (gmt 0)

10+ Year Member



Aha... with onlly 3 hours of sleep, I'm feeling smart again. I've identified the problem, and it has been staring me in the face the whole time. The rewrite rules used above are very explicit... what was happening was the external mystyle.css (which is a file just like any of my *.php files) was getting rewritten with the rule. For whatever reason it didn't occur to me that the rewrite would apply to the css as well.

Anyway, didn't Einstein say that he would spend 99% of his time definining the problem, and 1% fixing it? I've defined the problem, sort of. But now I need to get into mod_rewrite to write a rule (or an exception in an existing rule) that says "hey, when referencing the external style sheet, don't apply the rules above" or something like that. Sorry. I talk a lot... and I am definitely no Einstein...

jdMorgan

10:30 pm on Jan 24, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Now you have to define when the CSS file should, and should not, be redirected to or from HTTPS.

Jim

elbowlobstercowstand

11:13 pm on Jan 24, 2007 (gmt 0)

10+ Year Member



Yes... I'm actually understanding what I'm doing right now and things are working. I've dropped the shotgun, and am now attempting to wield the sniper rifle... picking one character off at at time. The regular expressions are what kill me, but this post:

[webmasterworld.com...]

has been an invaluable guide in helping me tweak the code. Here is what I have, and it is working great (note, I prefixed each piece with comments as if I was coding in PHP to help me understand what is going on):


RewriteEngine on
Options +FollowSymLinks
#RewriteBase /
#
# Redirect secure pages to HTTPS if requested with HTTP
# IF uri does NOT contain a .css file AND...
# IF server port is NOT 443 AND...
# IF the uri contains login.php OR edit_billing.php OR etc...
# THEN make it secure with https
RewriteCond %{REQUEST_URI}!^/mystyle\.css$
RewriteCond %{SERVER_PORT}!^443$
RewriteCond %{REQUEST_URI} ^/(login\.php¦edit_billing\.php)$
RewriteRule (.*) https://www.mysite.com/$1 [R=301,L]
#
# Redirect non-secure pages to HTTP if requested by HTTPS
# IF uri does NOT contain a .css file AND...
# IF port is 443 AND...
# IF the uri does NOT contain login.php OR edit_billing.php OR etc...
# THEN make it insecure
RewriteCond %{REQUEST_URI}!^/mystyle\.css$
RewriteCond %{SERVER_PORT} ^443$
RewriteCond %{REQUEST_URI}!^/(login\.php¦edit_billing\.php)$
RewriteRule (.*) http://www.mysite.com/$1 [R=301,L]

Some questions/challenges (the perfectionist in me) I'm facing:

1) i tried to test the passed url (e.g. [mysite.com...] and not modify it using:

RewriteCond %{REQUEST_URI}!^/*\.css$

but that didn't work. Not sure why. Learning as we speak.

2) Jim, why did you mention before that you have to have a leading / when testing REQUEST_URI?

3) Is there a way to see all the variables I have available to test, and to see what their actual value is b4 testing them? That would make things a lot easier...

4) Jim, in your original solution, you had a rewriterule that said:

RewriteRule ^(login\.php¦edit_billing\.php)$ [example.com...] [R=301,L]

I'm assuming that is shorthand of cond/rule in one statment. Any advice/tips on that, because that was the thing that really confused me in the beginning (hence, I broke it up in my statements...) is that bad for performance or anything?

jdMorgan

12:19 am on Jan 25, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



1) RewriteCond %{REQUEST_URI} !^/[^.]+\.css$
Re-read the regex thread you cited: "/*" would match zero or one slashes, but not any filename preceding ".css".

2) Because the following two snippets are equivalent and correct:


RewriteRule [b]^f[/b]oo\.php$ /bar.php [L]
#
RewriteCond %{REQUEST_URI} [b]^/f[/b]oo\.php$
RewriteRule . /bar.php [L]

but the former is far more efficient.

Note that in .htaccess (per-directory context), the URL-path 'seen' by RewriteRule does not start with "/", whereas the value in %{REQUEST_URI} always does.

3) The list of variables accessible to mod_rewrite is in the RewriteCond documentation. One way to see them is to use a test rule like:


RewriteRule ^foo\.php$ http://www.example.com/bar.php?Req_URI=%{REQUEST_URI}&Host=%{HTTP_HOST} [R,L]

The redirect will 'expose' the variables' values in your browser address bar.

4) Because RewriteRule can test a version of REQUEST_URI, it is far faster and simpler to use that facility when possible. Also, RewriteConds are not processed unless the RewriteRule pattern matches, so it's best to make that pattern as selective as possible. See the rule processing diagram in the mod_rewrite docs.

Continue to follow Albert's directive: "Make everything as simple as possible, but no simpler." And avoid introducing "cosmological constants" at any cost... :)

Jim

[edited by: jdMorgan at 12:19 am (utc) on Jan. 25, 2007]

elbowlobstercowstand

5:02 pm on Jan 30, 2007 (gmt 0)

10+ Year Member



Jim, thanks so much for those answers. You are mod_rewrite master.

New question (a little off topic maybe, but maybe not):

The code that jdMorgan wrote above and I modified works wonderfully in Firefox. You flow from http pages to https pages without a hitch. Internet Explorer (IE) 6.x, however is a different story.

For testing, I went to Tools/Internet Options/Advanced and pressed "Reset Default Settings." This is the way I'm betting most people view my pages. Anyway, what happens is that when they hit a secure page you are asked to "click" through a series of message boxes. The first one is normal: "You are about about view information over a secure connection..." fine... click. No biggie. But then, after the main body of the page loads, the images begin loading in (some of which are located in a *.css file, others wich are realtive urls in the page), and IE pops up a box FOR EACH image that says "You are about to leave a secure connection." Click... <less trust>... click... <less trust>... (note that mod_rewrite IS in fact rewriting thing securely. It just doesn't look that way to the user...

And worst of all, after clicking all the boxes, I don't see the padlock bottom right of the browser. Obviously all this is bad for buyer's confidence. So.... any ideas as to this behavior and how to fix it?

"Dear IE, You make my life harder than it needs to be. Can you stop being so mean to me?"

-christian

jdMorgan

5:13 pm on Jan 30, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Check each image link on the page (Tools -> Page Info -> Media in Firefox). All objects included on the secure page must have https in their URL, and point to the same domain as the page itself.

Get those on-page links correct first, and then rewrite them if necessary.

Jim

elbowlobstercowstand

10:10 pm on Jan 30, 2007 (gmt 0)

10+ Year Member



Possibly a miscommunication here... page info in Firefox checks out wonderfully (that is to say, any links are https). Firefox displays the padlock as expected. There are NO messages that pop up that say "you are viewing a partially encrypted page." Everthing works in Firefox great.

However, in IE 6.0 things are a bit different. Everytime an image loads it brings with it the message of "you are about to leave a secure connection..."

This makes no sense to me. Why would IE render the security of the page different? Mod_rewrite is still doing it's thing properly (as evidenced in Firefox). Yet IE is saying the page is insecure (no padlock ever appears) even though. And IE doesn't have a menu that allows you to check through what is causing the insecurity, although I can assume (due to the warning messages) it is not rendering the images as https....

I can sticky you the website address if you want to see it for yourself (if you have access to IE 6.0). Let me know.

jdMorgan

10:36 pm on Jan 30, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The first step to proper https operation is proper on-page links. If they are not correct, then the mod_rewrite code is irrelevant, since the browser checks those links before sending them as requests to your server. Only after a request for one of those URLs arrives at your server can mod_rewrite do anything with them. You are getting failures before that step, so you need to check the links.

Also, be sure to completely flush your browser caches before testing any changes to .htaccess or server config files.
In MSIE: Tools->Internet Options->General->Browsing History->Delete->Temporary Internet Files->Delete Files.
In Firefox: Tools->Options->Privacy->Private Data->Clear Now

If your browser has old content or responses cached for any or all of those image URLs, then you'll be seeing those old responses until those cache entries expire or until those entries are overwritten with newer cache entries.

Jim