.htaccess Raccomandazioni

Oct 05 2020

Ho un sito web personale che viene utilizzato principalmente per divertimento. Carico immagini, video e testi che voglio condividere. Un modulo di invio HTML accetta domande e invii di stringhe da parte degli utenti, che utilizza una phpmyadmintabella di database per l'archiviazione.

Lo snippet di seguito è il mio .htaccessfile corrente .https://gtmetrix.com/ osserva che i reindirizzamenti sono il principale responsabile del rallentamento dei caricamenti della mia pagina, ma non sono sicuro di come semplificarli.

RewriteEngine On

#REDIRECT TO SECURE HTTPS CONNECTION
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#FORCE WWW TO NON-WWW
RewriteCond %{HTTP_HOST} ^www.MYDOMAIN.com [NC]
RewriteRule ^(.*)$ https://MYDOMAIN.com/$1 [L,R=301]

#URL EXTENSION REMOVAL
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]

#HOTLINKING PROTECTION
    #NOTE: having |html| and |htm| included prevented access of the site through browser search, so i removed them.
RewriteCond %{HTTP_REFERER} !^https://(www\.)?MYDOMAIN\.com(/.*)*$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule \.(css|flv|gif|ico|jpe|jpeg|jpg|js|mp3|mp4|php|png|pdf|swf|txt)$ - [F]

#CONTENT SECURITY POLICY
<FilesMatch "\.(html|php)$">
    Header set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: 'unsafe-inline'; media-src 'self' data: 'unsafe-inline'; connect-src 'self';"
</FilesMatch>

#REDIRECT FOR DATE PAGE
Redirect /date /storage/date-202010

#REDIRECT FOR HOME PAGE
Redirect /home /

#CUSTOM ERROR PAGES
ErrorDocument 400 /allerror.php
ErrorDocument 401 /allerror.php
ErrorDocument 403 /allerror.php
ErrorDocument 404 /allerror.php
ErrorDocument 405 /allerror.php
ErrorDocument 408 /allerror.php
ErrorDocument 500 /allerror.php
ErrorDocument 502 /allerror.php
ErrorDocument 504 /allerror.php

#PREVENT DIRECTORY BROWSING
Options All -Indexes

#FILE CACHING
    #cache html and htm files for one day
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "max-age=43200"
</FilesMatch>
    #cache css, javascript and text files for one week
<FilesMatch "\.(js|css|txt)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
    #cache flash and images for one month
<FilesMatch "\.(flv|swf|ico|gif|jpg|jpeg|mp4|png)$">
Header set Cache-Control "max-age=2592000"
</FilesMatch>
    #disable cache for script files
<FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
Header unset Cache-Control
</FilesMatch>

#BLOCKS FILE TYPES FOR USERS
<FilesMatch "\.(htaccess|htpasswd|ini|log|sh|inc|bak)$">
Order Allow,Deny
Deny from all
</FilesMatch>

AGGIORNARE

Ho creato un nuovo post integrando un HSTS e molte delle modifiche consigliate da Mr. White. La taglia è stata assegnata. Si prega di inviare qualsiasi ulteriore feedback al nuovo post .

Risposte

4 MrWhite Oct 15 2020 at 23:17

https://gtmetrix.com/ osserva che i reindirizzamenti sono il principale responsabile del rallentamento dei caricamenti delle mie pagine

Il "suggerimento" di gtmetrix.com a questo proposito è probabilmente "errato" (o meglio, non così serio come implica), supponendo che tu stia già collegando costantemente all'URL canonico * 1 in tutto il tuo sito (e non hai altri reindirizzamenti in il codice dell'applicazione). È probabile che questi reindirizzamenti interessino solo una "frazione molto piccola" dei visitatori del tuo sito alla loro prima visita.

( * 1 URL canonico indica HTTPS + non www + nessuna .htmlestensione.)

Hai 3 reindirizzamenti esterni nel .htaccesscodice che hai pubblicato:

#REDIRECT TO SECURE HTTPS CONNECTION
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#FORCE WWW TO NON-WWW
RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

#URL EXTENSION REMOVAL
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]

Se hai implementato HSTS, devi reindirizzare da HTTP a HTTPS sullo stesso host, prima di canonizzare il sottodominio www, che è quello che stai facendo sopra nella prima regola. Questo è un requisito dell'HSTS e della "lista di precaricamento". Quindi non puoi evitare di avere almeno 2 reindirizzamenti (caso peggiore) in questo scenario.

Tuttavia, se non hai intenzione di implementare HSTS, puoi combinare i primi due reindirizzamenti in uno solo. Cosa che puoi fare semplicemente invertendo l'ordine delle prime due regole. Per esempio:

#FORCE WWW TO NON-WWW
RewriteCond %{HTTP_HOST} ^www\.example\.com [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

#REDIRECT TO SECURE HTTPS CONNECTION
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

La prima regola, che reindirizza www a non www, reindirizza anche a HTTPS, quindi non è mai necessario eseguire anche il 2 ° reindirizzamento. Quindi, esiste sempre e solo 1 reindirizzamento per canonizzare HTTPS e non www.

Ho anche rimosso il subpattern di cattura ridondante (cioè (.*)) nel RewriteRule pattern "da HTTP a HTTPS" , dal momento che stai utilizzando REQUEST_URIinvece la variabile del server. E ha cambiato l'altro reindirizzamento "www in non www" per essere coerente. Si noti che la REQUEST_URIvariabile del server contiene il percorso URL completo, incluso il prefisso barra, mentre il backreference catturato omette il prefisso barra.

Le due regole precedenti potrebbero essere combinate in un'unica regola (leggermente più complessa), ma non vi è alcun vantaggio nel farlo.

Le regole potrebbero anche essere rese più "generiche", senza dover dichiarare esplicitamente il nome host canonico. Tuttavia, il modo in cui lo si implementa e se ciò sia facilmente possibile dipende dal fatto che si disponga o meno di altri sottodomini. Ma ancora una volta, questo non serve a nessun "vantaggio", a parte essere più copia / incollabile. In generale, è preferibile essere espliciti qui - meno inclini all'errore.

#URL EXTENSION REMOVAL
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]

Puoi anche evitare che il .html"reindirizzamento rimozione estensione" attivi un reindirizzamento aggiuntivo includendo prima questo reindirizzamento (prima dei due reindirizzamenti canonici sopra) e reindirizzando direttamente a HTTPS e non www (lo schema canonico + nome host) come parte del reindirizzamento.

AGGIORNAMENTO: anche questo dovrebbe essere un reindirizzamento 301 (permanente), non un reindirizzamento 302 (temporaneo) come è attualmente. Un reindirizzamento 301 viene memorizzato nella cache dal browser per impostazione predefinita, quindi evita round trip non necessari al server. Quando non includi esplicitamente il codice di stato con il Rflag, il valore predefinito è 302.

The NC flag is also not required on the RewriteRule directive, since you are not matching anything here that is case-sensitive.

This rule to remove the .html extension probably works OK for your URLs, however, it's not necessarily correct and could possibly be made more efficient. The reason for checking against THE_REQUEST server variable, as opposed to the RewriteRule pattern or REQUEST_URI server variable is to avoid a potential redirect loop by preventing rewritten requests from being redirected. This is because THE_REQUEST does not change after the request is rewritten - it contains the first line of the HTTP request headers. However, THE_REQUEST also contains the query string, so it's possible for a legitimate request that contains .html as part of the query string to be incorrectly redirected.

For example, request example.com/?p1=foo.html&p2=bar (the homepage with a query string and URL parameters containing the value foo.html) and this will be incorrectly redirected to example.com/?p1=foo, truncating the query string.

The regex /([^.]+)\.html will also fail to match any URL that contains dots as part of the URL-path in places other than the file extension. eg. A request for /foo.bar.html would not be redirected. Although this may be perfectly OK for the URLs on your site.

To avoid these "incorrect" redirects you could capture the URL-path from the RewriteRule pattern instead and either use a simpler condition and check against THE_REQUEST (to avoid a loop) or use the REDIRECT_STATUS environment variable instead, which is always empty on direct requests.

For example:

#URL EXTENSION REMOVAL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)\.html$ https://example.com/$1 [NC,R=301,L]

This captures the URL-path before the .html file extension using the RewriteRule pattern (which naturally excludes the query string). The simple condition that checks the REDIRECT_STATUS env var prevents a redirect loop.

Bringing the above points together we have:

#URL EXTENSION REMOVAL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)\.html$ https://example.com/$1 [NC,R=301,L]

#FORCE WWW TO NON-WWW
RewriteCond %{HTTP_HOST} ^www\.example\.com [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

#REDIRECT TO SECURE HTTPS CONNECTION
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

The NC flag was not required in the "URL extension removal" redirect.

This now triggers at most 1 redirect regardless of whether a request comes in for HTTP, www or includes the .html extension. However, as noted, this is at the expense of not satisfying the requirements for HSTS.

And it should be noted, that in real terms, there may not be a perceivable difference between 1, 2 or even 3 redirects here. Particularly since it will not affect the vast majority of visitors anyway.


Additional:

#REDIRECT FOR DATE PAGE
Redirect /date /storage/date-202010

#REDIRECT FOR HOME PAGE
Redirect /home /

Generally, you should avoid mixing redirects from both mod_alias (Redirect / RedirectMatch) and mod_rewrite (RewriteRule). The two modules run independently and at different times during the request, despite the apparent order of the directives in the .htaccess file. mod_rewrite runs first. So, you can get unexpected conflicts.

Note also that Redirect is prefix-matching and everything after the match is appended on to the end of the target URL. eg. /date/foo would get redirected to /storage/date-202010/foo by the first rule. These particular redirects are also 302 (temporary) redirects. It looks like they should be 301 (permanent)?

However, in this case it probably does not matter whether you use Redirect or RewriteRule, but as a general rule, if you are using mod_rewrite for some redirects, then use mod_rewrite for all redirects. For example:

#REDIRECT FOR DATE PAGE
RewriteRule ^date$ /storage/date-202010 [R=301,L]

#REDIRECT FOR HOME PAGE
RewriteRule ^home$ / [R=301,L]

#BLOCKS FILE TYPES FOR USERS
<FilesMatch "\.(htaccess|htpasswd|ini|log|sh|inc|bak)$">
Order Allow,Deny
Deny from all
</FilesMatch>

You stated in comments that you are using Apache 2.4, however Order, Allow and Deny are Apache 2.2 directives and are formerly deprecated on Apache 2.4. They still work, but for backwards compatibility only and should be updated as soon as.

Note that you need to update all instances on your system since the newer directives don't necessarily mix well.

On Apache 2.4 you would use the Require directive instead:

#BLOCKS FILE TYPES FOR USERS
<FilesMatch "\.(ht[ap]|ini|log|sh|inc|bak)$">
Require all denied
</FilesMatch>

Note that the Apache server config "should" already be blocking direct access to .htaccess and .htpasswd files, but better to be safe I guess.


ErrorDocument 500 /allerror.php

Defining the 500 ErrorDocument late in .htaccess is probably too late to catch most 500 (Internal Server Error) responses (that result from misconfigurations). There's probably not much you can do about this, but it would be preferable to define this earlier in the server config (or <VirtualHost> container) in order to be more "useful".