Drupal and SSL - Multiple Recipes to Possible Solutions

As Matt Cheney likes to say "Much like Scrabble, the S is an important letter on the internet." If you really care about the data you are sending across the internet you want to make sure you are using SFTP instead of FTP, SSH instead of Telnet, and HTTPS instead of HTTP. So, within a Drupal site how can you use HTTPS to secure the data sent to and from your site and prevent sessions from being hijacked?

There are four basic solutions, though each has its benefits and drawbacks. I'll try to describe each one and give some guidance on the problems. They are covered from what seem to be the most common to the most secure. Note that the third technique is somewhat novel.

Note: All of these assume that you have configured your webserver to use SSL which is well documented elsewhere - I don't think that's useful to try to cover here.

Use the Securepages Module to Encrypt Login and Admin Pages

The Secure Pages module is a relatively old module and quite popular. It's goal is to only make certain pages of the site use HTTPS by using two lists of urls which should either by HTTPS or not. The benefit of this module is that you can use regular old HTTP for most of the site and only encrypt the traffic where you really need it. By default it will encrypt traffic for adding content, editing content, anything related to users, and for the admin area.

SSL processing is taxing on a server. Using SSL on just the most important pages helps make sure that the data sent back and forth on those pages is encrypted. However, the session cookie is still unencrypted so a user who authenticates over HTTPS and then visits a non secure page sends their sesssion identifier in the clear which allows for an attacker to steal their session and login to the site which gives them the access to the very data that was supposed to be protected. This is largely "security theater" but it sure makes people feel good.

Pro: Reduces load on server compared to a full SSL solution while encrypting important data transmission.
Con: Doesn't protect against session hijacking so data can still be compromised.

Using Securepages and Securepages Prevent Hijack

Noticing this weakness, the user grendzy created the Secure Pages Hijack Prevention. This module creates and sends along a second cookie that is marked as "secure" so that the browser will only send it over HTTPS. The module then tracks access to the site and logs out any user who attemps to visit an "important" page without sending along that second cookie.

Pro: Still reduced load on server with reduced damage from hijacking.
Con: Session hijack still possible, but limited in what damage can be done and data is still sent in the clear sometimes (may be an acceptable risk).

Use HTTPS for a session after login

This is a solution that one of my clients created to provide HTTPS pages for all logged in users, and keep all anonymous users on HTTP, but could be extended for other rules as well.

The major piece of the idea is in settings.php:


if ($_SERVER['HTTPS']) {
ini_set('session.cookie_secure', 1);
$base_url = 'https://example.com';
}
else
{
$base_url = 'http://example.com';
}

This little bit of code says "if the user is requesting a secure page, make sure that their cookie is marked as secure and that the base_url variable (used in many parts of Drupal) includes https - otherwise, use the regular http values." The use of the secure cookie flag prevents hijacking but does have one drawback: If the user has a bookmark for the homepage that is not https then their cookie won't be sent along to the site and they will appear to be logged out.

Combine that with a redirect from the regular "user/" pages to the https version and you should be all set.

Pro: Still simple, more complete than a "per path" SSL system, limited possibility to hijack a session.
Con: Potentially confusing to users under certain conditions.

Just Make All Drupal Pages SSL

This is the most secure solution, but also the most resource intensive on the server. If you just make all traffic to the site over HTTPS then it will all be encrypted - problem solved!

You can use Apache's mod_rewrite to achieve this:


RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R,L]

php_value session.cookie_secure 1

Pro: Complete solution. Simple - no extra modules required.
Con: May require more expensive servers, or additional servers.

Which Secure Page Solution Is the Best?

The best solution depends on your specific site, end-users, and privacy needs. Many sites don't need to worry about HTTPS at all. Some want to keep performance up as much as possible and only care about the security of the data en-route, but aren't concerned about session-hijacking (e-commerce where the credit card is not stored). As is often the case, you must balance multiple facets when considering the right solution for your site.

Got any other solutions? See any other pros or cons with the ideas presented here? Please let me know.

Comments

funny

I am working on http://drupal.org/node/1577#comment-1882244 this core patch right now. Care to land a hand? It's a novel idea, similar to Use HTTPS for a session after login but better.

Secure pages on shared hosts

Thanks for the good summary!

I have struggled to understand how to get secure pages with shared hosting SSL certificates provided by my Web host.

I think it would really boost Drupal security for lower-end, lesser-trafficked sites — the kind many people may use to learn Drupal — if there was a way to handle that scenario cleanly, easily, and preferably right in core. It seems that other CMS tools and frameworks handle this better, but maybe I'm just perceiving the grass in greener elsewhere.

In my case, the Web host gives a different URL path to get to my site when using the server's shared SSL certificate. They don't provide a different hostname, which some Web hosts may do (and which might be more convenient in some respects), but a different URL. That URL doesn't necessarily include my site's regular domain name — at least not until you get down to a deeper part of the URL path.

If there's a good resource for this topic — besides the Secure Pages issue queue — that I can be pointed to, I'd love to hear about it.

more a server question

I totally agree with you that it's important to make sure Drupal works in low cost hosting environments.

I think this is really more of a server question than it is a Drupal question. The idea of using a shared ssl certificate on a different domain/url is not required by shared host - you just need your own IP and either a self-signed certificate or a regular certificate.

SSL form submit is not working

Hi in my Drupal site the SSL added but now i submit the form means one blank page is display then after i refresh the page so many times then only i will get the display even in login itself

how can i solve this i tried

wrote one .htacess file in the root

RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R,L]

still not working

then i tried

$request_type = ($_SERVER['HTTP_X_FORWARDED_HOST'] == 'ssl.proxy.org') ? 'SSL' : 'NONSSL';
if($request_type!="SSL"){
//header("Location:https://ssl.proxy.org/www.example.com");
$base_url = 'http://www.mydailylifecoach.com'; // NO trailing slash!
//$cookie_domain = 'www.example.com';
} else {
$base_url = 'https://www.mydailylifecoach.com/SSL'; // NO trailing slash!
//$base_url = 'https://ssl.proxy.org/www.example.com/some/dir'; // NO trailing slash!
$cookie_domain = 'ssl.proxy.org';
$_SERVER['HTTPS']='on';
$_SERVER['REQUEST_URI']='https://www.mydailylifecoach.com'. $_SERVER['REQUEST_URI'];
//$_SERVER['REQUEST_URI']='/www.example.com'. $_SERVER['REQUEST_URI']; // Only the DNS name of the site needed here!
$conf = array(
'reverse_proxy' => TRUE,
'reverse_proxy_addresses' => array($_SERVER['REMOTE_ADDR']),
);
}

this is also not working any one hlp me to find the solutions in my drupal site

thank you
David
www.way2tour.com

get ssl working on its own first

This is tricky and depends on so many external factors, which is part of why I didn't cover it, but

still not working

If it's still not working you need to solve that first - try getting your site to work with all requests under HTTPS. If that works then you can start looking at one of these mixed mode solutions.

Mitigating User Confusion w/ 3rd Technique

If using the "Use HTTPS for a session after login" technique, I recommend writing a custom access denied menu item that redirects to the user's My Account if the user is trying to access the user/login path and they are already logged in on the HTTPS side, but followed the login link from the HTTP side. That will mitigate the con that you mentioned.

So add the following to the hook_menu in a custom module:

$items['custom/denied'] = array(
'access callback' => TRUE,
'page callback' => 'custom_denied',
'title' => 'Access denied',
'type' => MENU_CALLBACK,
);

Then write the following function:

function custom_denied() {
if (request_uri() == '/user/login' && user_is_logged_in()) {
drupal_set_message(t('You are already logged in.'));
menu_set_active_item('user');
$return = menu_execute_active_handler();
}
else {
drupal_set_title('Access denied');
$return = t('You are not authorized to access this page.');
}
return $return;
}

Lastly you will need to edit the site_403 variable. You can do this in your custom module by calling:

variable_set('site_403', 'custom/denied');

Can you elaborate on Securepages Prevent Hijack

What does it prevent and what does it fail to prevent?

Thanks!

Purpose of securepages prevent hijack

Sure thing. Basically the problem is that when you do "mixed mode" SSL someone can use the cookie from their secure session on a non https page which allows the cookie to be sniffed and the session to be hijacked.

Securepages Prevent Hijack prevents that ;)

Secure Page Prevent Hijack

In the article, you say "Session hijack still possible, but limited in what damage can be done and data is still sent in the clear sometimes (may be an acceptable risk)."

How is the damage limited, and when is the data sent in the clear (assuming on non https pages) ?

It is possible to hijack the

It is possible to hijack the session, but as long as you've configured securepages and securepages then the hijacked session will be lost as soon as the person tries to do something "important." The definition of important is up to your site and your configuration.

Since it is "mixed mode" ssl there will still be content sent in the clear on "unimportant" pages (i.e. those configured to not use ssl).

Caching and SSL

Hi,

will using the method "Use HTTPS for a session after login" cause problems with caching and modules such as pathfilter? I had SSL enabled and used Apache to enforce SSL for /user and /admin pages, but as soon as I enabled caching under Performance, it all went crazy. Some sites were cached in SSL, some not. Apparently, the cache does not differentiate between http or https versions and caches and delivers whatever was first opened. Example: I clear all caches, open 50% of pages in http and 50% of pages in https, then my cache will have 100% of my pages in the cache, but output internal links on my own site both in http and https...

Cheers, Jn.

New Drupal Module Inspired by this Blog Post

I wrote a simple module, 443 Session, incorporating some of the ideas in this blog post.

It forces all logged in users to use HTTPS for their entire session, while anonymous users use HTTP. It also implements the custom access denied handler as mentioned in the comments above, to mitigate confusion caused if a logged in user navigates to a HTTP page.

Another option if you have contributor/consumption separation

We use the following option and it works since all our logged in users (contributors) are internal users and the rest of our visitors are just viewing the public site (except for public comments).

The public (consumption) version of the site is available at http://mydomain.org. This points to the Drupal codebase and database. In this Apache virtualhost we use mod_rewrite to protect/hide important Drupal paths such as /user and /admin so no one accessing the site at this URL can get to those pages. You could also redirect users to the https URL for these pages, but we want to keep the contributor site private.

The private (contributor) version of the site is available at https://site1.mydomain.org. This points to the SAME Drupal codebase and database. In this Apache virtualhost we allow access to important Drupal paths and use the php configuration option mentioned in the post above, "php_value session.cookie_secure 1". Additionally you could enable another layer of authentication in Apache to completely protect this version of the site from unwanted visitors.

You can do this same setup using a single hostname and an SSL certificate for it, but if you are going to host multiple public sites on one server with this same configuration you can save some money by using a single wildcard SSL certificate for all the contributor sites. So if you buy a wildcard certificate for *.example.com you can use one IP address in Apache and still have multiple SSL virtualhosts like site1.mydomain.org, site2.mydomain.org, etc, for the secure URLs.

Some issues we've had with this setup is that it can be confusing for our less technical contributors in that they might enter an internal, absolute link to content using the wrong domain. This mistake can be corrected automatically by using a custom input filter or avoided by using a WYSIWYG editor with an internal node picker that inserts links without the domain (relative).

-Tim

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <h3> <blockquote> <br>
  • Lines and paragraphs break automatically.

More information about formatting options