Forum Moderators: phranque

Message Too Old, No Replies

mod rewrite SSL problem

         

ctoynbee

12:19 pm on Aug 27, 2009 (gmt 0)

10+ Year Member



Hi,

I have a website that needs a couple of pages to be SSL.

I'm trying to do this using mod_rewrite on apache.

Because the way the web-site has been coded I need to specify the pages in .htaccess that are need to be SSL like so:

########################################################
RewriteCond %{SERVER_PORT} 80$
RewriteCond %{REQUEST_URI} /company/contact-us?.*$ [OR]
RewriteCond %{REQUEST_URI} /request/test-drive?.*$
RewriteRule ^(.*)$ [%{HTTP_HOST}...] [R,L]
########################################################

This code above works ok...

Then I need to specify that all other pages need to be rewrite back to non-ssl. This is the part that isn't working for me. Can anyone help?

I assume this would be a list of pages to not force back to SSL (the ones above) and anything else needs to be forced back to http://

Ive tried this and it didnt force it back to http://

RewriteCond %{SERVER_PORT} 443
RewriteCond %{REQUEST_URI} !/company/contact-us?.*$
RewriteCond %{REQUEST_URI} !/request/test-drive?.*$
RewriteRule ^(.*)$ [%{HTTP_HOST}...] [R]

jdMorgan

12:59 pm on Aug 27, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Your RewriteCond patterns have three problems:

First, the patterns are not start-anchored and an un-escaped "?" means "zero or one of the preceding character or parenthesized sub-pattern," so the effect is to make the first RewriteCond match either <any-number-of-directories>/company/contact-us or <any-number-of-directories>/company/contact-u.

A secondary problem is that if this "?" *were* properly escaped to make it match a literal question mark, then the pattern would never match, because query strings are not part of the URL. Rather, they are data attached to the URL to be passed to the resource specified by that URL. As a result, neither the question mark nor the query string data will be present in the REQUEST_URI variable. The query string data is available in the QUERY_STRING variable if you wish to examine it, but the "?" delimiter is not present in either variable.

Lastly, the ".*$" at the end of the pattern is entirely unnecessary -- it does nothing and can be removed with no change whatsoever to the function. By removing the end-anchor, the pattern will still mean "Match the path /company/contact-us<anything>".

If you wish to require that that question mark always be present, but wish to allow the case where no query string follows that question mark, then things get complicated. You'll have to use THE_REQUEST and match patterns like
^[A-Z]+\ /company/contact-us\?[^\ ]+\ HTTP/
in order to match that kind of request line from the client.

Having fixed all four RewriteCond patterns, test again. If the SSL-to-non-SSL redirect still does not work, then the likely cause is that your SSL 'site' is hosted in a separate filespace from your non-SSL because it's implemented as a separate virtual host. If that's the case, then this .htaccess file won't be processed for SSL requests. You'll have to move the SSL-to-non-SSL redirect to a .htaccess file in the SSL server's filespace.

I've also seen cases where although both the SSL and non-SSL hosts are mapped to the same filespace, the configuration of these two servers is differnt, and mod_rewrite isn't enabled for the SSL vHost. So check the config files to make sure that's not the problem.

You may want to back off a bit and test only one very simple rule at a time, and go step by step instead of trying to debug both rules at the same time with two pages in each rule... "Divide and conquer" is often an effective strategy to reduce debugging time and preserve sanity.

BTW, these redirects should both specify [R=301,L] to avoid problems in the search engines.

Jim

ctoynbee

1:49 pm on Aug 27, 2009 (gmt 0)

10+ Year Member


HI Jim,

Thanks for replying so quickly it's much appreciated!

I've modified the file to read this based on your recommendations:

########################################################
# This work so dont change it.
RewriteCond %{SERVER_PORT} 80$
RewriteCond %{REQUEST_URI} ^/company/contact-us [OR]
RewriteCond %{REQUEST_URI} ^/request/test-drive
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
########################################################

RewriteCond %{SERVER_PORT} 443
RewriteCond %{REQUEST_URI} !^/company/contact-us
RewriteCond %{REQUEST_URI} !^/request/test-drive
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301]

Let me know if I've missing anything. I can't add the L to the last RewriteRule because there are more rules to process after that.

I can also tell you that the SSL and non-SSL hosts are mapped to the same file space.

Also I'm specifying: RewriteEngine on
at the top of the script.

Hopefully I've covered all your points - again let me know if I've missed something.

Unfortunately as before its the SSL to non-SSL part that isn't working. The non-SSL to SSL seems to fine.

Any other suggestions?

Many thanks.

jdMorgan

2:35 pm on Aug 27, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> I can't add the L to the last RewriteRule because there are more rules to process after that.

Be very careful here, as it is *highly* unusual that you would want to defer the 301 redirect until after further rules are processed. For example, if internal rewrite (URL-to-filepath translation) rules follow this external redirect (URL-to-URL translation) rule, then those (intended-to-be-) internally-rewritten filepaths will be 'exposed' to the client as URLs (i.e. visible in the user's address bar, and listed in search results). Therefore, this is almost *never* done.

When the 301 redirect is issued, the current HTTP(S) transaction is ended with the server's 301-redirect response to the client. The client will then (normally) repeat its original HTTP(S) request, but this time using the new URL supplied in the server's 301 redirect response. When this new HTTP(S) request arrives, the rules following the original redirect rule will then be applied. This is the normal scenario.

So I urge you to carefully consider your omission of the [L] flag, as this is literally a one-in-a-thousand exception to the normal method.

You took my 'server configuration' warning at too simple a level, I'm afraid. You'll need to check all server config settings to make sure that your AllowOverride is set in the SSL context to allow mod_rewrite to be enabled using Options +FollowSymLinks or Options +SymLinksIfOwnerMatch, and I further suggest that you disable MultiViews (content negotiation) and AcceptPathInfo (on Apache 2.x and above only) as these can interfere with mod rewrite. If you're doing any kind of reverse-proxying, then mod_proxy can also intercept the request before the rewrites are applied.

You might want to try something simple like


RewriteCond %{SERVER_PORT} =443
RewriteRule ^foo\.html$ http://www.google.com/ [R=301,L]

as an SSL test rule until you ascertain that this rule is being invoked. Request https;//example.com/foo.html from your server, and you should land at google. At that point, you can begin debugging problems with your 'real' SSL rule(s) -- although I don't see any problems that would cause them not to work, and so I believe that this is a matter of mod_rewrite (or the entire .htaccess file) not being invoked for SSL requests. But again, simplify, divide, and conquer.

Jim

ctoynbee

3:31 pm on Aug 27, 2009 (gmt 0)

10+ Year Member



Thanks again Jim.

I've put the L into the final rule.

I can also confirm that mod_rewrite is working for the SSL config because I can browse the rest of the site happily which using mod_rewrite on all pages.

Here's my directory:

<Directory "/path/to/filesystem/" >
Options Indexes FollowSymLinks
AllowOverride FileInfo Options AuthConfig Limit
</Directory>

however when I add this:

RewriteCond %{SERVER_PORT} 443
RewriteRule ^(.*)$ [google.com...] [R=301,L]

to the .htaccess file it doesnt redirect to google when its https:// so I think you are right and it must be something to do with the apache config.

I've added: AcceptPathInfo Off

to this list. I think Multiviews is off but I'm not 100% sure. TBH I'm not sure the syntax to disable this. It it related to Options?

Other than that I'm still a stumped because I have a still have a site that is SSL :(

jdMorgan

4:32 pm on Aug 27, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Use "Options -MultiViews" to disable multiviews.
You can combine this with other settings as needed for security/access control, such as
"Options +FollowSymLinks -Indexes -MultiViews"
See Apache core directives documentation.

In fact, it might be worth trying that latter Options statement right now, in case the server is configured with FollowSymLinks disabled for SSL. If so, mod_rewrite can't run (although you should be seeing an error in your error log in this case).

I also recommend that you change your first rule's first RewriteCond pattern to "=443" and your second rule's first RewriteCond pattern to "!=443" to require a precise string match in the first case, and a precise exclusion in the latter. As it stands now, there's some 'sloppiness' in what port numbers are and aren't going to be redirected... for example, your first rule now redirects any port that ends with "80", e.g. 80, 8080, 1080, 180, etc.

However, the failure of the google redirect test indicates that these rules are not being executed for SSL requests, and that's likely the root cause here.

If you are self-hosted, examine the httpd.conf file and *all other server config* files, and look for differences between the SSL/non-SSL config sections related to AllowOverride and Options as mentioned above.

If you're commercially-hosted, a call to your host's help desk would be in order, with the question being "What is it about your standard SSL server config that is different from your non-SSL config and results in my .htaccess mod_rewrite code not being invoked, or perhaps in my .htaccess file not being processed at all?"

If they try to weasel out by saying they don't support mod_rewrite questions (a common tactic because it costs them too much in support time to debug client's mod_rewrite code), point out that even the simplest rule (the google redirect) won't execute at all.

In fact you could temporarily and intentionally include a syntax error (i.e misspell a directive like "ReRightRuel") in your .htaccess file, and see if that error gets reported for both HTTP and HTTPS requests. If it only gets reported for HTTP requests and not for HTTPS, then that would conclusively prove that your .htaccess file isn't invoked at all for SSL requests.

Oh and do be sure to completely flush (delete) your browser cache after making any changes to your server configuration (httpd.conf, .htaccess, etc.) In fact, you may want to flush it between every test or even disable it temporarily in order to avoid the probability of your browser always showing you previously-cached pages and server responses whenever allowed by your (presumably-default) cache-control header settings.

Jim

ctoynbee

4:38 pm on Aug 27, 2009 (gmt 0)

10+ Year Member



Thanks Jim. I really appreciate your help. Very comprehensive and I've learnt a bit more about htaccess.