WOR(L)DPRESS Best practice

TIPS AND TRICKS OF COMMON SENSE



Safety is the attention to detail.

#1 - SERVER

Behind every great man there stands a great woman.

Behind a secure website there is always a secure server!

  • use iptables
  • using SFTP
  • use ModSecurity (apache module)
  • backup server-side DB and Filesystem
  • crontab script to check files and WP updates
  • system monitoring (Munin, Nagios)


#2 - VERSIONs

Show versions of the software 
that you use is the first security flaw.

  • Apache
  • PHP
  • Wordpress
  • JS

#3 - FILEs 'n' DIRs

Apache: 

<files wp-config.php>
order allow,deny
deny from all
</files>
wp-config.php
define('DISALLOW_FILE_EDIT', true);

Directories:

find /path/to/your/wordpress/install/ -type d -exec chmod 755 {} \;

Files:

find /path/to/your/wordpress/install/ -name 'wp-config.php' -exec chmod 440 {} \;
find /path/to/your/wordpress/install/ -type f -exec chmod 644 {} \;

#4 - Script

A crontab script can:
  • remove the file: /wp-admin/install.php
  • check files permissions
  • check Wordpress/plugins updates
  • report changed files

Over 70% of the installations of WordPress 

are vulnerable to lack of updates.

#5 - DATABASE

  • The table_prefix can be changed at will. 
    $table_prefix  = 'wp_';  
  • The port to connect to MySQL can be changed and managed during the connection as follows:
    define('DB_HOST', 'localhost:1234'); 
  • The permission can be changed for a standard use:
    CRUD rows (MySQL needs all privileges to update/install Wordpress and/or plugins.)
  • To prevent the size of the DB grow out of proportion, it is good practice to import into your
    wp-config as follows:

    define('WP_POST_REVISIONS', 2); // any integer, but don't get too crazy
    // define('WP_POST_REVISIONS', false); 
  • You can trace the number of queries and the queries themselves and possibly control them and rewrite them if they need.
  • it is good practice to use the cache of MySQL

#6 - Users

  • It is good practice that there is no user "admin". 
    If it exists, you can create another administrator user and delete the old "admin" .
  • Passwords must be complex to be safe 
    (there are tools that help to remind you)
  • The id of the user can be set to start numbering from a higher to be less easy to deduce.
  • Managing user tables can be renamed and defined as follows:
define('CUSTOM_USER_TABLE', $table_prefix.'my_users');
define('CUSTOM_USER_META_TABLE', $table_prefix.'my_usermeta');

#7 - WP-ADMIN & SSL

Is or is not rename the folder a problem? Yes, it is!
Must be used .htpasswd
Wordpress supports SSL for wp-admin starting from version 3.5:

define('FORCE_SSL_ADMIN', true);
define('FORCE_SSL_LOGIN', true);
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS']='on';
Virtual host http:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)\ HTTP/ [NC]
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^/?(wp-admin/|wp-login\.php) https://mysite.com%{REQUEST_URI}%{QUERY_STRING} [R=301,QSA,L]
Virtual host https:
RewriteRule !^/wp-admin/(.*) - [C]
RewriteRule ^/(.*) http://www.mysite.com/$1 [QSA,L]

#8 - wp Version

To not show the Wordpress version:

/* Remove links and version */
add_action('init', 'remheadlink');

function remheadlink() {
    remove_action('wp_head', 'rsd_link');
    remove_action('wp_head', 'wlwmanifest_link');
    remove_action('wp_head', 'wp_generator'); // remove wp versions
    remove_action('wp_head', 'start_post_rel_link');
    remove_action('wp_head', 'index_rel_link');
    remove_action('wp_head', 'adjacent_posts_rel_link');
} 

#9 - KEYS

Unique keys for identification

(If you change them you invalidate all existing cookies)

define('AUTH_KEY',         '~*+7U?+I!{rmDXf8@Tre0%4_9vYB^z1W^$X}!|niFs#p*`Hxloj6!Vi-IUANSu&l');
define('SECURE_AUTH_KEY',  '>)`fA[fW~)ra:nm<XLp`,$%y[:XHO$]M<X#.]tUh.&|DphKQtM2e3q6gO2+aVjF<');
define('LOGGED_IN_KEY',    'xw8ER`;Jgm{wJg2>i&A:kz:ya[-z+p SWVH{chgF-@kw$>_!5n*d7{a!{*XD$-!c');
define('NONCE_KEY',        'A}AO+49yjT!R|NsM,-<DU;O48Oom&9N7N/u+s)gwTnt).*8j`+Z6Xq|qUarKTJWe');
define('AUTH_SALT',        '|.aIOi}+v;A5[v/Wg?`}ZH|V6gVcFmpP(I)QX4]PT|s)W5#n~5+YdSNDsBMnGi+j');
define('SECURE_AUTH_SALT', 'Fi:M(D!`O$=xC(w>d7D>*!H`I>lT,|p%l{s?P2&1OvMk_h9#GknHOMYA{n-NOsV=');
define('LOGGED_IN_SALT',   'rn5%)xQQ(/v,+8:;_]i1f|M<&HtV}Xa4v<y,dUyR&3xeg-0YKyzssb`k!Djo{wW(');
define('NONCE_SALT',       'h+QSsR{yBoS&/xo~hoxD8O}k5OTx|T3j7HFVcdZvB(Hy],dm&TN/%tonO}6HyDqF');

https://api.wordpress.org/secret-key/1.1/salt/

#10 - CACHE


Server side:
Varnish

Wordpress side:
WP Super Cache
W3 Total Cache

THe END


Manuel Kanah
manuel@kanah.it
skype: testinaweb
my_wp: http://www.labna.it


http://slides.com/testinaweb/wordpress-best-practice


Special thanks:
Wordpress, Gabriele Giuranno, Francesco Lentini, Diane

Wor(l)dPress best practice

By Manuel Kanah

Wor(l)dPress best practice

  • 1,615