Como forçar os usuários a acessar minha página por HTTPS em vez de HTTP?


137

Eu tenho apenas uma página que quero forçar a ser acessada como uma página HTTPS (PHP no Apache). Como faço isso sem fazer com que o diretório inteiro exija HTTPS? Ou, se você envia um formulário para uma página HTTPS a partir de uma página HTTP, ele o envia por HTTPS em vez de HTTP?

Aqui está o meu exemplo:

http://www.example.com/some-page.php

Quero que ele seja acessado apenas através de:

https://www.example.com/some-page.php

Claro, eu posso colocar todos os links para esta página apontados para a versão HTTPS, mas isso não impede que algum tolo acesse-o por HTTP de propósito ...

Uma coisa que pensei foi colocar um redirecionamento no cabeçalho do arquivo PHP para verificar se eles estão acessando a versão HTTPS:

if($_SERVER["SCRIPT_URI"] == "http://www.example.com/some-page.php"){
  header('Location: https://www.example.com/some-page.php');
}

Mas esse não pode ser o caminho certo, pode?



3
Existe alguma razão para você não exigir apenas SSL para todas as páginas?
O Tahaan

Respostas:


177

A maneira como eu fiz isso antes é basicamente como o que você escreveu, mas não tem nenhum valor codificado:

if ($ _ SERVER ["HTTPS"]! = "ativado")
{
    header ("Localização: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    Saída();
}

15
Você esqueceu de chamar exit () para garantir que o script seja encerrado após o redirecionamento. Normalmente, envolvo isso em uma função chamada requireSSL (). Eu posso chamar isso no topo de qualquer página que eu queira ser criptografada.
Jesse Weigert

31
Altere o if to be (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")para corrigir os avisos do PHP.
precisa saber é o seguinte

As $_SERVER[]variáveis não são mutáveis ​​/ vulneráveis ​​à intervenção dos usuários?
Arian Faurtosh

@ArianFaurtosh fonte?
John

3
@ArianFaurtosh alguns são extraídos de cabeçalhos de clientes, como HTTP_X_FORWARDED, e podem ser manipulados, mas outros gostam HTTPSou SERVER_PORTsão definidos diretamente no servidor da web e geralmente devem ser seguros.
Mahn

46

Você poderia fazer isso com uma diretiva e mod_rewrite no Apache:

<Location /buyCrap.php>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Location>

Você pode tornar o local mais inteligente ao longo do tempo usando expressões regulares, se desejar.


6
Onde você colocaria isso? arquivo .htaccess?

1
REQUEST_URI não inclui a "string de consulta" (como? Page = 1 & id = 41 etc.)? Isso é o que a documentação apache diz ... Então, se eu tentar o acesso site.com/index.php?page=1&id=12 I será redirecionado site.com/index.php
Rolf

2
Da documentação do apache: REQUEST_URI O componente de caminho do URI solicitado, como "/index.html". Isso exclui notavelmente a string de consulta que está disponível como sua própria variável denominada QUERY_STRING. Então, você precisará adicionar QUERY_STRING após REQUEST_URI
Rolf

2
Você também precisa adicionar o flagelo [R] depois disso para torná-lo redirecionar
Rolf

40

Você deve forçar o cliente a solicitar HTTPS sempre com os cabeçalhos HTTP Strict Transport Security (HSTS):

// Use HTTP Strict Transport Security to force client to use secure connections only
$use_sts = true;

// iis sets HTTPS to 'off' for non-SSL requests
if ($use_sts && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
    header('Strict-Transport-Security: max-age=31536000');
} elseif ($use_sts) {
    header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
    // we are in cleartext at the moment, prevent further execution and output
    die();
}

Observe que o HSTS é suportado na maioria dos navegadores modernos, mas não universal. Portanto, a lógica acima redireciona manualmente o usuário, independentemente do suporte, se ele terminar em HTTP e, em seguida, define o cabeçalho HSTS para que outras solicitações do cliente sejam redirecionadas pelo navegador, se possível.


Estou surpreso que as outras respostas não incluam esse cabeçalho, é muito importante ... alguma armadilha para combinar os dois?
keisar

Não ... você pode definitivamente definir esse cabeçalho de qualquer maneira, se quiser sempre HTTPS. É meio redundante configurá-lo antes e depois do redirecionamento. Também alterei minha resposta acima para explicar com mais precisão a compatibilidade.
precisa

1
(Editando o comentário original) Não notei o requisito específico de "apenas uma página". O HSTS será aplicado a todas as páginas; minha resposta está tecnicamente incorreta.
precisa saber é o seguinte

4
Para sua informação, a seção 7.2 da RFC 6797 padrão diz "Um host HSTS NÃO DEVE incluir o campo de cabeçalho STS nas respostas HTTP transmitidas por transporte não seguro". portanto, não há necessidade de enviá-lo quando a solicitação é http normal; deve ser ignorado se o navegador seguir o padrão.
Frank Forte

1
@mark, se houver um MITM e seu site não tiver esse cabeçalho, você poderá permitir que uma sessão compreendida vá para http e as pessoas insiram seus detalhes e elas provavelmente não notarão e um redirecionamento não ajudará (o especialista em o meio se conectará ao site via https e o apresentará como http). O uso desse cabeçalho forçará o HTTPS no lado do cliente. Isso é particularmente importante devido à recente vulnerabilidade de segurança WPA2 WiFi.
quer

19

Acabei de criar um arquivo .htaccess e adicionei:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Simples!


9
// Force HTTPS for security
if($_SERVER["HTTPS"] != "on") {
    $pageURL = "Location: https://";
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
    }
    header($pageURL);
}

8

Tinha que fazer algo assim ao executar atrás de um balanceador de carga. Dica para o chapéu https://stackoverflow.com/a/16076965/766172

function isSecure() {
    return (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
     || $_SERVER['SERVER_PORT'] == 443
     || (
            (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
         || (!empty($_SERVER['HTTP_X_FORWARDED_SSL'])   && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
        )
    );
}

function requireHTTPS() {
    if (!isSecure()) {
        header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], TRUE, 301);
        exit;
    }
}

6

A maneira PHP:

$is_https=false;
if (isset($_SERVER['HTTPS'])) $is_https=$_SERVER['HTTPS'];
if ($is_https !== "on")
{
    header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
    exit(1);
}

A maneira mod_rewrite do Apache:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Eu prefiro o modo PHP, porque há casos em que desejo substituir o requisito de SSL. Por exemplo, acesso local a APIs e coisas como a configuração automática do Mozilla Thunderbird etc.
Jay

O método PHP funciona perfeitamente para mim, altamente recomendado.
Moxet Jan

5

http://www.besthostratings.com/articles/force-ssl-htaccess.html

Às vezes, pode ser necessário garantir que o usuário esteja navegando no site por uma conexão segura. Uma maneira fácil de redirecionar sempre o usuário para garantir a conexão (https: //) pode ser realizada com um arquivo .htaccess contendo as seguintes linhas:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

Observe que o arquivo .htaccess deve estar localizado na pasta principal do site.

Caso deseje forçar o HTTPS para uma pasta específica, você pode usar:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteCond %{REQUEST_URI} somefolder 
RewriteRule ^(.*)$ https://www.domain.com/somefolder/$1 [R,L]

O arquivo .htaccess deve ser colocado na pasta em que você precisa forçar o HTTPS.


5

Ok .. Agora, existem muitas coisas sobre isso agora, mas ninguém realmente completa a pergunta "Segura". Para mim, é ridículo usar algo que é inseguro.

A menos que você o use como isca.

A propagação do $ _SERVER pode ser alterada à vontade de alguém que sabe como.

Além disso, como Sazzad Tushar Khan e thebigjc declararam, você também pode usar oaccessaccess para fazer isso e há muitas respostas aqui contendo ele.

Basta adicionar:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://example.com/$1 [R,L]

até o final do que você tem no seu .httaccess e é isso.

Ainda não estamos tão seguros quanto possível com essas duas ferramentas.

O resto é simples. Se houver atributos ausentes, ou seja, ...

if(empty($_SERVER["HTTPS"])){ // SOMETHING IS FISHY
}

if(strstr($_SERVER['HTTP_HOST'],"mywebsite.com") === FALSE){// Something is FISHY
}


Diga também que você atualizou o seu arquivoaccessaccess e verifique:

if($_SERVER["HTTPS"] !== "on"){// Something is fishy
}

Há muito mais variáveis ​​que você pode verificar, isto é ..

HOST_URI (Se houver atributos estáticos para verificar)

HTTP_USER_AGENT (Valores diferentes da mesma sessão)

Então, tudo o que estou dizendo é que não se conforma com um ou outro quando a resposta está em uma combinação.

Para obter mais informações sobre a reescrita do updaccess, consulte os documentos-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Algumas pilhas aqui -> Forçar SSL / https usando .htaccess e mod_rewrite
e
Obtendo o URL completo do página atual (PHP)
para citar alguns.


2
mas agora eu recebo o seguinte erro: ERR_TOO_MANY_REDIRECTS. Como faço para corrigir isso?
Pathros

3

Use $_SERVER['HTTPS']para saber se é SSL e, se não , redirecione para o local certo.

E lembre-se, a página que exibe o formulário não precisa ser alimentada via HTTPS, é o URL de postagem que mais precisa.

Edit : yes, como é indicado abaixo, é melhor ter todo o processo em HTTPS. É muito mais reconfortante - eu estava apontando que o post é a parte mais crítica. Além disso, você precisa cuidar para que todos os cookies estejam configurados para serem seguros, para que sejam enviados apenas via SSL. A solução mod_rewrite também é muito bacana, usei-a para proteger muitos aplicativos em meu próprio site.


É verdade que o formulário em si não precisa ser https, embora seja uma boa ideia para a maioria das pessoas que não sabem disso. Se eles estiverem prestes a enviar o formulário e perceberem que o ícone de cadeado não está lá, eles podem assumir por engano que o formulário é inseguro.
Graeme Perrow

1
@ Graeme: além disso, ninguém pode ter certeza de que o formulário será enviado por https. O formulário inteiro (exibido por http) pode ser falso, sendo enviado para um site desconhecido ou http em texto não criptografado. Https não se trata apenas de criptografia, também autentica o servidor.
Olaf Kock

3

use htaccess:

#if domain has www. and not https://
  RewriteCond %{HTTPS} =off [NC]
  RewriteCond %{HTTP_HOST} ^(?i:www+\.+[^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]

#if domain has not www.
  RewriteCond %{HTTP_HOST} ^([^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]

1

Não misture HTTP e HTTPS na mesma página. Se você tiver uma página de formulário exibida via HTTP, ficarei nervoso com o envio de dados - não consigo ver se o envio passa por HTTPS ou HTTP sem fazer uma fonte de exibição e procurá-la.

Servir o formulário por HTTPS junto com o link de envio não é uma mudança tão grande para a vantagem.


1

Se você usa o Apache ou algo como o LiteSpeed, que suporta arquivos .htaccess, você pode fazer o seguinte. Se você ainda não possui um arquivo .htaccess, deve criar um novo arquivo .htaccess no diretório raiz (geralmente onde o index.php está localizado). Agora adicione estas linhas como as primeiras regras de reescrita no seu .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Você só precisa da instrução "RewriteEngine On" uma vez no seu .htaccess para todas as regras de reescrita; portanto, se você já a possui, copie a segunda e a terceira linha.

Eu espero que isso ajude.


Isto é o que funcionou para mim e o que estou usando em meus próprios scripts em um Framework semelhante ao Zend 2 - não entendo o voto negativo.
Antonio

Talvez você se downvoted porque a resposta é praticamente o mesmo que um presente de @MatHatrik que foi publicado mais de um ano antes?
Wilt

1

Usar isso NÃO é suficiente:

if($_SERVER["HTTPS"] != "on")
{
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

Se você tiver algum conteúdo http (como uma fonte externa de imagem http), o navegador detectará uma possível ameaça. Portanto, verifique se todas as suas referências e src dentro do seu código são https


1

Passei por muitas soluções com a verificação do status de $ _SERVER [HTTPS] mas parece que não é confiável porque às vezes ele não é ativado ou desativado, etc., causando o redirecionamento de loop interno do script.

Aqui está a solução mais confiável se o seu servidor suportar $ _SERVER [SCRIPT_URI]

if (stripos(substr($_SERVER[SCRIPT_URI], 0, 5), "https") === false) {
    header("location:https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
    echo "<meta http-equiv='refresh' content='0; url=https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]'>";
    exit;
}

Observe que, dependendo da sua instalação, seu servidor pode não suportar $ _SERVER [SCRIPT_URI], mas, se houver, esse é o melhor script a ser usado.

Você pode verificar aqui: Por que algumas instalações PHP têm $ _SERVER ['SCRIPT_URI'] e outras não


1

Para aqueles que usam o IIS, adicionar esta linha no web.config ajudará:

<httpProtocol>
    <customHeaders>
        <add name="Strict-Transport-Security" value="max-age=31536000"/>
    </customHeaders>
</httpProtocol>
<rewrite>
    <rules>
        <rule name="HTTP to HTTPS redirect" stopProcessing="true">
              <match url="(.*)" />
              <conditions>
                 <add input="{HTTPS}" pattern="off" ignoreCase="true" />
              </conditions>
              <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
         </rule>
    </rules>
</rewrite>

Um arquivo de exemplo completo

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Strict-Transport-Security" value="max-age=31536000"/>
             </customHeaders>
        </httpProtocol>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                      <match url="(.*)" />
                      <conditions>
                         <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                      </conditions>
                      <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
                 </rule>
            </rules>
       </rewrite>
   </system.webServer>
</configuration>

A pergunta é específica sobre o Apache, não o IIS.
Quentin

1
A) não está marcado como apache. O Apache é dividido entre aspas. B) é uma pergunta genérica que não tem nada a ver com apache em geral. Sua aplicável a vários servidores web que suportam PHP
Tschallacka

0

Você não deveria, por razões de segurança. Especialmente se houver cookies em jogo aqui. Isso deixa você aberto a ataques de repetição baseados em cookies.

De qualquer forma, você deve usar as regras de controle do Apache para ajustá-lo.

Em seguida, você pode testar se o HTTPS está ativado e redirecionar conforme necessário, onde necessário.

Você deve redirecionar para a página de pagamento apenas usando um FORM POST (sem obtenção) e os acessos à página sem um POST devem ser direcionados de volta para as outras páginas. (Isso fará com que as pessoas peguem pulos.)

http://joseph.randomnetworks.com/archives/2004/07/22/redirect-to-ssl-using-apaches-htaccess/

É um bom lugar para começar, desculpas por não fornecer mais. Mas você realmente deve empurrar tudo através do SSL.

É superprotetor, mas pelo menos você tem menos preocupações.


0

talvez este possa ajudar você, é assim que eu fiz no meu site, funciona como um encanto:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

if (!strstr($protocol, 'https')){
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

0

Se você deseja usar o PHP para fazer isso, dessa maneira funcionou muito bem para mim:


<?php

if(!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != "on") {
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"], true, 301);
    //Prevent the rest of the script from executing.
    exit;
}
?>

Ele verifica a variável HTTPS no array superglobal $ _SERVER para ver se é igual a "on". Se a variável não for igual a on.


-1

Eu usei esse script e funciona bem através do site.

if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off"){
    $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    enter code hereheader('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $redirect);
    exit();
}

-2
<?php 
// Require https
if ($_SERVER['HTTPS'] != "on") {
    $url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    header("Location: $url");
    exit;
}
?>

Tão fácil.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.