Recomendações .htaccess

Oct 05 2020

Tenho um site pessoal que é usado principalmente para diversão. Eu envio imagens, vídeos e textos que desejo compartilhar. Um formulário de envio de HTML aceita perguntas e envios de strings de usuários, que usam uma phpmyadmintabela de banco de dados para armazenamento.

O snippet abaixo é meu .htaccessarquivo atual .https://gtmetrix.com/ observa que os redirecionamentos são os maiores culpados por desacelerar o carregamento da minha página, mas não tenho certeza de como simplificá-los.

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>

ATUALIZAR

Eu criei um novo post integrando um HSTS e muitas das mudanças que foram recomendadas pelo Sr. White. A recompensa foi concedida. Por favor, direcione qualquer feedback adicional para o Novo Post .

Respostas

4 MrWhite Oct 15 2020 at 23:17

https://gtmetrix.com/ observa que os redirecionamentos são o maior culpado por desacelerar o carregamento da minha página

A "sugestão" de gtmetrix.com a esse respeito é indiscutivelmente "incorreta" (ou melhor, não é tão séria quanto sugere), supondo que você já esteja vinculando consistentemente ao URL canônico * 1 em todo o seu site (e não tenha outros redirecionamentos em seu código de aplicativo). É provável que esses redirecionamentos afetem apenas uma "fração muito pequena" dos visitantes do seu site na primeira visita.

( * 1 URL canônico sendo HTTPS + não www + nenhuma .htmlextensão.)

Você tem 3 redirecionamentos externos no .htaccesscódigo postado:

#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 você implementou o HSTS , você precisa redirecionar de HTTP para HTTPS no mesmo host, antes de canonizar o subdomínio www - que é o que você está fazendo acima na primeira regra. Este é um requisito do HSTS e da "lista de pré-carga". Portanto, você não pode evitar ter pelo menos 2 redirecionamentos (pior caso) neste cenário.

No entanto, se você não tiver intenção de implementar o HSTS, poderá combinar os dois primeiros redirecionamentos em um. O que você pode fazer simplesmente invertendo a ordem das duas primeiras regras. Por exemplo:

#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]

A primeira regra, que redireciona www para não www, também redireciona para HTTPS, portanto, nunca há necessidade de executar o segundo redirecionamento também. Portanto, há apenas um redirecionamento para canonizar HTTPS e não-www.

Também removi o subpadrão de captura redundante (ou seja, (.*)) no RewriteRule padrão "HTTP para HTTPS" , já que você está usando a REQUEST_URIvariável do servidor. E alterou o outro redirecionamento de "www para não www" para ser consistente. Observe que a REQUEST_URIvariável do servidor contém o caminho de URL completo, incluindo o prefixo de barra, enquanto a referência anterior capturada omite o prefixo de barra.

As duas regras acima podem ser combinadas em uma única regra (um pouco mais complexa), mas não há benefício em fazer isso.

As regras também podem ser mais "genéricas", sem a necessidade de indicar explicitamente o nome canônico do host. No entanto, como você implementa isso e se isso é facilmente possível, depende se você tem outros subdomínios ou não. Mas, novamente, isso não tem nenhum "benefício", exceto ser mais copiável / colável. Geralmente, é preferível ser explícito aqui - menos sujeito a erros.

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

Você também pode evitar que o .html"redirecionamento de remoção de extensão" acione um redirecionamento adicional incluindo este redirecionamento primeiro (antes dos dois redirecionamentos canônicos acima) e redirecionando diretamente para HTTPS e não www (o esquema canônico + nome do host) como parte do redirecionamento.

ATUALIZAÇÃO: Este também deve ser um redirecionamento 301 (permanente), não um redirecionamento 302 (temporário) que é atualmente. Um redirecionamento 301 é armazenado em cache pelo navegador por padrão, evitando viagens de ida e volta desnecessárias ao servidor. Quando você não inclui explicitamente o código de status com o Rsinalizador, o padrão é 302.

O NCsinalizador também não é necessário na RewriteRulediretiva, uma vez que você não está correspondendo a nada que faça distinção entre maiúsculas e minúsculas.

Esta regra para remover a .htmlextensão provavelmente funciona bem para seus URLs, no entanto, não é necessariamente correta e pode ser mais eficiente. O motivo para verificar a THE_REQUESTvariável do servidor, ao contrário do RewriteRule padrão ou da REQUEST_URIvariável do servidor, é evitar um loop de redirecionamento potencial, evitando que as solicitações reescritas sejam redirecionadas. Isso ocorre porque THE_REQUESTnão muda depois que a solicitação é regravada - ela contém a primeira linha dos cabeçalhos da solicitação HTTP. No entanto, THE_REQUESTtambém contém a string de consulta, portanto, é possível que uma solicitação legítima que contenha .htmlcomo parte da string de consulta seja redirecionada incorretamente.

Por exemplo, solicite example.com/?p1=foo.html&p2=bar(a página inicial com uma string de consulta e parâmetros de URL contendo o valor foo.html) e isso será redirecionado incorretamente para example.com/?p1=foo, truncando a string de consulta.

O regex /([^.]+)\.htmltambém falhará em corresponder a qualquer URL que contenha pontos como parte do caminho do URL em lugares diferentes da extensão do arquivo. por exemplo. Uma solicitação de /foo.bar.htmlnão seria redirecionada. Embora isso possa ser perfeitamente adequado para os URLs do seu site.

Para evitar esses redirecionamentos "incorretos", você pode capturar o caminho de URL do RewriteRule padrão e usar uma condição mais simples e verificar THE_REQUEST(para evitar um loop) ou usar a REDIRECT_STATUSvariável de ambiente, que está sempre vazia em solicitações diretas.

Por exemplo:

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

Isso captura o caminho da URL antes da .htmlextensão do arquivo usando o RewriteRule padrão (que naturalmente exclui a string de consulta). A condição simples que verifica o REDIRECT_STATUSenv var evita um loop de redirecionamento.

Reunindo os pontos acima, temos:

#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]

A NCsinalização não era necessária no redirecionamento "remoção de extensão de URL".

Isso agora dispara no máximo 1 redirecionamento, independentemente de a solicitação entrar em HTTP, www ou incluir a .htmlextensão. No entanto, conforme observado, isso ocorre às custas do não cumprimento dos requisitos do HSTS.

E deve ser notado, que em termos reais, pode não haver uma diferença perceptível entre 1, 2 ou mesmo 3 redirecionamentos aqui. Principalmente porque não afetará a grande maioria dos visitantes.


Adicional:

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

#REDIRECT FOR HOME PAGE
Redirect /home /

Geralmente, você deve evitar misturar redirecionamentos de mod_alias ( Redirect/ RedirectMatch) e mod_rewrite ( RewriteRule). Os dois módulos funcionam de forma independente e em momentos diferentes durante a solicitação, apesar da ordem aparente das diretivas no .htaccessarquivo. mod_rewrite é executado primeiro. Portanto, você pode obter conflitos inesperados.

Observe também que Redirecthá correspondência de prefixo e tudo após a correspondência é anexado ao final do URL de destino. por exemplo. /date/fooseria redirecionado para /storage/date-202010/foopela primeira regra. Esses redirecionamentos específicos também são redirecionamentos 302 (temporários). Parece que eles deveriam ser 301 (permanentes)?

No entanto, neste caso provavelmente não importa se você usa Redirectou RewriteRule, mas como regra geral, se você estiver usando mod_rewrite para alguns redirecionamentos, use mod_rewrite para todos os redirecionamentos. Por exemplo:

#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>

Você declarou em comentários que está usando o Apache 2.4, no entanto Order, Allowe Denysão diretivas do Apache 2.2 e foram descontinuados anteriormente no Apache 2.4. Eles ainda funcionam, mas apenas para compatibilidade com versões anteriores e devem ser atualizados assim que.

Observe que você precisa atualizar todas as instâncias em seu sistema, já que as diretivas mais recentes não necessariamente combinam bem.

No Apache 2.4, você usaria a Requirediretiva:

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

Observe que a configuração do servidor Apache "deveria" já estar bloqueando o acesso direto aos arquivos .htaccesse .htpasswd, mas acho melhor estar seguro.


ErrorDocument 500 /allerror.php

Definindo a 500 ErrorDocument tarde no .htaccessé provavelmente tarde demais para pegar a maioria das respostas 500 (Internal Server Error) (que resultam de erros de configuração ). Provavelmente não há muito que você possa fazer sobre isso, mas seria preferível definir isso anteriormente na configuração do servidor (ou <VirtualHost>contêiner) para ser mais "útil".