Forum Moderators: phranque
I am trying to force https on some pages and default back to http on the rest. My rules are,
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(user-welcome.phpŠuser-details.php)$ [example.com...] [R=301]
RewriteCond %{SERVER_PORT} ^443$
RewriteRule !^/?(user-welcome.phpŠuser-details.php)$ http://www.example.com/%1 [R=301,L]
However, its not happening correctly. https pages are showing 404 whereas the rest of the pages if called from http redirect to homepage. Can you please help.
Kind Regards,
<IfModule mod_rewrite.c>
Options +FollowSymLinks -MultiViews
RewriteEngine onRewriteCond %{SERVER_PORT} =443
RewriteRule ^login/$ /login.php [L]# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcomeŠuser/details)/.*) [example.com...] [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcomeŠuser/detailsŠimages)/ http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
RewriteCond %{SERVER_PORT} =443
RewriteRule ^login/$ /login.php [L]
#
RewriteCond %{SERVER_PORT} =443
RewriteCond %{THE_REQUEST} [A-Z]{3-9}\ /login/\ HTTP
RewriteRule ^login\.php$ - [L]
#
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcomeŠuser/details)/.*)$ [example.com...] [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcomeŠuser/details)/ http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
The internal rewrites must follow, not lead the redirects. Remember, all external redirects first, in order from most-specific patterns & conditions to least-specific, followed by any internal rewrites, again in order from most-specific patterns/conditions to least-specific. Doing otherwise risks unintended operation and 'exposing' internally-rewritten filepaths as URLs!
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcomeŠuser/details)/.*) https://www.example.com/$1 [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcomeŠuser/detailsŠimages)/ http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
#
RewriteRule ^login/$ /login.php [L]
Jim
[edited by: jdMorgan at 7:10 pm (utc) on Nov. 27, 2009]
<IfModule mod_rewrite.c>
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcomeŠuser/details)/.*) [example.com...] [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcomeŠuser/detailsŠimages)/ http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
#
RewriteCond %{SERVER_PORT} =443
RewriteRule ^login/$ login.php [L]RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? 404.php [L]</IfModule>
Also if the substitution path in a rule does not itself include a question mark, get rid of the [QSA] flag, because it is not required; query strings pass through rewriterules by default unless the substitution URL explicitly changes them.
To reduce the "waste", go through your rules and look for commonalities that you can use, along with the power of mod_rewrite, to get rid of mostly-redundant rules.
For example, replace nine rules:
RewriteRule ^user/welcome/?$ user-welcome.php [L]
RewriteRule ^user/details/?$ user-details.php [QSA,L]
RewriteRule ^user/cashback/?$ user-cashback.php [QSA,L]
RewriteRule ^user/wishlist/?$ user-wishlist.php [QSA,L]
RewriteRule ^user/referrals/?$ user-referrals.php [QSA,L]
RewriteRule ^user/reviews/?$ user-reviews.php [QSA,L]
RewriteRule ^user/clicks/?$ user-clicks.php [QSA,L]
RewriteRule ^user/tickets/?$ user-tickets.php [QSA,L]
RewriteRule ^user/preferences/?$ user-preferences.php [QSA,L]
RewriteRule ^user/(welcomeŠdetailsŠcashbackŠwishlistŠreferralsŠreviewsŠclicksŠticketsŠpreferences)/?$ user-$1.php [L]
Jim
The internal rewrites must follow, not lead the redirects.
That's usually how I do it, but what I did was exclude login.php from the redirect ruleset, if (and only if) THE_REQUEST was for the directory /login/ exactly AND on port 443...
What I did should not have any ill-effects, because an original request for anything other than /login/ on port 443 still makes it to your ruleset. Like I said, not ideal, but should solve the issue.
One of the biggest issues here is not being in control of the site being worked on, because personally, I would put all 'secure' files rewritten to in a specific directory say, /secure-files/, and exclude any original request from the location, which eliminates any issues with further rulesets since they can only be accessed through an internal rewrite.
As far as putting the rewrites last goes, I understand what you are saying about putting them there, but what's going on now is exposing the file path too, so there is no added risk using mine if that's the 'risk issue' ... It's already happening, which means there must be the same risk involved either way. If not, there would be an error, not a redirect to the actual file on another port. Right?
I have exposed the full internal file path through an error message generated by the server even with all rewrites following all redirects.
It may be safer to always have the rewrites last, but it does not entirely eliminate the possibility of the internal server file path being exposed. It may entirely depend on server configuration, etc, but it is possible to expose the internal server file path even when the rewrites follow all redirects.... I know because I've done it!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? 404.php [L]
As long as you set a 404 header with the PHP page you'll be fine.
header('HTTP/1.1 404 Not Found');
I would change the rule to this, but it's technically unnecessary:
RewriteRule .? /404.php [L]
Check a 'missing' URL on your site with a header check (like the one available here in your control panel) and see what you get. I just did to quadruple check and make sure I'm correct...
I *often* include a custom 404 page on scripts that are rewritten to if a database result cannot be found and the header is correct as long as you serve it with PHP... It's actually the most effective way to serve a 404 on a dynamic site. Rewriting to the custom error page has exactly the same result.
I'm going to bounce out of this thread now and leave the rest of it to the two of you to figure out...
@ khuram one of the biggest problems is probably you not being familiar enough with the language you're working with to be able to take what we say and adjust it to your situation, which is really a tough spot for you to be in, because every solution is 'site specific' and even more than that, is 'situation specific' and we all have slight 'nuances' to how we do things and work around issues. I highly recommend taking some time (more if you already have) and getting very familiar with the language we are using, because unless you personally know what you are doing and can incorporate everything in here so it works every time you run the risk of security issues, especially when using https. There's a bunch of resource in the library and in the forum charter and I suggest you become very familiar with them, including the documents on regular expressions.
Have a great day, both of you, and best of luck to you khuram.
<added>
I'm not always very good at typing in this little reply box, and just noticed my condition using THE_REQUEST is not start anchored... if you decide to use it, you probably should. It will work as is, but would be more technically sound like this:
RewriteCond %{THE_REQUEST} ^[A-Z]
</added>
If error document handling is exposing internal filepaths, then there is something else wrong with the server -- and again, it's likely something that can be fixed without adding more code. Something, somewhere, is invoking a redirect, and so 'informing' the client and exposing the internal path; Since errordocuments are normally served in the context of the originally-requested URL, this should not happen. And note that that is "URL," not filepath; internal rewrites should not change anything about this.
@khuram: It should not be necessary to do anything special using mod_rewrite to handle missing files; Just declare your 404 error document:
ErrorDocument 404 /404.php
In both cases described here, simple is better, IMHO.
Jim
Not to put too fine a point on it, but my objection to adding a "skip rule" to cure a problem that can easily be fixed by simply putting the rules in the right order is just that it adds code unnecessarily, plain and simple. Unnecessary code is bad code, because it slows down serving pages. Other than that, to each his own...
I assumed khuram actually did as they posted and didn't just flat out lie, otherwise I would not have bothered to post, but the two of you were 30 posts into an 'it's not working thread' so I figured I would present an alternative to the standard solution, because if khuram tried the code as they stated and it did not work then something else (which may be out of their control) is *obviously* having an effect. Your code following my post was *exactly* what they said they already tried, except theirs had a ? following the / which should have rewritten more requests and duplicated the login page at two different locations.
They should *not* have been redirected to http://www.example.com/login.php from the internal rewrite, but I don't think khuram just made it up, so obviously they were and something was not working as expected. I presented a solution that would work with *minimal* extra code roughly 30 posts into the thread. It won't happen again.
If error document handling is exposing internal filepaths, then there is something else wrong with the server
And not all of us have the luxury of maintaining the server to correct whatever error(s) may exist to be causing the issue and have much more productive things to do with our time than troubleshooting an error for a hosting company or even caring why the 'error' (or just plain difference) happened, because we can either use a 5 minute, two line work around or move the site if the slight amount of code bloat becomes an issue.
Further, if the hosting company doesn't want code bloat on their servers then they should maintain them so standard code works, because when you (I anyway) have to move a site from one host where I had httpd.conf access and everything worked *exactly* as coded and as it should, but does not work as previously coded or expected on the new host where I do not have httpd.conf access, I can relatively safely assume there is something the new host is doing differently that is not 'stock standard' and I really don't care that much when all the solution involves is two lines of stinking code bloat, because as I previously stated: I have better things to do with my time, which does not include contributing much more in this thread for sure and most likely not in this forum either.
@khuram: It should not be necessary to do anything special using mod_rewrite to handle missing files; Just declare your 404 error document:ErrorDocument 404 /404.php
Why on Earth would you not just post that the first time rather than saying a proper 404 will not ever be served by rewriting to an error page, which is a complete fallacy?
I think it's time for me to retire from the Apache Forum again...
Can you confirm that the rules in your code are now in this order, and please tell us your current status and test results?
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcomeŠuser/details)/.*) https://www.example.com/$1 [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcomeŠuser/detailsŠimages)/ http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
#
RewriteRule ^login/$ /login.php [L]
So, it's possible the problem was caused simply by incorrect rule order.
... and maybe that's the problem here, but you have not reported multiple redirects, only failures to redirect. You could try changing the redirect rules to:
Options +FollowSymLinks -MultiViews
RewriteEngine on
#
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((loginŠuser/welcome/Šuser/details/).*) https://www.example.com/$1 [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(loginŠuser/welcome/Šuser/details/Šimages/) http://www.example.com%{REQUEST_URI} [R=301,L]
#
# Redirect non-canonical hostname requests to canonical hostname using originally-requested protocol
RewriteCond %{HTTP_HOST} !^(www\.example\.com)?$
RewriteCond %{SERVER_PORT}>s ^(443>(s)Š[0-9+]>s)$
RewriteRule ^(.*)$ http%2://www.example.com/$1 [R=301,L]
#
RewriteRule ^login/?$ /login.php [L]
This removes the requirement for any specific characters following "/login" in the requested URL-path. That is, http requests for either "/login", "/login/", or "login.php" will be redirected to https.
Jim
My man, I dont know how to thank you but it has started to work. I may not be the most useful man in the world but if there is anything I can do for you in return, I will be your servant. :)
Honorable mention to @TheMadScientist for showing such interest in such a noob situation.
I'll post something here if something is missing but I have been able to remove the in-secure contents alert as well. Things are finally looking up.
Yours truly,
Khuram Javaid
A slight bump. I know nothing for you though :).
you see, to https the login page, we have done
RewriteRule ^((login¦ ....
However, for user/welcome, we have done,
RewriteRule ^((....¦user/welcome/¦....
But this is not happening, its sending /user/welcome/ page to /user-welcome.php page. Although no error but no https either. Please correct me. :)
It's up to you to determine if the patterns in these rules are correct *for your URLs in the way you wish to use them* -- We do not know anything about your site except what is posted in this thread...
If you do not intend the 'welcome' page to require a trailing slash, then remove that trailing slash from the RewriteRule pattern.
Be aware however, that you should decide whether you want trailing slashes or not; Pick either trailing-slashes or no trailing slashes, and if you get a request for your non-preferred URL format, then redirect it to the preferred format (with the correct http/https protocol as well). This will prevent duplicate-content problems in the search engines.
Jim
thank you for the insight.
What I have done is simplify my https through following method. Instead of /user/welcome/ i have just done ¦user¦
# Redirect secure pages requested via http to https
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^((login¦register¦user¦admin).*) [example.com...] [R=301,L]
#
# Redirect non-secure pages requested via https back to http
RewriteCond %{SERVER_PORT} =443
RewriteRule !^(login¦register¦user¦admin¦images/¦css/¦resources/¦js/) http://www.example.com%{REQUEST_URI} [R=301,L]....
...
..RewriteRule ^user/welcome/?$ user-welcome.php [L]
and its rewriting all user pages. However, it doesnt happen with either /user/welcome or /user/welcome/ in the https clause. Can you take a look.
Make sure the pipes are correct, completely-flush your browser cache... If that doesn't help, we may need some news eyes on this thread, because I don't see any problems.
Jim