Search code examples
wordpressapache.htaccesssslmixed-content

Mixed Content/Insecure Content SSL


I am currently having issues with the following

Mixed Content: The page at 'https://www.example.com/' was loaded over HTTPS, but requested an insecure stylesheet

This is a Wordpress website on a Centos server with httpd installed.

I have following virtual host setup in `http.conf:

NameVirtualHost *:80
NameVirtualHost *:443


<VirtualHost *:443>
    DocumentRoot /var/www/html/example
    ServerName www.example.com
    ServerAlias example.com
    SSLEngine on
    SSLCACertificateFile /etc/httpd/conf/ssl.crt/intermediate.crt
    SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
    SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
</VirtualHost>

<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com
    Redirect / https://www.example.com/
</VirtualHost>

In my httpd.conf I have changed AllowOverride to all, so it looks like so:

<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

I can confirm the htaccess is working as I am using iTheme security plugin and this is working as expected, also if I type some garbage in the htacces I get a server misconfiguration error as expected.

I have changed both the Wordpress URLs in the Dashboard to use https instead of http.

Once all of this was done, I was able to access the site over HTTP, be redirected to the HTTPS version of the site and see the site. However in the console I receive the error regarding mixed content and the padlock shield appears as yellow or red crossed as opposed to the desired green.

There are a few files that are an issue and I know for example I can change the URLs manually to use https as opposed to http. As I understand it, I can use change the URL to the below and this will simply adjust the link to the current protocol in use:

<img src="//www.example.com/image.jpg" />

I have also seen that if a resource is not available over https I can simply do the following:

https://example.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad

I am however, trying to find a way to fix all of these in one go using htaccess (something I am sure I have done before, but my snippets aren't working for me).

There are two main snippets I have used in an attempt to force everything over https, the first being:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On

#These Lines to force HTTPS
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]

RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

The second is from Dave Walsh:

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

However, neither seem to solve my issue. As a precaution I have restarted the httpd service after every change even htaccess changes which shouldn't require a restart, however the situation remains the same. Can anyone point me in the right direction?


Solution

  • The simplest solution is to replace all links manually using this solution below will save your time and its very straight forward.

    The idea is to remove all (protocol HTTP and HTTPS) and leave them to use protocol relative URL https://stackoverflow.com/a/15146073/3599237

    We can do this using the following code for index.php

    <?php
    //this lined added here
    ob_start();
    /**
     * Front to the WordPress application. This file doesn't do anything, but loads
     * wp-blog-header.php which does and tells WordPress to load the theme.
     *
     * @package WordPress
     */
    
    /**
     * Tells WordPress to load the WordPress theme and output it.
     *
     * @var bool
     */
    define('WP_USE_THEMES', true);
    
    /** Loads the WordPress Environment and Template */
    require( dirname( __FILE__ ) . '/wp-blog-header.php' );
    
    //and these lines also 
    $output = ob_get_contents();
    ob_end_clean();
    
    $output = str_replace(array("https://", "http://"), "//", $output);
    echo str_replace('http:\/\/', "\/\/", $output);
    

    Update: You can simply use Content Security Policy

    The HTTP Content-Security-Policy (CSP) upgrade-insecure-requests directive instructs user agents to treat all of a site's insecure URLs (those served over HTTP) as though they have been replaced with secure URLs (those served over HTTPS). This directive is intended for web sites with large numbers of insecure legacy URLs that need to be rewritten.

    The upgrade-insecure-requests directive is evaluated before block-all-mixed-content and if it is set, the latter is effectively a no-op. It is recommended to set either directive, but not both, unless you want to force HTTPS on older browsers that do not force it after a redirect to HTTP.

    Put below line into header section (header.php file).

    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
    

    For more information please read: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests