yeah, I need a tag line.

Securing a WordPress page with https

What I needed

I needed a way to secure a single page. This could be an order page or a page where I want to protect user information. The problem is, even if you simply try to go to “https://mysite.com/page”, you’ll be re-directed to the http page by WordPress. Furthermore, even if you use htaccess to force the content over https, you’ll still get “partially encrypted” errors.

What is out there

There was Admin SSL, which has a 4-star rating… but did not work for me; I think the developer stopped working on it and newer versions of WP don’t work with the plugin. I also tried HTTPS for WordPress, and that didn’t work either.

Because I couldn’t find anything… I put together this hack. I guess I could make it into a plugin, but I’m lazy.

How to do it

Required knowledge/tools:

  • Installation of CURL on your server
  • Basic knowledge of .htaccess, and how to edit the file
  • Basic php knowledge
  • A working SSL certificate

1. Modify your .htaccess file

Figure out what page you wan to secure. For example, you might want to secure /contact-us. Add the following lines to your .htacccess file, before the normal wordpress lines:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^contact-us/ /secure-page.php [QSA,L]
RewriteRule ^contact-us /secure-page.php [QSA,L]
</IfModule>
# normal WordPress stuff:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

Here we’re checking to see if the visitor is requesting the “contact-us” page, and if so, we’re rewriting the request to a file called secure-page.php, instead of loading WordPress (step 2).

2. Rename /contact-us & modify menu

Untitled-1

Next, you’ll need to get rid of the old /contact-us page you had, and rename it to contact-page-content – you can do this using WordPress… edit the Premalink, and set it to /contact-page-content.

You’ll need to exclude the page from your navigation, and then put an absolute link to /contact-us in your menu. I suggest the “Exclude Pages” plugin, found at http://wordpress.org/extend/plugins/exclude-pages/

2. Create secure-page.php

Create a file called secure-page.php and add it to your base directory (in the same location as your .htaccess file):

$domain = "www.mydomain.com";
if (  $_SERVER['HTTPS'] != 'on' )
{
$url="https://$domain".$_SERVER['REQUEST_URI'];
header("Location:$url");
exit;
}
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL,"http://$domain/contact-page-content"); // assuming pretty urls are setup this way...
curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
$buffer = curl_exec($curl_handle);
curl_close($curl_handle);
if (empty($buffer))
{
print "Timed Out";
}
else
{
$buffer = str_replace("src=\"http://$domain", 'src="', $buffer);
$buffer = str_replace("src='$domain", "src='", $buffer);
$buffer = str_replace("url(\"http://$domain", 'url("', $buffer);
$buffer = preg_replace ("/http:\/\/.*?(\/.*?\.css)/", "$1", $buffer);
$buffer = preg_replace ("/http:\/\/.*?(\/.*?\.js)/", "$1", $buffer);
$buffer = preg_replace ("/http:\/\/.*?(\/.*?\.xml)/", "$1", $buffer);
print $buffer;
}

OK, here’s an explanation:

You renamed /contact-us to /contact-page-content, and then excluded it from your navigation.  Note that the page still exists – you can enter /contact-page-content into your browser, and it will show the page, right?  But, you hid it from navigation, and you provided the user with a link to /contact-us.  Some people might say this solution is still not “secure”, but I could honestly care less if the user can still go to /contact-page-content… if they do, who cares?

As for what secure-page.php is doing:

The first part checks to make sure the page is served over https. If not, it forwards to the https version, and exits.

Next, we use CURL to request another page (contact-page-content).  Remember that you can still navigate to /contact-page-content, and CURL is doing just that. CURL then downloads the entire content of the page into a buffer/string.

Next, we replace all references to http assets to https… or just “/”. We do this because WordPress uses absolute URLs to assets (”http://mysite.com/image.jpg”), and we want it to be relative (”/image.jpg”).  We then echo out the buffer, and voila, your page is now secured.

Conclusion

I should turn this into a plugin, but I’m lazy and I just don’t have the time…

If you have problems just comment on this post and I’ll get back to you!

24 Responses to “Securing a WordPress page with https”

  1. Andy C says:

    New blog theme looks good!

  2. josh says:

    How would this work to secure multiple pages? Say, three.

  3. admin says:

    Good question!

    To secure three pages… you’d just modify your .htaccess file:
    RewriteRule ^page-one/ /secure-page.php [QSA,L]
    RewriteRule ^page-one /secure-page.php [QSA,L]
    RewriteRule ^page-two/ /secure-page.php [QSA,L]
    RewriteRule ^page-two/secure-page.php [QSA,L]
    RewriteRule ^page-three/ /secure-page.php [QSA,L]
    RewriteRule ^page-three/secure-page.php [QSA,L]

    Then, in secure-page.php, you’d handle those requests:
    add this to line 0:
    $requested_page = $_SERVER['REQUEST_URI'];
    switch ($requested_page)
    {
    case “/page-one”: $pagetoload = “page-one-content”;
    break;

    case “/page-two”: $pagetoload = “page-two-content”;
    break;

    case “/page-three”: $pagetoload = “mypagethree”;
    break;
    }
    // where, the right side of $pagetoload = X… X = the page you renamed/hid in wordpress

    Next, you’d modify the page that CURL loads:

    from line 5:
    exit;
    }
    $curl_handle=curl_init();
    curl_setopt($curl_handle,CURLOPT_URL,”http://$domain/$pagetoload”); // assuming pretty urls are setup this way…
    curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
    curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
    $buffer = curl_exec($curl_handle);
    curl_close($curl_handle);
    if (empty($buffer))

    Hope this helps… ping me back if you have questions

  4. admin says:

    Also… I’m thinking about making a plugin… but I’m pretty busy right now. Maybe if there’s enough interest it would be fun to make a plugin…

  5. ryan says:

    This is incredible. I’ve been searching for a solution for this for over a week. I’m stunned that this hasn’t made it into the core wordpress release yet as people have been selling on their sites since wordpress began. DO THE PLUGIN!!! There’s absolutely nobody else doing this feature right now (the other two plugins are no longer supported). It would make for great free marketing for your services and website!

  6. admin says:

    haha… I’m thinking about it, but honestly I have so much work right now that I don’t think I have the time!

    Did you get the solution to work for you?

  7. ryan says:

    sadly, no. i can see how it would work but something is broken in my code. ill keep at it. i’m sure i’ll figure it out. i’ve also been looking at a software called digital access pass that looks like it might do what i need. thanks for posting this.

  8. admin says:

    Ok – any specific errors?

    You’re running a linux server right?

    Let me know about any specifics and I’d be happy to take a look at it.

  9. Sonic says:

    So I was just reading this, and I had an idea for multiple pages without having to rewrite the page every time.
    What if we added this code:
    [code]
    $URI = $_SERVER['REQUEST_URI']; //put the URI into a new variable
    if($URI[strlen($URI)-1] == "/") //check to see if there's a slash on the end of the requested URI, as this could mess things up later on
    {
    substr_replace($URI, "", -1); //kill the slash
    }
    [/code]
    …and then replaced what was line 5 with:
    [code]
    curl_setopt($curl_handle,CURLOPT_URL,"http://".$domain.$URI."-content");
    [/code]
    (This of course assumes you’ve used the “-content” naming convention…)
    It seems like it should work, and it saves all the trouble of adding an extra line for each page (which could get quite tedious).

  10. admin says:

    Yes! You can 100% do that. For the sake of this example I wanted to keep it easy for newbies.

    Good idea!

    Alex

  11. Sonic says:

    Hi again! My code as it was didn’t work (I can give you the working code if you want…), but I did get it to work with some tweaking.
    Anyways. After following your tutorial (with a few minor tweaks), I still get the error that some parts of the page aren’t secure – any idea why this is, and/or how to fix it?

    Thanks!
    ~Sonic

  12. RD says:

    Hello, I am having trouble getting this to work but I am glad you have put this out there, it is much needed functionality in Wordpress.

  13. admin says:

    Are you getting any specific errors?

  14. admin says:

    Are you getting any specific errors… what happens when you try it?

  15. Ryan says:

    Any idea if there’s a way to secure a page with a shared SSL cert? This is the closest I’ve come to some sort of WordPress SSL solution. Thanks for posting this.

  16. admin says:

    This should work with shared SSL – I actually have a live working version at https://www.mytowntutors.com/tutor-application (or so I think!)

    This is using a GoDaddy Shared SSL certificate.

    Whose your hosting/ssl provider?

    Alex

  17. Bob says:

    So. I’m looking into developing a secure client portal for a wp customer of mine. Would it be possible to secure the whole site with ssl, including login, admin, etc…?

    How secure is this solution? Does it have 64-bit encryption?

    Thanks,
    Bob

  18. admin says:

    This solution does not secure /wp-admin or anything.

    It simply secures individual pages (e.g. checkout pages).

    The level of encryption depends on the certificate you have. Most SSL certs are a minimum of 128-bit encryption. For example, GoDaddy’s cheapest “shared” certificate is around $20 a year: http://www.godaddy.com/gdshop/ssl/ssl.asp?ci=8979

    Alex

  19. Bob says:

    thanks for your answer Alex. so if i want to secure the login page for customers to login, this solution wouldn’t work?

    any ideas as to how this can be done?
    and i’m assuming that i need a private ssl certificate not a shared one?

    thanks,
    Bob

  20. admin says:

    It could be possible – I honestly haven’t tested it yet though!

    You need an SSL certificate that can be installed on your domain. GoDaddy calls these “shared” ssl certificates. They’re pretty cheap. It will work on a shared certificate – I have it working on a site right now.

    I wish I had some time right now – I am betting it would work for /wp-admin, I just can’t test it today :-)

  21. Zhaidarbek says:

    @admin: I tried to apply your tips for Wordpress MU 2.9.1. But fortunately modifying only .htaccess file worked for me. To secure http://www.domain.com/pricing-signup page i added following to .htaccess file as you suggested before the normal wordpress lines:

    RewriteEngine On
    RewriteBase /
    RewriteCond %{SERVER_PORT} 80
    RewriteCond %{REQUEST_URI} pricing-signup
    RewriteRule ^(.*)$ https://%{SERVER_NAME}/$1 [R,L]

    I am not sure of any consequences that might cause but it works.

  22. admin says:

    oh wow… so that was the only modification you had to make?

    If so, my entire solution is overkill!

  23. Zhaidarbek says:

    Ah, never mind, i was mistaken. I thought it’s done when i saw https in the address bar of firefox. Some js and css files are loaded via http, so i still need to leverage secure-page.php.
    Sorry for confusion and thanks for sharing the trick.

  24. RD says:

    Hi Admin,

    I think I was just getting a 404 error, I do not remember 100% now. I ended up basically turning ssl on the whole website, but that is causing a few problems of its own. I would rather have the ssl just run on the shopping cart and checkout pages. The site is countryontheriver.com, please feel free to reply if you have any insight. Thanks again!

Leave a Reply

Powered by Wordpress | Designed by Elegant Themes