Notatnik techniczny

.htaccess - co powinien zawierać

Szablon pliku .htaccess

Ten szablon nie zawiera adresu pod jakim jest umieszczony, można go łatwo kopiować pomiędzy projektami.

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg                 "access 1 month"
    ExpiresByType image/jpeg                "access 1 month"
    ExpiresByType image/gif                 "access 1 month"
    ExpiresByType image/png                 "access 1 month"
    ExpiresByType text/css                  "access 1 month"
    ExpiresByType text/html                 "access 5 minutes"
    ExpiresByType application/pdf           "access 1 month"
    ExpiresByType text/x-javascript         "access 1 month"
    ExpiresByType application/javascript    "access 1 month"
    ExpiresByType image/x-icon              "access 1 month"
    ExpiresDefault                          "access 6 hours"
</IfModule>

<IfModule mod_headers.c>
    Header set Content-Security-Policy " \
        default-src 'self' https://*.disqus.com https://c.disquscdn.com\;
        script-src 'self' 'unsafe-inline' https://www.google-analytics.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://www.googletagmanager.com; \
        object-src 'none'; \
        frame-src https://disqus.com https://www.youtube.com; \
        img-src 'self'; \
        style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net; \
        connect-src 'self' https://*.disqus.com; \
        font-src https://fonts.googleapis.com https://fonts.gstatic.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net; \
        base-uri 'self'"

    Header always set X-Content-Type-Options "nosniff"

    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

    Header always set X-FRAME-OPTIONS "DENY"

    Header always set X-XSS-Protection "1; mode=block"

    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    Header set Referrer-Policy "origin-when-cross-origin"

    Header set Feature-Policy: "vibrate 'none'; \
                                notifications 'none'; \
                                push 'none'; \
                                microphone 'none'; \
                                camera 'none'; \
                                payment 'none'; \
                                geolocation 'self'"

</IfModule>

AddDefaultCharset UTF-8

RewriteEngine On

ErrorDocument 401 https://%{SERVER_NAME}/404
ErrorDocument 404 https://%{SERVER_NAME}/404
ErrorDocument 500 https://%{SERVER_NAME}/404

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

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{SERVER_NAME}/$1 [R=301,L]

RewriteRule ^index\.html$ / [R=301,L]
RewriteRule ^(.*)/index\.html$ /$1/ [R=301,L]


ServerSignature Off

Wyjaśnienie działania

Konfiguracja czasu życia

Ustalamy jak długo przeglądarka ma przechowywać zasoby bez ich ponownego pobierania.

<IfModule mod_expires.c>
	ExpiresActive On
	ExpiresByType image/jpg                 "access 1 month"
	ExpiresByType image/jpeg                "access 1 month"
	ExpiresByType image/gif                 "access 1 month"
	ExpiresByType image/png                 "access 1 month"
	ExpiresByType text/css                  "access 1 month"
	ExpiresByType text/html                 "access 5 minutes"
	ExpiresByType application/pdf           "access 1 month"
	ExpiresByType text/x-javascript         "access 1 month"
	ExpiresByType application/javascript    "access 1 month"
	ExpiresByType image/x-icon              "access 1 month"

	ExpiresDefault                          "access 6 hours"
</IfModule>

Ustawiamy Content-Security-Policy

Definiujemy Content-Security-Policy, osobno dla różnych typów zasobów

Header set Content-Security-Policy " \
    default-src 'self' https://*.disqus.com https://c.disquscdn.com\;
    script-src 'self' 'unsafe-inline' https://www.google-analytics.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://www.googletagmanager.com; \
    object-src 'none'; \
    frame-src https://disqus.com https://www.youtube.com; \
    img-src 'self'; \
    style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net; \
    connect-src 'self' https://*.disqus.com; \
    font-src https://fonts.googleapis.com https://fonts.gstatic.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net; \
    base-uri 'self'"

Nagłówki związane z bezpieczeństwem

Przeglądarka nie będzie ‘zgadywać’ typu MIME zasobu na podstawie zawartości. (link)

Header always set X-Content-Type-Options "nosniff"

Ciasteczka nie dostępne z poziomu javascript. (link)

Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

Zabraniamy wyświetlać naszą stronę w ramkach. (link)

Header always set X-FRAME-OPTIONS "DENY"

Utrudniamy ataki XSS. (link)

Header always set X-XSS-Protection "1; mode=block"

Informujemy klienta ze ta witryna powinna być dostępna tylko przez https. (link)

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Definiujemy jakie informacje będą przekazywane do obcych serwerów w nagłówku Referer. (link)

Header set Referrer-Policy "origin-when-cross-origin"

Wyłączamy wybrane API przeglądarki dla danej witryny. (link)

Header set Feature-Policy: "vibrate 'none'; \
                            notifications 'none'; \
                            push 'none'; \
                            microphone 'none'; \
                            camera 'none'; \
                            payment 'none'; \
                            geolocation 'self'"

Przekierowania

Strony błędów

ErrorDocument 401 https://%{SERVER_NAME}/404
ErrorDocument 404 https://%{SERVER_NAME}/404
ErrorDocument 500 https://%{SERVER_NAME}/404

Przekierowanie do adresu bez www

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

Przekierowanie do protokołu https

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{SERVER_NAME}/$1 [R=301,L]

Nie wyświetlamy ‘.html’ na końcu nazwy zasobu

RewriteRule ^index\.html$ / [R=301,L]
RewriteRule ^(.*)/index\.html$ /$1/ [R=301,L]

Odnośniki