WordPress Sicherheit erhöhen ohne Plugins

#Update(02.10.2019): Es wurde ein neuer Befehl für das Blockieren von REST-API im function.php hinzugefügt inklusiver IP Whitelist.
#Update(19.12.2018): Es hat sich in letzter Zeit einiges geändert. Webbkoll überprüft die Webseiten jetzt genauer und da sind mir einige Lücken aufgefallen besonders im Bereich CSP(Content-Security-Policy). Dies konnte ich leider noch nicht vollständig beheben aber verbessern. Zudem habe ich eine 6G Firewall eingebaut und das Caching verbessert.
Das “.htaccess File” wurde jetzt vollständig überarbeitet.
In diesen Beitrag möchte ich euch zeigen wie ich ohne Plug-Ins die Sicherheit meiner Webseite erhöht habe, sowie die Sicherheit meiner Besucher. Am besten testet Ihr gleich eure eigene Webseite, wie sicher diese ist mit Webbkoll und an wem Ihr eure Besucher weiterleitet.
Das erste und einfachste was man tun kann ist Cookies und Verlinkungen zu vermeiden. (z.B. keine Fonts von Google usw.)
Auch wichtig ist es die Plug-Ins und Themes die nicht zwingend benötigt werden zu löschen (nicht nur deaktivieren). Ich benutze auch keine Sicherheits Plug-Ins da diese weitere Sicherheitslücken in mein System einbringen (Da man nie weiß was diese eigentlich wirklich tun). Das einzige Plug-In was ich benutze ist “Antispam Bee” um Spam Kommentare abzufangen und “No Right Click Images Plugin” um das kopieren meiner Fotos zu erschweren.
Als nächstes wenden wir uns das sichere einloggen des Admins. Dies machen wir über eine Zwei-Faktor-Authentifizierung.
Auf dieser Webseite wird erklärt wie man die “.htpasswd” erstellt die wir benötigen:
“die-netzialisten.de”
Um die weiteren Punkte für HTTP Security-Header, HTTPS, CSP werde ich über mein Config Datei erklären.
Achtung die Änderungen wurden nur auf ein Apache 2.4 Server getestet.
Als erstes bearbeiten wir die .htaccess die im Verzeichnis “/wordpress/…” liegt.
.htaccess (Stand: 10.2019)
################################################################################### # .htaccess by RayChan # Für WordPress 5.0 auf eine Synology Diskstation ################################################################################### # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress ################################################################################### # Umleitung HTTP zu HTTPS ################################################################################### RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] ################################################################################### # CORS aktivieren für bestimmte Dateitypen # Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, der Webbrowsern oder auch anderen # Webclients Cross-Origin-Requests ermöglicht. … CORS ist ein Kompromiss zugunsten größerer Flexibilität # im Internet unter Berücksichtigung möglichst hoher Sicherheitsmaßnahmen. ################################################################################### <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js|gif|png|jpe?g|svg|svgz|ico|webp)$"> Header set Access-Control-Allow-Origin "*" ################################################################################### # Der Referrer Header für mehr Datenschutz ################################################################################### ## No-Referrer-Header Header set Referrer-Policy "no-referrer" ################################################################################### # Die HTTP-Security-Header ################################################################################### ### @see https://scotthelme.co.uk/hardening-your-http-response-headers ## X-FRAME-OPTIONS-Header Header set X-Frame-Options "sameorigin" ## X-XSS-PROTECTION-Header Header set X-XSS-Protection "1; mode=block" ## X-Content-Type-Options-Header Header set X-Content-Type-Options "nosniff" ## Strict-Transport-Security-Header Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;" ################################################################################### # Content-Security-Policy (CSP) # https://www.ceilers-news.de/serendipity/373-Schutzmassnahmen-Content-Security-Policy-gegen-XSS,-Teil-1.html # http://www.heise.de/security/artikel/XSS-Bremse-Content-Security-Policy-1888522.html # +++ Muss ist noch nicht Komplett und muss umgebaut werden +++ ################################################################################### Header set Content-Security-Policy "frame-ancestors; font-src 'self';frame-src 'self'; object-src 'none';" ################################################################################### # Zwei-Faktor-Authentifizierung ################################################################################### # Auth protect wp-login.php AuthType Basic AuthName "Restricted Admin-Area" AuthUserFile /volume3/web/wordpress/.htpasswd Require valid-user ################################################################################### # | BLOCK NUISANCE REQUESTS - New in 2018 # https://perishablepress.com/block-nuisance-requests # Manche Bots suchen sehr emsig nichtexistente Dateien auf Deinem Server / Webhosting und blockieren auf diese # Weise die Ressourcen des Hostings. Der böswillige Datenverkehr spamt zudem die Fehlerprotokolle des Servers zu, # sodass eigentliche Probleme durch diese Anfragen an nichtexistente Dateien kaum mehr gefunden werden. # Comment it out, if you don't use Let's Encrypt, because Let's Encrypt ist using .well-known # Wenn Du Let's Encrypt nutzt, kannst Du das nicht verwenden, weil Let's Encrypt .well-known nutzt. ################################################################################### RedirectMatch 403 (?i)\.php\.suspected RedirectMatch 403 (?i)\.(git|well-known) RedirectMatch 403 (?i)apple-app-site-association RedirectMatch 403 (?i)/autodiscover/autodiscover.xml ################################################################################### # Sperrt Zugriffe auf Ordner und Dateien ################################################################################### # Deaktiviert sämtliche *.php dateien im Upload Ordner Require all denied # Sperrt Zugriff auf .hta dateien <FilesMatch "(\.htaccess|\.htpasswd)"> Require all denied # Sperrt Zugriffe auf wp-config / *.txt außer robots <FilesMatch "(^\.|wp-config\.php|(?<!robots)\.txt|(liesmich|readme)\.*)"> Require all denied ################################################################################### # Ausblenden des Inhaltsverzeichnisses ################################################################################### Options -Indexes ################################################################################### # Alle Fehlerhaften Seiten auf 404 umleiten ################################################################################### ErrorDocument 404 /error404.html ################################################################################### # Sperrt Zugriff auf XML-RPC ################################################################################### <FilesMatch "xmlrpc.php"> Require all denied ################################################################################### # Hotlink Protection gegen Bildklau # Das Hotlinking verhindert, dass Deine Bilder auf anderen Websites verlinkt werden können und # somit die Ressourcen Deines Webhostings negativ beeinflussen. Mit diesem Schutz werden Deine Bilder # nur dort angezeigt, wo sie es auch sollen. Auf Deiner Website. Du musst nur das Wort »domain« # in Zeile 6 gegen Deine Domain tauschen. ################################################################################### RewriteEngine on RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$ [NC] RewriteCond %{HTTP_REFERER} !^https?://([^.]+\.)?fototour-und-technik\. [NC] RewriteRule \.(gif|jpe?g?|png)$ - [F,NC,L] ################################################################################### #Browser Cache ################################################################################### ExpiresActive On ExpiresDefault "access plus 1 month" # CSS ExpiresByType text/css "access plus 1 year" # Data interchange ExpiresByType application/atom+xml "access plus 1 hour" ExpiresByType application/rdf+xml "access plus 1 hour" ExpiresByType application/rss+xml "access plus 1 hour" ExpiresByType application/json "access plus 0 seconds" ExpiresByType application/ld+json "access plus 0 seconds" ExpiresByType application/schema+json "access plus 0 seconds" ExpiresByType application/vnd.geo+json "access plus 0 seconds" ExpiresByType application/xml "access plus 0 seconds" ExpiresByType text/xml "access plus 0 seconds" # Favicon (cannot be renamed!) and cursor images ExpiresByType image/vnd.microsoft.icon "access plus 1 week" ExpiresByType image/x-icon "access plus 1 week" # HTML - Behält die Website eine Stunde im Cache, neues wird erst nach Ablauf einer Stunde # angezeigt. Wenn nicht gewuenscht, bei 3600 eine Null eintragen ExpiresByType text/html "access plus 3600 seconds" # JavaScript ExpiresByType application/javascript "access plus 1 year" ExpiresByType application/x-javascript "access plus 1 year" ExpiresByType text/javascript "access plus 1 year" # Manifest files ExpiresByType application/manifest+json "access plus 1 week" ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" ExpiresByType text/cache-manifest "access plus 0 seconds" # Media files ExpiresByType audio/ogg "access plus 1 month" ExpiresByType image/bmp "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType image/webp "access plus 1 month" ExpiresByType video/mp4 "access plus 1 month" ExpiresByType video/ogg "access plus 1 month" ExpiresByType video/webm "access plus 1 month" # Web fonts # Embedded OpenType (EOT) ExpiresByType application/vnd.ms-fontobject "access plus 1 month" ExpiresByType font/eot "access plus 1 month" # OpenType ExpiresByType font/opentype "access plus 1 month" # TrueType ExpiresByType application/x-font-ttf "access plus 1 month" # Web Open Font Format (WOFF) 1.0 ExpiresByType application/font-woff "access plus 1 month" ExpiresByType application/x-font-woff "access plus 1 month" ExpiresByType font/woff "access plus 1 month" # Web Open Font Format (WOFF) 2.0 ExpiresByType application/font-woff2 "access plus 1 month" # Other ExpiresByType text/x-cross-domain-policy "access plus 1 week" # Insert filters / compress text, html, javascript, css, xml: AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE text/vtt AddOutputFilterByType DEFLATE text/x-component AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/js AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript AddOutputFilterByType DEFLATE application/x-httpd-php AddOutputFilterByType DEFLATE application/x-httpd-fastphp AddOutputFilterByType DEFLATE application/atom+xml AddOutputFilterByType DEFLATE application/json AddOutputFilterByType DEFLATE application/ld+json AddOutputFilterByType DEFLATE application/vnd.ms-fontobject AddOutputFilterByType DEFLATE application/x-font-ttf AddOutputFilterByType DEFLATE application/font-woff2 AddOutputFilterByType DEFLATE application/x-font-woff AddOutputFilterByType DEFLATE application/x-web-app-manifest+json font/woff AddOutputFilterByType DEFLATE font/woff AddOutputFilterByType DEFLATE font/opentype AddOutputFilterByType DEFLATE image/svg+xml AddOutputFilterByType DEFLATE image/x-icon # Exception: Images SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png|svg)$ no-gzip dont-vary # Drop problematic browsers BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-vary #Alternative caching using Apache's "mod_headers", if it's installed. #Caching of common files - ENABLED <FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt)$"> Header set Cache-Control "max-age=2592000, public" <FilesMatch "\.(js|css|xml|gz)$"> Header append Vary Accept-Encoding # Set Keep Alive Header Header set Connection keep-alive # If your server don't support ETags deactivate with "None" (and remove header) Header unset ETag FileETag None <FilesMatch ".(js|css|xml|gz|html|woff|woff2|ttf)$"> Header append Vary: Accept-Encoding ################################################################################### # 6G - Firewal gegen die Einschleusung von Schadcode # 6G FIREWALL/BLACKLIST - Version 2018 # @ https://perishablepress.com/6g/ ################################################################################### # 6G:[QUERY STRINGS] RewriteEngine On RewriteCond %{QUERY_STRING} (eval\() [NC,OR] RewriteCond %{QUERY_STRING} (127\.0\.0\.1) [NC,OR] RewriteCond %{QUERY_STRING} ([a-z0-9]{2000,}) [NC,OR] RewriteCond %{QUERY_STRING} (javascript:)(.*)(;) [NC,OR] RewriteCond %{QUERY_STRING} (base64_encode)(.*)(\() [NC,OR] RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC,OR] RewriteCond %{QUERY_STRING} (<|%3C)(.*)script(.*)(>|%3) [NC,OR] RewriteCond %{QUERY_STRING} (\\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR] RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR] RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR] RewriteCond %{QUERY_STRING} (\'|\")(.*)(drop|insert|md5|select|union) [NC] RewriteRule .* - [F] # 6G:[REQUEST METHOD] RewriteCond %{REQUEST_METHOD} ^(connect|debug|move|put|trace|track) [NC] RewriteRule .* - [F] # 6G:[REFERRERS] RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000,}) [NC,OR] RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC] RewriteRule .* - [F] # 6G:[REQUEST STRINGS] RedirectMatch 403 (?i)([a-z0-9]{2000,}) RedirectMatch 403 (?i)(https?|ftp|php):/ RedirectMatch 403 (?i)(base64_encode)(.*)(\() RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\. RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&?)/?$ RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\") RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\s|\{|\}|\[|\]|\|) RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|etc/passwd|muieblack) RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ) RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$ RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php # 6G:[USER AGENTS] SetEnvIfNoCase User-Agent ([a-z0-9]{2000,}) bad_bot SetEnvIfNoCase User-Agent (archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune) bad_bot # Apache >= 2.3 Require all Granted Require not env bad_bot # 6G:[BAD IPS]
Als zweites erweitern wir die “functions.php” aus dem “/wordpress/wp-content/themes/****/…” Verzeichnis.
functions.php (Stand: 10.2019)
/* Automatische installieren von Updates */ /* add_filter( 'auto_update_plugin', '__return_true' ); */ /* Deaktivieren von Emoji's */ function disable_emojis() { remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ); remove_action( 'wp_print_styles', 'print_emoji_styles' ); remove_action( 'admin_print_styles', 'print_emoji_styles' ); remove_filter( 'the_content_feed', 'wp_staticize_emoji' ); remove_filter( 'comment_text_rss', 'wp_staticize_emoji' ); remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' ); add_filter( 'tiny_mce_plugins', 'disable_emojis_tinymce' ); } add_action( 'init', 'disable_emojis' ); /* Entfernen von TinyMCE emoji plugin */ function disable_emojis_tinymce( $plugins ) { if ( is_array( $plugins ) ) { return array_diff( $plugins, array( 'wpemoji' ) ); } else { return array(); } } /* Deaktivieren der XML-RPC Schnittstelle */ add_filter( 'xmlrpc_enabled', '__return_false' ); /* Deaktivieren der REST API Schnittstelle */ add_action('rest_api_init', function() { $whitelist = ['1.1.1.1', "::1"]; /* IP Whitelist*/ if(!in_array($_SERVER['REMOTE_ADDR'], $whitelist)){ die('REST API is disabled.'); } }, 1); /* HTTP-Header Eintrag entfernen */ function wps_remove_x_pingback( $headers ) { unset( $headers['X-Pingback'] ); return $headers; } add_filter( 'wp_headers', 'wps_remove_x_pingback' ); /* Entfernen von XMLRPC, WLW, Generator und ShortLink tags vom Header */ remove_action('wp_head', 'rsd_link');
Wenn Ihr dies alles getan habt, könnt Ihr nochmals eure Webseite mit Webbkoll testen.
19. Dez 2018 von