Tag Archive: wordpress

WordPress mit naxsi

Naxsi (Logo von MARE system)

Changelog

  • 24.10.2014 – Merged latest rules from github
  • 29.12.2013 – Merged latest rules from github
  • 29.12.2013 – Fix for „wp-admin/customize.php“

Ich habe mittlerweile einen Beitrag zum erstellen eigener Whitelists erstellt.

Naxsi ist die Web Application Firewall von nginx. Sie läuft als Modul mit nginx und ist im Gegensatz zu anderen Lösungen sehr einfach zu konfigurieren. Ebenfalls gibt es einen „Lernmodus“, um Regeln quasi anzulernen. Hierzu erschien im Admin Magazin ein schöner Artikel, der sich auch zu kaufen lohnt.

Mehr oder weniger durch Zufall bin ich auf ein fertiges Regelwerk gestoßen, um WordPress mit naxsi abzusichern. Die Quelle befindet sich hier.

Voraussetzung ist natürlich, dass nginx bereits installiert ist. Das Meta-Paket „nginx“ beinhaltet naxsi nicht, jedoch kann nginx mit dem Modul naxsi einfach nachinstalliert werden, die Konfigurationen bleiben erhalten und werden nicht überschrieben:

sudo apt-get install nginx-naxsi

In der Datei /etc/nginx/nginx.conf befand sich bereits ein Parameter für naxsi, der nun aktivieret werden kann:

/etc/nginx/nginx.conf:

http {
...
        include /etc/nginx/naxsi_core.rules;
...
}

Naxsi sieht vor, für jede Location im Server-Abschnitt ein eigenes Regelwerk zu verwenden. Dazu wird nun die jeweilige Site Konfiguration geöffnet, die WordPress beinhaltet. Zusätzlich wird eine neue Location angelegt, in die der Besucher im Falle weitergeleitet wird.

/etc/nginx/sites-available/default (Beispiel!):

server {
...
        location / {
                include    /etc/nginx/naxsi_wp.rules;
                ...
        }

        location /Denied {
                return 500;
        }
...
}

In diesem Fall befinden sich die Regeln – logischerweise – in der Datei „/etc/nginx/naxsi_wp.rules“.
Die Datei herunterladen:

wget http://debinux.de/wp-content/uploads/naxsi.rules -O /etc/nginx/naxsi_wp.rules

Zur Übersicht/Vollständigkeit hier der Code:

# Sample rules file for default vhost.
 
#LearningMode;
SecRulesEnabled;
#SecRulesDisabled;
DeniedUrl "/Denied";
 
## check rules
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
 
# WordPress naxsi rules

### HEADERS
BasicRule wl:1000,1001,1005,1007,1010,1011,1013,1100,1200,1308,1309,1310,1311,1315 "mz:$HEADERS_VAR:cookie";
# xmlrpc
BasicRule wl:1402 "mz:$HEADERS_VAR:content-type";

### simple BODY (POST)
# comments
BasicRule wl:1000,1010,1011,1013,1015,1200,1310,1311 "mz:$BODY_VAR:post_title";
BasicRule wl:1000 "mz:$BODY_VAR:original_publish";
BasicRule wl:1000 "mz:$BODY_VAR:save";
BasicRule wl:1008,1010,1011,1013,1015 "mz:$BODY_VAR:sk2_my_js_payload";
BasicRule wl:1001,1009,1005,1016,1100,1310 "mz:$BODY_VAR:url";
BasicRule wl:1009,1100 "mz:$BODY_VAR:referredby";
BasicRule wl:1009,1100 "mz:$BODY_VAR:_wp_original_http_referer";
BasicRule wl:1000,1001,1005,1008,1007,1009,1010,1011,1013,1015,1016,1100,1200,1302,1303,1310,1311,1315,1400 "mz:$BODY_VAR:comment";
BasicRule wl:1100 "mz:$BODY_VAR:redirect_to";
BasicRule wl:1000,1009,1315 "mz:$BODY_VAR:_wp_http_referer";
BasicRule wl:1000 "mz:$BODY_VAR:action";
BasicRule wl:1001,1013 "mz:$BODY_VAR:blogname";
BasicRule wl:1015,1013 "mz:$BODY_VAR:blogdescription";
BasicRule wl:1015 "mz:$BODY_VAR:date_format_custom";
BasicRule wl:1015 "mz:$BODY_VAR:date_format";
BasicRule wl:1015 "mz:$BODY_VAR:tax_input%5bpost_tag%5d";
BasicRule wl:1015 "mz:$BODY_VAR:tax_input[post_tag]";
BasicRule wl:1100 "mz:$BODY_VAR:siteurl";
BasicRule wl:1100 "mz:$BODY_VAR:home";
BasicRule wl:1000,1015 "mz:$BODY_VAR:submit";
# news content matches pretty much everything
BasicRule wl:0 "mz:$BODY_VAR:content";
BasicRule wl:1000 "mz:$BODY_VAR:delete_option";
BasicRule wl:1000 "mz:$BODY_VAR:prowl-msg-message";
BasicRule wl:1100 "mz:$BODY_VAR:_url";
BasicRule wl:1001,1009 "mz:$BODY_VAR:c2c_text_replace%5btext_to_replace%5d";
BasicRule wl:1200 "mz:$BODY_VAR:ppn_post_note";
BasicRule wl:1100 "mz:$BODY_VAR:author";
BasicRule wl:1001,1015 "mz:$BODY_VAR:excerpt";
BasicRule wl:1015 "mz:$BODY_VAR:catslist";
BasicRule wl:1005,1008,1009,1010,1011,1015,1315 "mz:$BODY_VAR:cookie";
BasicRule wl:1101 "mz:$BODY_VAR:googleplus";
BasicRule wl:1007 "mz:$BODY_VAR:name";
BasicRule wl:1007 "mz:$BODY_VAR:action";
BasicRule wl:1100 "mz:$BODY_VAR:attachment%5burl%5d";
BasicRule wl:1100 "mz:$BODY_VAR:attachment_url";
BasicRule wl:1001,1009,1100,1302,1303,1310,1311 "mz:$BODY_VAR:html";
BasicRule wl:1015 "mz:$BODY_VAR:title";
BasicRule wl:1001,1009,1015 "mz:$BODY_VAR:recaptcha_challenge_field";
BasicRule wl:1011 "mz:$BODY_VAR:pwd";
BasicRule wl:1000 "mz:$BODY_VAR:excerpt";

### BODY|NAME
BasicRule wl:1000 "mz:$BODY_VAR:delete_option|NAME";
BasicRule wl:1000 "mz:$BODY_VAR:from|NAME";

### Simple ARGS (GET)
# WP login screen
BasicRule wl:1100 "mz:$ARGS_VAR:redirect_to";
BasicRule wl:1000,1009 "mz:$ARGS_VAR:_wp_http_referer";
BasicRule wl:1000 "mz:$ARGS_VAR:wp_http_referer";
BasicRule wl:1000 "mz:$ARGS_VAR:action";
BasicRule wl:1000 "mz:$ARGS_VAR:action2";
# load and load[] GET variable
BasicRule wl:1000,1015 "mz:$ARGS_VAR:load";
BasicRule wl:1000,1015 "mz:$ARGS_VAR:load[]";
BasicRule wl:1015 "mz:$ARGS_VAR:q";
BasicRule wl:1000,1015 "mz:$ARGS_VAR:load%5b%5d";

### URL
BasicRule wl:1000 "mz:URL|$URL:/wp-admin/update-core.php";
BasicRule wl:1000 "mz:URL|$URL:/wp-admin/update.php";
# URL|BODY
BasicRule wl:1009,1100 "mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_http_referer";
BasicRule wl:1016 "mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect";
BasicRule wl:11 "mz:$URL:/xmlrpc.php|BODY";
BasicRule wl:11 "mz:$URL:/wp-cron.php|BODY";
BasicRule wl:2 "mz:$URL:/wp-admin/async-upload.php|BODY";
# URL|BODY|NAME
BasicRule wl:1100 "mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_original_http_referer|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/user-edit.php|$BODY_VAR:from|NAME";
BasicRule wl:1100 "mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:attachment%5burl%5d|NAME";
BasicRule wl:1100 "mz:$URL:/wp-admin/post.php|$BODY_VAR:attachment_url|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/plugins.php|$BODY_VAR:verify-delete|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/post.php|$BODY_VAR:post_category[]|NAME";
BasicRule wl:1311 "mz:$URL:/wp-admin/post.php|$BODY_VAR:post_category|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/post.php|$BODY_VAR:tax_input[post_tag]|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/post.php|$BODY_VAR:newtag[post_tag]|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/users.php|$BODY_VAR:users[]|NAME";
# URL|ARGS|NAME
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/load-scripts.php|$ARGS_VAR:load[]|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/users.php|$ARGS_VAR:delete_count|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/users.php|$ARGS_VAR:update|NAME";

# plain WP site
BasicRule wl:1000 "mz:URL|$URL:/wp-admin/update-core.php";
BasicRule wl:1000 "mz:URL|$URL:/wp-admin/update.php";
# URL|BODY
BasicRule wl:1009,1100 "mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_http_referer";
BasicRule wl:1016 "mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect";
BasicRule wl:11 "mz:$URL:/xmlrpc.php|BODY";
BasicRule wl:11 "mz:$URL:/wp-cron.php|BODY";
# URL|BODY|NAME
BasicRule wl:1100 "mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_original_http_referer|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/user-edit.php|$BODY_VAR:from|NAME";
BasicRule wl:1100 "mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:attachment%5burl%5d|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:data[wp-auth-check]|NAME";
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/update-core.php|$BODY_VAR:checked[]|NAME";

# URL|ARGS|NAME
BasicRule wl:1310,1311 "mz:$URL:/wp-admin/load-scripts.php|$ARGS_VAR:load[]|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/users.php|$ARGS_VAR:delete_count|NAME";
BasicRule wl:1000 "mz:$URL:/wp-admin/users.php|$ARGS_VAR:update|NAME";

# WP 3.6/8 Fix
BasicRule wl:1100 "mz:$URL:/|$ARGS_VAR:statify_referrer";
BasicRule wl:1001,1015,1009,1311,1310,1101,1016 "mz:$URL:/|$BODY_VAR:customized";
### Plugins
#WP Minify
BasicRule wl:1015 "mz:$URL:/wp-content/plugins/bwp-minify/min/|$ARGS_VAR:f";

Via „naxsi_wp.rules“ wird /Denied als Umleitung für geblockte Anfragen definiert. „return 500“ würde ergo auf die Fehlerseite 500 verweisen. Selbstverständlich sind diese Pfade und Parameter nach Belieben einzustellen. Wer witzig ist, darf auch 418 zurückgeben. ;)

Zur Aktivierung den Dienst neustarten:

service nginx restart

Achtung: Bei WordPress Updates kann es passieren, dass die Regeln geändert werden müssen! Ich habe die obigen Regeln erfolgreich auf WordPress 3.8 getestet. Sollte etwas nicht mehr funktionieren, empfehle ich den Lernmodus („LearningMode“) zu aktivieren und das Wiki zu naxsi zu studieren. Ein Blick in die Funktionsweise schadet generell nicht und sollte in jedem Fall schon geschehen sein.

Hat naxsi etwas gefiltert, so wird dies in der Fehler-Logdatei (via „ErrorLog“) des jeweiligen Servers festgehalten.
Getestet werden kann die Konfiguration und Wirksamkeit, indem „?a=<>“ an eine WordPress URL angehängt wird, z.B. www.domain.tld/?a=<>
Der Fehler wird protokolliert:

NAXSI_FMT: ip=X.X.X.X&server=www.domain.tld&uri=/&learning=0&total_processed=8&total_blocked=2&zone0=ARGS&id0=1302&var_name0=a, client: X.X.X.X, server: debinux.de, request: „GET /?a=%3C%3E HTTP/1.1“, host: „www.domain.tld“


Das naxsi-Logo ist Eigentum von MARE system.

Ladezeit verbessern: jQuery im Footer von WordPress laden

Ein kleines Snippet, um jQuery im Footer von WordPress zu laden. Daher ohne großes Getippe:

Gehört in die Datei „functions.php“ des jeweiligen Themes, z.B. „/wordpress/wp-content/themes/custom-1/functions.php“.

function evolution_clean_head() {
 
	remove_action('wp_head', 'wp_print_scripts'); 
	remove_action('wp_head', 'wp_print_head_scripts', 9); 
	remove_action('wp_head', 'wp_enqueue_scripts', 1); 
}
 
add_action( 'wp_enqueue_scripts', 'evolution_clean_head' );

Weiterlesen