WordPress Sicherheit erhöhen ohne Plugins

19. Dezember 2018 0 Von Raychan

#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
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
 
###################################################################################
# Umleitung HTTP zu HTTPS
###################################################################################
<IfModule mod_headers.c>
	RewriteEngine On
	RewriteCond %{HTTPS} !=on
	RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
 
###################################################################################
# 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.
###################################################################################
<IfModule mod_headers.c>
    <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 "*"
    </FilesMatch>
</IfModule>
 
###################################################################################
# Der Referrer Header für mehr Datenschutz
###################################################################################
## No-Referrer-Header
<IfModule mod_headers.c>
    Header set Referrer-Policy "no-referrer"
</IfModule>
 
###################################################################################
# Die HTTP-Security-Header
###################################################################################
### @see https://scotthelme.co.uk/hardening-your-http-response-headers
 
## X-FRAME-OPTIONS-Header
<IfModule mod_headers.c>
    Header set X-Frame-Options "sameorigin"
</IfModule>
 
## X-XSS-PROTECTION-Header
<IfModule mod_headers.c>
    Header set X-XSS-Protection "1; mode=block"
</IfModule>
 
## X-Content-Type-Options-Header
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
</IfModule>
 
## Strict-Transport-Security-Header 
<IfModule mod_headers.c>
   Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;"
</IfModule>
 
###################################################################################
# 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 +++
###################################################################################
<IfModule mod_headers.c>
	Header set Content-Security-Policy "frame-ancestors; font-src 'self';frame-src 'self'; object-src 'none';"
</IfModule>
 
###################################################################################
# Zwei-Faktor-Authentifizierung
###################################################################################
# Auth protect wp-login.php
<Files wp-login.php>
	AuthType Basic
	AuthName "Restricted Admin-Area"
	AuthUserFile /volume3/web/wordpress/.htpasswd
   Require valid-user
</Files>
 
###################################################################################
# | 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.
###################################################################################
<IfModule mod_alias.c>
	RedirectMatch 403 (?i)\.php\.suspected
	RedirectMatch 403 (?i)\.(git|well-known)
	RedirectMatch 403 (?i)apple-app-site-association
	RedirectMatch 403 (?i)/autodiscover/autodiscover.xml
</IfModule>
 
###################################################################################
# Sperrt Zugriffe auf Ordner und Dateien
###################################################################################
# Deaktiviert sämtliche *.php dateien im Upload Ordner
<FilesMatch /volume3/web/wordpress/wp-content/uploads/*.php$>
   Require all denied
</FilesMatch>
 
# Sperrt Zugriff auf .hta dateien
<FilesMatch "(\.htaccess|\.htpasswd)">
	Require all denied
</FilesMatch>
 
# Sperrt Zugriffe auf wp-config / *.txt außer robots
<FilesMatch "(^\.|wp-config\.php|(?<!robots)\.txt|(liesmich|readme)\.*)">
   Require all denied
</FilesMatch>
 
###################################################################################
# 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
</FilesMatch>
 
###################################################################################
# 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.
###################################################################################
<IfModule mod_rewrite.c>
     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]
</ifModule>
 
###################################################################################
#Browser Cache
###################################################################################
<IfModule mod_expires.c>
	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"
</IfModule>
 
<IfModule mod_deflate.c>
	# 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
</IfModule>
 
#Alternative caching using Apache's "mod_headers", if it's installed.
#Caching of common files - ENABLED
<IfModule mod_headers.c>
	<FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt)$">
		Header set Cache-Control "max-age=2592000, public"
	</FilesMatch>
</IfModule>
 
<IfModule mod_headers.c>
	<FilesMatch "\.(js|css|xml|gz)$">
		Header append Vary Accept-Encoding
	</FilesMatch>
</IfModule>
 
# Set Keep Alive Header
<IfModule mod_headers.c>
    Header set Connection keep-alive
</IfModule>
 
# If your server don't support ETags deactivate with "None" (and remove header)
<IfModule mod_expires.c> 
    <IfModule mod_headers.c> 
      Header unset ETag 
    </IfModule> 
    FileETag None 
</IfModule>
 
<IfModule mod_headers.c>
	<FilesMatch ".(js|css|xml|gz|html|woff|woff2|ttf)$">
		Header append Vary: Accept-Encoding
	</FilesMatch>
</IfModule>
 
###################################################################################
# 6G - Firewal gegen die Einschleusung von Schadcode
# 6G FIREWALL/BLACKLIST - Version 2018
# @ https://perishablepress.com/6g/
###################################################################################
# 6G:[QUERY STRINGS]
<IfModule mod_rewrite.c>
	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]
</IfModule>
 
# 6G:[REQUEST METHOD]
<IfModule mod_rewrite.c>
	RewriteCond %{REQUEST_METHOD} ^(connect|debug|move|put|trace|track) [NC]
	RewriteRule .* - [F]
</IfModule>
 
# 6G:[REFERRERS]
<IfModule mod_rewrite.c>
	RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000,}) [NC,OR]
	RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC]
	RewriteRule .* - [F]
</IfModule>
 
# 6G:[REQUEST STRINGS]
<IfModule mod_alias.c>
	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)/(\$(\&)?|\*|\"|\.|,|&|&amp;?)/?$
	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
</IfModule>
 
# 6G:[USER AGENTS]
<IfModule mod_setenvif.c>
	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
	<IfModule mod_authz_core.c>
		<RequireAll>
			Require all Granted
			Require not env bad_bot
		</RequireAll>
	</IfModule>
</IfModule>
 
# 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.

Dann müsste eure Webseite so aussehen: