WordPress.org

Ready to get started?Download WordPress

Forums

WordPress HTTPS (SSL)
SSL Administration over Non-Standard Ports (20 posts)

  1. doingweb
    Member
    Posted 2 years ago #

    I recently found myself with the not so uncommon problem of needing to secure multiple WordPress installations on the same web server. Unlike standard HTTP with VirtualHosts (Apache), HTTPS requires different ports for each site. However, WordPress does not currently allow you to specify which port should be used for SSL functions, and automatically assumes the standard port 443. This is a reasonable assumption for the core WordPress code to follow, but some of us host many small sites on a single server, and still care about security.

    During my research, I came across the WordPress HTTPS plugin, which appeared to have exactly what I needed in its "Shared SSL" feature, since I needed my SSL Host to be "something other than 'https://example.com/'". However, after trying to set my Shared SSL Host to "https://example.com:4432", followed by a thorough examination of the source code, I discovered that it wasn't designed to work with port numbers at all.

    So, after a few lengthy hacking sessions figuring out how WordPress plugins and filters work, I have a patch here for WordPress HTTPS 1.9.2 that supports port numbers and works beautifully on my secondary (and now secure) WordPress installation on my personal VPS. I'd like to submit it to Mvied for consideration in the next release, but I could not find a way to do so, other than reach out through the forum here. I couldn't find a GitHub repo, a "send message" link on his profile, and the Trac for WordPress Plugins doesn't even list the plugin as a Component. I'm pretty lost when it comes to my contribution.

  2. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    It's true, this is really the only place to get in touch with me. If you'd like you can toss the source in a pastebin and I'll take a look at it.

    Thanks for contributing. :)

    Mike

  3. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    I went ahead and edited the plugin to accept a port in the Shared SSL Host field. In 1.9.2, line 740 would be changed to this:
    $_POST[$key] = 'https://' . $url['host'] . ((@$url['port']) ? ':' . $url['port'] : '') . @$url['path'];

    That should pretty much do it. I'd still like to see the modifications you made in case I overlooked something.

    Thanks,
    Mike

  4. doingweb
    Member
    Posted 2 years ago #

    Hey! Thanks for the prompt reply! Here's the pastebin for the patch: http://pastebin.com/bs3GRaYp.

    I made almost the same change on line 740, except I used isset(), though an error suppression is probably a better choice for brevity and consistency. This change makes it so that the URL including port number can be saved, but it doesn't solve all of the problems associated with port numbers in the URL.

    I found that, while the URL was rewritten correctly in many places, there were several places where the port number was added twice. That is, "src" and "href" attributes would contain URLs with "https://example.com:4432:4432" in them, which would break functionality. This indicated to me that the "https://example.com" portion was being replaced twice with my Shared SSL Host URL, and that there was some code that ignored the port number and only looked for a plain base URL to replace.

    So most of the other changes I made were to the regular expressions in the process() and replace_http_url() functions that deal with recognizing and capturing the URL to replace.

    I don't think I have to tell you, but please feel totally free to make necessary changes for correctness and style if you choose to use it. Though I'd call myself a decent PHP/RegEx coder, this is my first experience with the "dirty" side of WordPress, and I didn't read any of the developer docs or much of the core code. I very well could've completely missed something.

    Thanks!

  5. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    Could you do me a favor and download the development version and see how it works? I've made quite a few changes to the regular expressions for the next version (they're much more generic). For example: preg_match_all('/\<(a|form)[^>]+[\'"]((http|https):\/\/[^\'"]+)[\'"][^>]*>/im', $buffer, $matches);

    The only regex that's not completely generic is the one in the replace_http_url method. I've changed it to preg_match_all('/(http|https):\/\/[\/-\w\.,#?=\+&%;:\d]+/im', $string, $url); which I think should be sufficient to make it work with a port number.

    If you want, download the development version here and replace your current wordpress-https.php with the one in the zip archive and let me know how it works.

    Thanks,
    Mike

  6. doingweb
    Member
    Posted 2 years ago #

    This version (1.9.3-dev) does not fully work, and still exhibits the doubled port number bug.

    I believe the problem is in the replace_http_url() function, where we have the lines (651, 652):

    $string = str_replace($this->replace_http($this->http_url), $this->https_url, $string);
    $string = str_replace($this->http_url, $this->https_url, $string);

    Keep in mind that sometimes, the input string ($string) contains a URL that already contains the port number.

    For reference, $this->http_url is defined as (line 100):

    $this->http_url = 'http://' . parse_url(get_option('home'), PHP_URL_HOST);

    And $this->https_url is our Shared SSL Host (port and all).

    The apparent goal of these replacements is to replace the https and http versions of the site's hostname with the Shared SSL Host name and the https scheme in the URL contained in $string. However, when port numbers are involved, that part of the replacement target is left out, and only the hostname and scheme are replaced, resulting in duplicated port numbers.

    As an example, replace_http_url() receives "https://example.com:4432/wp-admin/" as $string at some point of the page load. $this->http_url is logically "http://example.com". But when the first replacement is issued, it replaces "https://example.com" with "https://example.com:4432", and the function returns "https://example.com:4432:4432".

    It looks to me like the solution would be to capture the complete base URL (that is, up until the path) and just do one replacement on that, no matter what it is, with $this->https_url (and please correct me if I'm wrong/looking at it too narrowly). I've created a patch for the changes to get it working again: http://pastebin.com/UKDVv4Bs.

    Just after I got it working, I noticed a mixed content warning. It looks like URLs in the inline Javascript are getting returned to http (with the port number). I'm investigating.

  7. doingweb
    Member
    Posted 2 years ago #

    For some reason, the Shared SSL Host is showing on the settings page as HTTP, even though I definitely saved it as HTTPS, and it even reflects so in the database. The HTML in the settings() function suggests that it should be using the correct HTTPS version...

    It looks like this is the same problem as with the improper inline Javascript. Still investigating.

  8. doingweb
    Member
    Posted 2 years ago #

    Okay, I figured out what it was.

    What was happening was the first section of process() ("Fix any occurrence of the HTTPS version of the regular domain when using Shared SSL") was taking those instances where the URL was already switched, and then replacing the HTTPS with HTTP. This resulted in some URLs like "http://example.com:4432", which never got corrected by later code.

    In my previous patch for 1.9.2, I'd made similar changes to a similar section, which in that version was at the end of process().

    I've updated the latest pastebin (http://pastebin.com/UKDVv4Bs), and I am now free of any mixed content warnings.

  9. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    Gotcha, that makes sense. I'll get an update into the development version today and update the topic when I do, then you can give it a test run.

    Thanks for your help,
    Mike

  10. doingweb
    Member
    Posted 2 years ago #

    Sounds great! Thanks!

  11. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    Sorry it's taken me a while to get back to you. I was doing some heavy development on the plugin. I think I've got the plugin working with a custom port, but have no real-world server to test it with. If you would, try downloading the new development version and let me know if it works.

    Thanks,
    Mike

  12. doingweb
    Member
    Posted 2 years ago #

    Sure thing.

  13. doingweb
    Member
    Posted 2 years ago #

    Hey, good to hear from you again!

    I just loaded it up, and it looks like it's definitely not working. The port number only shows up in 5/21 instances in the page source where the HTTPS URL is supposed to be. This is also strange, because in the previous version, there were 33 HTTPS URLs... I'll dig a little deeper later today.

    I'd also appreciate an acknowledgement for my work on this feature in the changelog, if you wouldn't mind. Just my name ("doingweb" or "Chris Antes") would be sufficient, which could link to my (as yet incomplete) blog or Twitter, where applicable.

  14. doingweb
    Member
    Posted 2 years ago #

    All of the link, script, and img URLs did not get the port number. URLs that appear in inline script were also not given the port number.

    It looks like many of those 33 URLs from the previous version shouldn't have even been replaced (they were intended to be off-site), so 21 is the right number.

  15. doingweb
    Member
    Posted 2 years ago #

    Those URLs that weren't given the port number were not run through replace_http_url(), which would have done the job. The second section of process(), labeled "Fix the regular stuff", goes through each of these tags (see for loop lines 532-573). However, there is a lot of complicated and seemingly redundant logic in there. For instance, three separate branches end in the single line:

    $buffer = str_replace($html, str_replace($url, $this->replace_http_url($url), $html), $buffer);

    The inline script problem was previously solved by the first section of process() ("Fix any occurrence of the HTTPS version of the regular domain when using different SSL Host"). However, this now checks if the SSL host is different, which it isn't, since the port is now considered separate.

  16. doingweb
    Member
    Posted 2 years ago #

    Okay, I have a small patch here that clears up all of my problems. The source now shows all HTTPS URLs with ports (with no doubling), including all tags and inline script, and I have no mixed content warnings.

    I changed the condition for when to replace the HTTPS version of the regular domain from being only if the SSL Host is different to if the SSL Host is different or an SSL Port is set. I also corrected what I believed to be a typo on a later line in that condition, switching the call to replace_https_url() with replace_http_url().

  17. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    Sorry it's been so long since I've responded. Had to take a little break from development. The patch you posted won't quite work since it breaks functionality for using a different SSL Host. That block is very much intentional.

    I think the code has finally become complex enough to where I need to add a suite of debug and testing tools into the plugin. It's something I've been meaning to do for a while, anyways. I'm working on that now and should be done shortly. With some testing and debugging tools in place, I should be able to optimize the code and ensure that changes do not break existing functionality. Right now it's kind of hard to wrap my head around everything that could possibly be thrown through the output buffering processor, hence why I just had to step away from it for a little while to let my head clear.

    I'll let you know when I get a newer development version out. In the meantime, feel free to try to work out a solution.

    Thanks,
    Mike

  18. doingweb
    Member
    Posted 2 years ago #

    Ah, okay, so "Fix any occurrence of the HTTPS version of the regular domain" actually means that those HTTPS URLs should be converted to HTTP URLs so later parts of process() can treat it correctly?

    It really feels like that block (or, rather, a nearly identical block) is what is needed to add the port to all of the URLs that need it. Maybe there's a DRYer way of doing it than copying the block and changing those lines.

    I think I'll wait for the test suite before spending more time on a solution.

    Thanks for getting back!

  19. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    You are correct, sir!

    I've completely rewritten the replace_http_url and replace_https_url to be much more aggressive, which (I think) will fix the problems you were having.

    Check out the new development version at http://downloads.wordpress.org/plugin/wordpress-https.2.0.zip

    Also, the class now has a $debug variable that, when set to true, will spit out exactly what the plugin is doing into the browser's console. It's really handy to see if URL's are being changed properly.

    Let me know how it goes. If this works out for you, I think we'll be ready for release.

    Thanks,
    Mike

  20. Mvied
    Member
    Plugin Author

    Posted 2 years ago #

    Hey doingweb,

    I'm going to be rolling 2.0 out very soon. I'm pretty sure it'll work for you. If it doesn't, I can push out a bug fix pretty easily, so it shouldn't be a big deal. I feel confident about this one, though. :)

    Just wanted to give you a heads up. I don't want to delay the release too much longer since it has a lot of bug fixes and features in it.

    Thanks,
    Mike

Topic Closed

This topic has been closed to new replies.

About this Plugin

About this Topic