SwitchToSSLMode-Talk

This is the discussion page for the SwitchToSSLMode recipe.

While having both HTTP and HTTPS access activated on the Wiki server, it may be worth enabling HSTS to have the browser automatically prefering HTTPS over HTTP and be less sensible to MITM attacks by adding something like below in your configuration file:

$HTTPHeaders[] = "Strict-Transport-Security: max-age=604800; includeSubdomains";

More details on https://hstspreload.org/

Dfaure November 04, 2020, at 02:17 PM


I had a lot of trouble getting this to work with UserAuth2 and I only wanted SSL for my login prompt and user management. I came up with this solution which seems to work, but I'd like feedback since I'm still new to modrewrite.

Charles: sonikbuddha ATT hotmail DOTT com

config.php

if (@$_SERVER['HTTPS'] == 'on' || @$_SERVER['SERVER_PORT'] == '443')
{
        $UrlScheme='https';
} else {
        $UrlScheme='http';
}
$ScriptUrl = $UrlScheme.'://www.example.com/wiki';
$PubDirUrl = $UrlScheme.'://www.example.com/wiki/pub';

.httaccess

# Use mod_rewrite to enable "Clean URLs" for a PmWiki installation.
RewriteEngine On
# Define the rewrite base.
RewriteBase /wiki
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} ^/wiki/Site/Login [OR]
RewriteCond %{QUERY_STRING} action=login [OR]
RewriteCond %{QUERY_STRING} ^n=Site.Login [OR]
RewriteCond %{QUERY_STRING} ^action=admin [OR]
RewriteCond %{QUERY_STRING} ^action=pwchange
RewriteRule (.*)  https://www.example.com/wiki/$1 [R=permanent,L]
RewriteCond %{SERVER_PORT} 443
RewriteCond %{REQUEST_URI} !(\.gif|\.css) 
RewriteCond %{REQUEST_URI} !^/wiki/Site/Login
RewriteCond %{QUERY_STRING} !^n=Site/Login 
RewriteCond %{QUERY_STRING} !^action=login
RewriteCond %{QUERY_STRING} !action=admin 
RewriteCond %{QUERY_STRING} !action=pwchange
RewriteRule (.*)  http://www.example.com/wiki/$1 [R=permanent,L]
# Send requests without parameters to pmwiki.php.
RewriteRule ^$           pmwiki.php  [L]
# Send requests for index.php to pmwiki.php.
RewriteRule ^index\.php$ pmwiki.php  [L]
# Send requests to pmwiki.php, appending the query string part.
RewriteRule ^([A-Z0-9\xa0-\xff].*)$ pmwiki.php?n=$1  [QSA,L]

Hi Hagan,

I have been trying all combinations to get ssl https:// to work with farms. Is there any way of doing this?

Clive Hetherington cc1708@soul-healer.com

Clive,

A wiki in a farm works the same way as a stand-alone wiki. The only thing different would be to change your $FarmPubDirUrl in the following manner:

##  $FarmPubDirUrl is the URL for the farm-wide pub directory.
if ($_SERVER["HTTPS"] == 'on') {
  $FarmPubDirUrl = 'https://www.example.com/~someuser/pmwiki/pub';
} else {
  $FarmPubDirUrl = 'http://www.example.com/~someuser/pmwiki/pub';
}

I tried, as an experiment, just catching the "login" and "edit" actions in my config.php, to convert those pages to use https. In those cases, set $ScriptUrl=$SecureScriptUrl. Otherwise, just use the default $ScriptUrl. Unfortunately, when you then get a login page and check the page source, you'll see that while most URLs have been translated to the https path, one significant URL remains using the http path: the URL to which the password is posted. Consequently, this seems to encrypt what I don't care about, and leave in plaintext the one thing I must encrypt. (Actually, the URL for posting is a relative URL. So it would be fine if I always used https. But if I am normally using http, this will post using http. Web server logs confirm this.)

It seems to me that we need to somehow catch the URLs generated by forms, including the default login form, and switch posting URLs only to use https. Any ideas how to do this?

For my purposes, I don't care about encrypting the session cookie. If I cared, I'd just switch to always using https. That works fine, simply by setting the appropriate $ScriptUrl, and that is what I am doing for now. But I have another web site that the "$SecureScriptUrl" will actually be a different hostname than I want folks to normally use, so for that I really need a solution that only encrypts passwords and other sensitive information. (Perhaps, anything POSTed, only.) -- rlt, 2007-Feb-21


I use this basic technique to use kerberos (through .htaccess) for Apache. I added the following to my farmconfig.php

function AuthPrompt($pagename)
{
  if ($_SERVER['SERVER_PORT'] != 443)
    {
      $host = $_SERVER['HTTP_HOST'];
      $uri = $_SERVER['PHP_SELF'];

         //this will copy all GET request parameters,
         //and fix the problem with empty filename on upload page

      $url = array();
      $query = '';
      reset($_GET);
      while(list($name,$value) = each($_GET))
        if(!empty($value) && ($value != 'login'))
          {
            $url[$name] = $name."=".urlencode($value);
            $query = '?';
          }
      header("Location: https://$host$uri".$query.implode("&",$url));
      exit;
    }
}

if( $action=='logout')
{

  $host = $_SERVER['HTTP_HOST'];
  $uri = $_SERVER['PHP_SELF'];
  header("Location: http://$host$uri");
  exit;
}

if(   $action=='edit'
      || $action=='post'
      || $action=='postattr'
      || $action=='attr'
      || $action=='upload'
      || $action=='loginadmin'
      || $action=='login' )
{
  AuthPrompt($pagename);
}
SDV($AuthPromptFmt, 'function:AuthPrompt');

In the config.php I put the following

if ($_SERVER['SERVER_PORT'] != 443)
{
   $ScriptUrl = 'http://path_to_wiki';
}
else
{
  $ScriptUrl = 'https://path_to_wiki'
}

$AuthID = $_SERVER['REMOTE_USER'];
$AuthId = $AuthID;
include_once("$FarmD/scripts/authuser.php");
$Author = $AuthId;
AuthUserID($pagename, $AuthID);

This approach causes the transition to SSL whenever authuser requires a "login". Transition from SSL occurs with "action=logout".


Hello Hagan,

I am having problems getting my wiki to switch to SSL for password prompts only. I tried both examples with the following results:

  • The method from the SwitchToSSLMode page serves the password and edit pages in clear text (http). After clicking save or cancel, I am redirected to the edit page using https but Firefox complains the server is redirecting the request in a way that will never complete.
  • I tried the method above (without the $AuthID section) and am able to get the edit page url as https. However, the entire password page is blank. I can't find any php-related errors in my logs.

It seems like either I can switch to SSL or enter a password or content, but never both. Is there something I might be missing? Where else could I debug or look for errors? I am able to server my entire wiki using SSL just fine using the first example on the main page.

Thanks, Chub (chub_1238@yahoo.com)


I use the config.php code below to automatically enable SSL as needed based on page actions such as 'attr', or based on group or page name containing a security key word such as 'Security' or 'SiteAdmin'. It has been tested with PmWiki 2.2.0-beta63 with standard URLs, please see limitations below. --jtankers

##  Set URL to http or https, Open Source 2007/09/13pm jtankers/PmWiki 2.2.0-beta63
function ChangeUrlScheme($urlscheme) { 
  $url = array();
  $query = '';
  reset($_GET);
  while(list($name,$value) = each($_GET)) {
    if (!empty($value)) {
      $url[$name] = $name."=".urlencode($value);
      $query = '?';
    }
  }
  header("Location: ".$urlscheme."://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$query.implode("&",$url));
  exit;
}
##  Enable SSL for security actions and group or page names containing key words
##  Open Source 2007/09/13pm2 jtankers/PmWiki 2.2.0-beta63.  
##  Limitations: SSL is not enabled for automatic login on unauthorized page actions unless  
##  page action is included in $my_ssl_actions, or group.page name contains $my_secure_keyword
$my_secure_domain = 'www.wiki1.net';
$my_secure_keyword = 'Secure';
$my_secure_pageactions = 'admin,analyze,attr,crypt,diag,login,loginadmin,postattr,source,webadmin';
if (substr_count($_SERVER['HTTP_HOST'], $my_secure_domain)) { 
  if ( substr_count($my_secure_pageactions, $action) 
    || substr_count($pagename, $my_secure_keyword) 
    || substr_count($pagename, 'SiteAdmin') 
  ) {
    if (@$_SERVER['SERVER_PORT'] != '443') ChangeUrlScheme('https');
  } else {
    if (@$_SERVER['SERVER_PORT'] == '443') ChangeUrlScheme('http');
  }
}
Limitations: SSL is not enabled for automatic login on unauthorized page actions unless the page action is included in $my_secure_actions or group or page name contains a security key word such as 'Secure' or 'SiteAdmin'. The following code attempts to solve the issue but does not work because reading CondAuth() in config.php while logging in re-triggers another automatic login. What appears to be needed is a method to detect automatic login in config.php when user attempts an unauthorized page action without reading CondAuth().
# I would like to use the 3 lines of code below, but reading CondAuth while logging in re-triggers another login...
    || ($action == 'browse' && !CondAuth($pagename, 'read'))
    || ($action == 'edit' && !CondAuth($pagename, 'edit'))
    || ($action == 'attr' && !CondAuth($pagename, 'attr'))

Edit Work Around: Re-set page actions to 'login' on un-authorized page actions that do not already trigger SSL.

Page Header: Add the following to Site.PageActions:

(:if auth read:)
* %item class=browse accesskey='$[ak_view]'%[[{$FullName} | $[View] ]]
(:else:)
* %item class=browse accesskey='$[ak_view]'%[[{$FullName}?action=login | $[View*] ]]
(:if:)
(:if auth edit:)
* %item rel=nofollow class=edit accesskey='$[ak_edit]'%[[{$FullName}?action=edit | $[Edit this page] ]]
(:else:)
* %item rel=nofollow class=edit accesskey='$[ak_edit]'%[[{$FullName}?action=login | $[Edit this page*] ]]
(:if:)
* %item rel=nofollow class=diff accesskey='$[ak_history]'%[[{$FullName}?action=diff | $[History] ]]
(:if auth upload:)
* %item rel=nofollow class=upload accesskey='$[ak_attach]'%[[{$FullName}?action=upload | $[Attach file] ]]
(:else:)
* %item rel=nofollow class=upload accesskey='$[ak_attach]'%[[{$FullName}?action=login | $[Attach file*] ]]
(:if:)
(:if auth edit:)
* %item rel=nofollow class=rename accesskey=$[ak_rename]% [[{*$FullName}?action=rename | $[Rename] ]]
(:else:)
* %item rel=nofollow class=rename accesskey=$[ak_rename]% [[{*$FullName}?action=login | $[Rename*] ]]
(:if:)
(:if auth attr:)
* %item rel=nofollow% [[$[Attributes] -> $[{$FullName}?action=attr]]]
* %item rel=nofollow% [[$[Group Attributes] -> $[{$Group}.GroupAttributes?action=attr]]]
(:if:)
* %item rel=nofollow class=print accesskey='$[ak_print]'%[[{$FullName}?action=print | $[Print] ]]

Page Footer: Add the following to [skin].php:

(:if auth edit:)
* %item rel=nofollow% [[$[Edit] -> $[{$FullName}?action=edit]]]
(:else:)
* %item rel=nofollow% [[$[Edit*] -> $[{$FullName}?action=login]]]
(:if:)

I was thinking, for the case where the main concern is to ensure that all logins are submitted securely, if all logins are funneled through the standard login form, shouldn't that be where we focus our efforts?

A bit of poking around in forms.php turned up a section which caught my eye, which starts with the comment

## Form-based authorization prompts (for use with PmWikiAuth)

I simply changed the action in the first SDVA() call from

 SDVA(... ':html' => "<form action='{$_SERVER['REQUEST_URI']}' ... );

to

 SDVA(... ':html' => "<form action='{$SecureScriptUrl}{$_SERVER['REQUEST_URI']}' ... );

and set $SecureScriptUrl in config.php to the same as $ScriptUrl but with https, and it seems to work (tested by removing my site's self-signed certificate from the approved list in my browser; when I clicked OK on the login screen, I was asked to approve the cert).

Other than the need to hack forms.php, am I missing something? -- shi

I've been reading a lot about this SwitchToSSLMode but this last suggestion by shi has the best value for money. With just two changes. First, add $SecureScriptUrl (a misnomer, since it should be "https://www.example.com") to config.php. Next, change forms.php. I had to change line 244, from:

  ':html' => "<form action='$r' method='post'

to:

  ':html' => "<form action='{$SecureScriptUrl}$r' method='post'

That's all there's to it! One caveat though: once in https it will stay in https. To fix this, set your $ScriptUrl in config.php and force it to use "http://" (by default it will use whatever the current URL is using, so if the URL is https, it will always refer to https.) This solves the first caveat but the user will see warning message when submitting wiki content since at that moment it will switch from https to http. To solve this, the password processing should redirect the URL to http immediately, showing the form in http, but I don't know how to do that. -- Lio

Talk page for the SwitchToSSLMode recipe (users?).