Fixed – Cross-Origin Resource Sharing Error with Origin on Amazon CloudFront

Amazon Cloud Front is one of the AWS features which is popular among other CDNs. Configuring Amazon Cloud Front into WordPress website is easier with a plugin called W3 Total Cache.

However, most of the time, there is an error happened during the negotiation between the website, origin, and the S3 bucket using this plugin.

No ‘Access-Control-Allow-Origin’ header error is blocked by Amazon Cloud Front

To fix this, simply follow the following instructions:

  1. Change “Forward Headers” from “None” to “Whitelist”
  2. Add “Origin” to the “Whitelist Headers”
  3. Make sure that “Use Origin Cache Headers” is checked
  4. Invalidate the cached fonts

Read https://knackforge.com/blog/font-awesome-woff2-failing-load-amazon-cloudfront

https://www.naschenweng.info/2014/09/23/wordpress-w3-total-cache-cloudfront-font-cors-issue/

http://blog.celingest.com/en/2014/10/02/tutorial-using-cors-with-cloudfront-and-s3/

Remove Query Strings from Static Resources to Improve Page Load Using W3 Total Cache Plugin

Google demands WordPress sites to remove query strings from its static resources to improve page load performance.

As of July 2018, page speed has become another Google Update and the site that already load fast, there is nothing to worry about.

If you have a running WordPress site with the caching plugin W3 Total Cache already installed, there is an option to remove those messy query strings.

Go to the General Settings tab, tick on the option “Remove query strings from static resources” then hit Save all settings and you’re done.

Common .htaccess Configuration for Redirections

Below are the common configurations for any redirection. Thanks to ScottPhillips.

#301 Redirects for .htaccess

#Redirect a single page:
Redirect 301 /pagename.php http://www.domain.com/pagename.html

#Redirect an entire site:
Redirect 301 / http://www.domain.com/

#Redirect an entire site to a sub folder
Redirect 301 / http://www.domain.com/subfolder/

#Redirect a sub folder to another site
Redirect 301 /subfolder http://www.domain.com/

#This will redirect any file with the .html extension to use the same filename but use the .php extension instead.
RedirectMatch 301 (.*)\.html$ http://www.domain.com$1.php

##
#You can also perform 301 redirects using rewriting via .htaccess.
##

#Redirect from old domain to new domain
RewriteEngine on
RewriteBase /
RewriteRule (.*) http://www.newdomain.com/$1 [R=301,L]

#Redirect to www location
RewriteEngine on
RewriteBase /
rewritecond %{http_host} ^domain.com [nc]
rewriterule ^(.*)$ http://www.domain.com/$1 [r=301,nc]

#Redirect to www location with subdirectory
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} domain.com [NC]
RewriteRule ^(.*)$ http://www.domain.com/directory/index.html [R=301,NC]

#Redirect from old domain to new domain with full path and query string:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(.*) http://www.newdomain.com%{REQUEST_URI} [R=302,NC]

#Redirect from old domain with subdirectory to new domain w/o subdirectory including full path and query string:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/subdirname/(.*)$
RewriteRule ^(.*) http://www.katcode.com/%1 [R=302,NC]

Rewrite and redirect URLs with query parameters (files placed in root directory)

Original URL:

http://www.example.com/index.php?id=1
Desired destination URL:

http://www.example.com/path-to-new-location/
.htaccess syntax:

RewriteEngine on
RewriteCond %{QUERY_STRING} id=1
RewriteRule ^index\.php$ /path-to-new-location/? [L,R=301]
Redirect URLs with query parameters (files placed in subdirectory)

Original URL:

http://www.example.com/sub-dir/index.php?id=1
Desired destination URL:

http://www.example.com/path-to-new-location/
.htaccess syntax:

RewriteEngine on
RewriteCond %{QUERY_STRING} id=1
RewriteRule ^sub-dir/index\.php$ /path-to-new-location/? [L,R=301]
Redirect one clean URL to a new clean URL

Original URL:

http://www.example.com/old-page/
Desired destination URL:
http://www.example.com/new-page/
.htaccess syntax:

RewriteEngine On
RewriteRule ^old-page/?$ $1/new-page$2 [R=301,L]
Rewrite and redirect URLs with query parameter to directory based structure, retaining query string in URL root level

Original URL:

http://www.example.com/index.php?id=100
Desired destination URL:

http://www.example.com/100/
.htaccess syntax:

RewriteEngine On
RewriteRule ^([^/d]+)/?$ index.php?id=$1 [QSA]
Rewrite URLs with query parameter to directory based structure, retaining query string parameter in URL subdirectory

Original URL:
http://www.example.com/index.php?category=fish
Desired destination URL:
http://www.example.com/category/fish/
.htaccess syntax:

RewriteEngine On
RewriteRule ^/?category/([^/d]+)/?$ index.php?category=$1 [L,QSA]
Domain change – redirect all incoming request from old to new domain (retain path)

RewriteEngine on
RewriteCond %{HTTP_HOST} ^example-old\.com$ [NC]
RewriteRule ^(.*)$ http://www.example-new.com/$1 [R=301,L]
If you do not want to pass the path in the request to the new domain, change the last row to:

RewriteRule ^(.*)$ http://www.example-new.com/ [R=301,L]

#From blog.oldsite.com -> www.somewhere.com/blog/
retains path and query, and eliminates xtra blog path if domain is blog.oldsite.com/blog/
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_URI}/ blog
RewriteRule ^(.*) http://www.somewhere.com/%{REQUEST_URI} [R=302,NC]
RewriteRule ^(.*) http://www.somewhere.com/blog/%{REQUEST_URI} [R=302,NC]

Disable XML-RPC to Prevent Brute Force Attack!

XML-RPC is a remote procedure call (RPC) protocol which uses XML to encode its calls and HTTP as a transport mechanism. XML-RPC also refers generically to the use of XML for remote procedure call, independently of the specific protocol.

With WordPress XML-RPC support, you can post to your WordPress blog using many popular Weblog Clients.

This is useful if you want to post the content via other platforms other than logging into the WordPress admin. Unfortunately, attackers can also use those weblog clients to brute force attack your WordPress site.

Thus if you don’t need to have other weblog clients to access to your WordPress posts, simply disable XML-RPC feature.

To do it, simply paste the following code right into your .htaccess file:

# BEGIN Disable XML-RPC.PHP

<Files xml-rpc.php>
    Order Deny,Allow
    Deny from all
</Files>

# END Disable XML-RPC.PHP

Learn more

Creating a Child Theme in WordPress

Child theme has become one of the best practices in inheriting styles from another WordPress theme, mostly for themes you purchased or installed from the WordPress theme directory. This is to prevent overriding to changes you have made once new updates are available.

To do so, simply create another folder next to your theme folder. Use the name as [your-theme-name]-child. For example, your theme is wimple then your child theme for it is wimple-child.

Inside the wimpo-child folder create 2 files. 1 named style.css and another one named functions.php.

Edit the style.css file and paste in the following code:

/*
Theme Name: Wimple Child
Theme URI: http://themecountry.com/themes/wimple
Author: ThemeCountry Team
Author URI: http://themecountry.com
Template: wimple
Description: Wimple is a really clean and fast loading WordPress theme designed specially for professional blog. With many color scheme design option to choose, Wimple is also very optimized for user reading experience and boosting advertising revenue.
Version: 2.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: wimple
Tags: black, white, gray, green, orange, red, pink, theme-options, editor-style, two-columns

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned with others.

Wimple is based on Underscores http://underscores.me/, (C) 2012-2014 Automattic, Inc.

Resetting and rebuilding styles have been helped along thanks to the fine work of
Eric Meyer http://meyerweb.com/eric/tools/css/reset/index.html
along with Nicolas Gallagher and Jonathan Neal http://necolas.github.com/normalize.css/
and Blueprint http://www.blueprintcss.org/
*/

Next, create a functions.php file and add in the following code:

<?php
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );
function my_theme_enqueue_styles() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );

}
?>

Learn more at https://codex.wordpress.org/Child_Themes

If we want to add security over to the main theme, then inside functions.php, paste in the following codes:

/************************
* Security
***********************/

/* Block from reading wp-config.php file */

$transient_name = 'wce_block_' . $_SERVER['REMOTE_ADDR'];

$transient_value = get_transient( $transient_name );

if ( $transient_value !== false ) {

    die( 'BANNED!' );

}

if ( isset( $_GET['wp_config_enumeration'] ) ) {

    set_transient( $transient_name, 1, DAY_IN_SECONDS );

    die( 'BANNED!' );

}

/* Disable User Agent for WP Scan */

if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) && preg_match( '/WPScan/i', $_SERVER['HTTP_USER_AGENT'] ) ) {

    die( 'WP Scan is blocked in this site!' );

}

/* Remove strange XML-RPC server info. */

function add_fake_xmlrpc() {

    // We don’t want to display die(‘XML-RPC server accepts POST requests only.’); on $_GET
    if ( !empty( $_POST ) ) {

        return 'wp_xmlrpc_server';

    } else {

        return 'fake_xmlrpc';

    }

}

class fake_xmlrpc {

    function serve_request() {

        // It's fake 😉
        die();
    }

}

add_filter( 'wp_xmlrpc_server_class', 'add_fake_xmlrpc' );

/* Remove Generator information */

add_filter( 'the_generator', 'remove_generator' );

function remove_generator() {

    // Return nothing
    return ' ';

}

remove_action( 'wp_head', 'wp_generator' );

/* Remove version number from stylesheet */

function remove_version_number_from_css() {

    global $wp_version;

    $wp_version = '168.0';

}

add_action( 'init', 'remove_version_number_from_css' );

/* Prevent advanced fingerprinting */

if ( isset( $_GET['advanced_fingerprinting'] ) ) {

    switch ( $_GET['advanced_fingerprinting'] ) {

        case ‘1’:

        // Unpack file
        $file = gzopen( ABSPATH . 'wp-includes/js/tinymce/wp-tinymce.js.gz', 'rb' );

        // Add comment
        $out = '// ' . uniqid( true ) . "\n";

        while ( ! gzeof( $file ) ) {

            $out .= gzread( $file, 4096 );
        }

        // Pack again
        header( 'Content-type: application/x-gzip' );

        echo gzencode( $out );

        break;

        default:

            status_header( 404 );
        }

    die();

}

/* Stop plugin enumeration. */

if ( isset( $_GET['plugin_enumeration'])) {

    // Display something random

    die( '' );

}

/* Prevent username enumeration. */

if ( ! is_admin() && isset( $_REQUEST[ 'author' ] ) ) {

    status_header(404);

    die();

}

Last but not least, copy the screenshot.png file from the main theme and paste into the child theme and you’re ready to go.

Using iMacros to Update WordPress Posts Published Date

Google loves fresh contents so do users. If your article’s date shows "Last Year" or older than that, users will think your content is out of date and most of the time they will leave your page immediately. Moreover, if you don’t publish content regularly and all your previous posts are too old, Google will also de-rank your site for sure.

WordPress comes with the ability to update each post’s published date manually. However, how if you have more than 500 articles? Updating each post’s date manually will consume a lot of time and effort. It hurts!

I’ve found a tool to help, iMacro, a Chrome addon. This tool helps us do a lot of manual tasks automatically, just leave the browser opens and let it does the jobs for you.

To update the published date in each of the WordPress posts, first, log into your WordPress Dashboard => All Posts. Then click on the Screen Options drop-down on the top right corner of the screen. On the Pagination option, put in the number 1. Then navigate to the last post.

After that, click on the iMacros addon icon of your Chrome toolbar, then the iMacro pannel will pop up.

Click on one of the built-in functions that provided by iMacro and paste in the following code:

VERSION BUILD=844 RECORDER=CR
URL GOTO=https://site.com/wp-admin/edit.php?post_status=publish&post_type=post&mode=list&paged=600
SET !VAR1 EVAL("var randomNumber=Math.floor(Math.random()*30 + 1); randomNumber;")
TAG POS=1 TYPE=A ATTR=TXT:Quick<SP>Edit
TAG POS=1 TYPE=SELECT FORM=ID:posts-filter ATTR=NAME:mm CONTENT=%03
TAG POS=1 TYPE=INPUT:TEXT FORM=ID:posts-filter ATTR=NAME:jj CONTENT={{!VAR1}}
TAG POS=1 TYPE=INPUT:TEXT FORM=ID:posts-filter ATTR=NAME:aa CONTENT=2018
TAG POS=1 TYPE=BUTTON FORM=ID:posts-filter ATTR=TXT:Update

Then click on Save & Close.

The line URL GOTO command you to put the URL of the last post of your website that I’ve noted above.

The Line SET !VAR1 will create a random number from 1 to 31.

%03 here represents the month of March. And 2018 is surely the year of 2018 ;).

Choose the loop options from the iMacros panel and put the maximum number which is 100, then click on Play Loop.

In this example, there are 600 articles so that you will have to click on the Play Loop button 6 times to get all posts updated their date.

Right, you’re done!

Drop me a comment if you can’t make it work.

Force HTTP to HTTPS Using 301 Permanently Redirect in .htaccess file

Sometimes installing plugins for every type of purpose you want is wrong. Some small tasks could be done by just a very small tweak.

When you have just enabled SSL for your website, some of the URLs to your previous content might be still in HTTP. We can force them to redirect to HTTPs.

To do so, put the following codes in between and of your .htaccess file in the root of your website:

RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.*)$ [NC]
RewriteRule (.*) https://%1%{REQUEST_URI} [L,R=301]

If you are using WordPress, the .htaccess file will look like this:

# BEGIN WordPress

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

RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.*)$ [NC]
RewriteRule (.*) https://%1%{REQUEST_URI} [L,R=301]

# END WordPress

And if we want to always redirect from www to non-www, the .htaccess code becomes:

# BEGIN WordPress

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

RewriteCond %{HTTPS} on 
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

Protect WordPress Sites from WP Scan

WP Scan is a tool to scan for vulnerable parts on your WordPress website. It checks various kinds of files and directories to make sure you don’t leave the backdoor behind.

WP Scan is capable to:

  1. Scan in general
  2. Guess WordPress login name and password
  3. List all plugins the site is using
  4. List what theme the site is using
  5. Ability to read .htaccess, XML files, …

However, hackers can use it to scan your site, looking for possible backdoors, and use them to attack your site and steal the information. Cam CERT’s tip has written a great advice on what to allow and what not to.

WP Scan does not support Windows operating system. It comes pre-installed on some Linux distributions and is packaged by Homebrew for Mac OS.

Regardless of the operating systems needed, install WP Scan by using Docker.

First, you need Docker to be up and running on your machine. To install Docker, follow this tutorial.

Next, install WP Scan by running the following command:

docker pull wpscanteam/wpscan

Scan any of your sites by running the following command:

docker run -it --rm wpscanteam/wpscan -u https://yourblog.com [options]

You can find the [options] argument on the WP Scan official website.

Here are the things we should add to stop hackers who might use this tool against us.

1. Block from Reading robots.txt File

Hook the following codes to your functions.php:

/** Block Robot Information */
add_action(‘do_robots’, ‘hook_robots’, 1);
function hook_robots() {
// Return 404
status_header(404);
// End script
die();
}

2. Block from Reading readme.txt File

Simply put the following code to your .htaccess file:

RewriteRule ^readme\.html$ – [R=404,L,NC]

3. Block Full Path Disclosure

When a website is badly configured, hackers can pull down all your directory structures from wp-includes/rss-functions.php.

To stop this action, put the following setting to your .htaccess file:

RewriteRule ^wp-includes/rss-functions\.php$ – [R=404,L,NC]

4. Block from Reading wp-config.php File

Put the following settings to your .htaccess file:

RewriteRule ^wp-config\.php\.save$index.php?wp_config_enumeration=1 [L]
RewriteRule ^\.wp-config\.php\.swp$ index.php?wp_config_enumeration=1 [L]
RewriteRule ^wp-config\.php\.swp$ index.php?wp_config_enumeration=1 [L]

Then put the following codes to your functions.php:

/** Detect this requests and temporary block user. */
$transient_name = ‘wce_block_’.$_SERVER[‘REMOTE_ADDR’];
$transient_value = get_transient( $transient_name );

if ( $transient_value !== false ) {
die( ‘BANNED!’ );
}

if ( isset( $_GET[‘wp_config_enumeration’] ) ) {
set_transient( $transient_name, 1, DAY_IN_SECONDS );
die(‘BANNED!’);
}

5. Disable User-Agent

Put the following codes to your functions.php:

/** Detect User Agent */
if ( !empty( $_SERVER[‘HTTP_USER_AGENT’] ) && preg_match(‘/WPScan/i’, $_SERVER[‘HTTP_USER_AGENT’] ) ) {
die( ‘Wrong user agent’ );
}

6. Block from Reading from  XML-RPC Server

Put the following codes into your functions.php:

/** Remove strange XML-RPC server info. */
function add_fake_xmlrpc() {
// We don’t want to display die(‘XML-RPC server accepts POST requests only.’); on $_GET
if ( !empty( $_POST ) ) {
return ‘wp_xmlrpc_server’;
} else {
return ‘fake_xmlrpc’;
}
}

add_filter(‘wp_xmlrpc_server_class’, ‘add_fake_xmlrpc’);

class fake_xmlrpc {
function serve_request() {
// It's fake 😉
die();
}
}

7. Hide Your WordPress Version Information

Append these codes to your functions.php:

/** Remove generator info. */
remove_action(‘wp_head’, ‘wp_generator’);
add_filter(‘the_generator’, ‘remove_generator’);
function remove_generator() {
// Return nothing
return ”;
}

8. Stop Advance Fingerprint

First, add the following setting to your .htaccess file:

RewriteRule ^wp-includes/js/tinymce/wp-tinymce\.js\.gz$ index.php?advanced_fingerprinting=1 [L]

then put the following codes to append to your functions.php

/** Prevent advanced fingerprinting */
if ( isset( $_GET[‘advanced_fingerprinting’] ) ) {
switch ($_GET[‘advanced_fingerprinting’]) {
case ‘1’:
// Unpack file
$file = gzopen( ABSPATH . ’wp-includes/js/tinymce/wp-tinymce.js.gz’, ‘rb’ );
// Add comment
$out = ‘// ‘ . uniqid(true) . ”\n”;
while( !gzeof( $file ) ) {
$out .= gzread( $file, 4096 );
}

// Pack again
header( ‘Content-type: application/x-gzip’ );
echo gzencode($out);
break;
default:
status_header( 404 );
}

die();
}

9. Remove WordPress Version Number

Append these codes to the functions.php:

/** Remove version number from stylesheet. */
add_action( ‘init’, ‘init’ );
function init() {
global $wp_version;
$wp_version = ‘some_strange_number’;
}

10. Disable Plugin Enumeration

Put the following setting to your .htaccess file:

RewriteRule ^(.*)wp-content/plugins/(.*)$ index.php?plugin_enumeration=1 [L]

Then place the following codes to your functions.php:

/** Stop plugin enumeration. */
if (isset($_GET[‘plugin_enumeration’])) {
// Display something random
die(‘‘);
}

11. Block Username Enumeration

Hackers can get your username easily by just appending the ?author=[user_id] to the domain name. To disable the access to the $_GET['author'], simply add the following codes to your functions.php file:

/** Prevent username enumeration. */
if ( ! is_admin() && isset( $_REQUEST[‘author’] ) ) {
status_header(404);
die();
}

After applying the above configurations, when WP Scan scans your website, it will tell you that "The remote website is up, but does not seem to be running WordPress".

Source: CamCERT