¿Cómo puedo forzar a los usuarios a acceder a mi página a través de HTTPS en lugar de HTTP?

137

Solo tengo una página que quiero forzar para que se acceda como una página HTTPS (PHP en Apache). ¿Cómo hago esto sin hacer que todo el directorio requiera HTTPS? O, si envía un formulario a una página HTTPS desde una página HTTP, ¿lo envía por HTTPS en lugar de HTTP?

Aquí está mi ejemplo:

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

Quiero que solo se acceda a través de:

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

Claro, puedo poner todos los enlaces a esta página apuntados a la versión HTTPS, pero eso no impide que algún tonto acceda a través de HTTP a propósito ...

Una cosa que pensé fue poner una redirección en el encabezado del archivo PHP para verificar que estén accediendo a la versión HTTPS:

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

Pero esa no puede ser la forma correcta, ¿verdad?

Wiki
fuente
posible duplicado de Force SSL / https usando .htaccess y mod_rewrite
Trilarion
3
¿Hay alguna razón por la que no solo requiera SSL para todas las páginas?
El Tahaan

Respuestas:

177

La forma en que lo hice antes es básicamente como lo que escribió, pero no tiene ningún valor codificado:

if ($ _ SERVER ["HTTPS"]! = "activado")
{
    header ("Ubicación: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    salida();
}
Adam Rosenfield
fuente
15
Olvidó llamar a exit () para asegurarse de que el script se cierra después de la redirección. Por lo general, lo envuelvo en una función llamada requireSSL (). Puedo llamar a esto en la parte superior de cualquier página que quiera encriptar.
Jesse Weigert el
31
Cambia el if to be (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")para arreglar avisos PHP.
dave1010
¿Las $_SERVER[]variables no son cambiables / vulnerables a la intervención de los usuarios?
Arian Faurtosh
@ArianFaurtosh fuente?
John
3
@ArianFaurtosh, algunos se extraen de los encabezados de los clientes, como HTTP_X_FORWARDED, y pueden manipularse, pero a otros les gusta HTTPSo SERVER_PORTse configuran directamente desde el servidor web y, por lo general, deben ser seguros.
Mahn
46

Podrías hacerlo con una directiva y mod_rewrite en Apache:

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

Puede hacer que la ubicación sea más inteligente con el tiempo utilizando expresiones regulares si lo desea.

thebigjc
fuente
66
¿Dónde pondrías esto? archivo .htaccess?
1
¿REQUEST_URI no incluye la "cadena de consulta" (como? Page = 1 & id = 41 etc.)? Eso es lo que dice la documentación de Apache ... Entonces, si intento acceder a site.com/index.php?page=1&id=12 , seré redirigido a site.com/index.php
Rolf,
2
Desde la documentación de apache: REQUEST_URI El componente de ruta del URI solicitado, como "/index.html". Esto excluye notablemente la cadena de consulta que está disponible como su propia variable denominada QUERY_STRING. Por lo tanto, deberá agregar QUERY_STRING después de REQUEST_URI
Rolf
2
También debe agregar la pestaña [R] después de eso para que se redirija
Rolf
40

Debe obligar al cliente a solicitar HTTPS siempre con encabezados 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();
}

Tenga en cuenta que HSTS es compatible con la mayoría de los navegadores modernos, pero no es universal. Por lo tanto, la lógica anterior redirige manualmente al usuario independientemente del soporte si terminan en HTTP, y luego establece el encabezado HSTS para que el navegador pueda redirigir más solicitudes del cliente si es posible.

Jacob Swartwood
fuente
Me sorprende que ninguna de las otras respuestas incluya este encabezado, es bastante importante ... ¿alguna dificultad para combinar las dos?
keisar
No ... definitivamente podría establecer ese encabezado de todos modos si desea HTTPS siempre. Es algo redundante configurarlo antes y después de hacer la redirección. También modifiqué mi respuesta anterior para explicar con mayor precisión la compatibilidad.
Jacob Swartwood el
1
(Redacción del comentario original) No noté el requisito específico de "solo una página". HSTS se aplicará a todas las páginas; Mi respuesta es técnicamente incorrecta.
Jacob Swartwood el
44
Para su información, la sección 7.2 del RFC 6797 estándar dice "Un host HSTS NO DEBE incluir el campo de encabezado STS en las respuestas HTTP transmitidas a través del transporte no seguro". así que no es necesario enviarlo cuando la solicitud es http normal, debe ignorarse si el navegador sigue el estándar.
Frank Forte
1
@mark si hay un MITM y su sitio web no tiene este encabezado, puede permitir que una sesión comprendida vaya a http y las personas ingresen sus detalles y probablemente no lo noten y una redirección no ayudará (el hombre en el medio se conectará al sitio a través de https y lo presentará como http). El uso de este encabezado forzará HTTPS en el lado del cliente. Esto es particularmente importante debido a la reciente vulnerabilidad de seguridad WiFi WPA2.
Rudiger
19

Acabo de crear un archivo .htaccess y agregué:

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

Sencillo !

MatHatrik
fuente
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);
}
Jeff
fuente
8

Tenía que hacer algo como esto cuando se ejecuta detrás de un equilibrador de carga. Punta de sombrero 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;
    }
}
2 revoluciones
fuente
6

La forma 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);
}

La forma de Apache mod_rewrite:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Arrendajo
fuente
Prefiero la forma PHP porque hay casos en los que deseo anular el requisito de SSL. Por ejemplo, acceso local a API y cosas como la autoconfiguración de Mozilla Thunderbird, etc.
Jay
El método PHP funciona perfectamente para mí, muy recomendable.
Moxet
5

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

A veces es posible que deba asegurarse de que el usuario esté navegando por su sitio a través de una conexión segura. Una manera fácil de redirigir siempre al usuario a una conexión segura (https: //) se puede lograr con un archivo .htaccess que contenga las siguientes líneas:

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

Tenga en cuenta que .htaccess debe ubicarse en la carpeta principal del sitio web.

En caso de que desee forzar HTTPS para una carpeta en particular, puede usar:

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

El archivo .htaccess debe colocarse en la carpeta donde necesita forzar HTTPS.

itsazzad
fuente
5

Ok .. Ahora hay toneladas de cosas sobre esto ahora, pero nadie realmente completa la pregunta "segura". Para mí es ridículo usar algo inseguro.

A menos que lo use como cebo.

La propagación de $ _SERVER se puede cambiar a voluntad de alguien que sepa cómo hacerlo.

Además, como Sazzad Tushar Khan y thebigjc declararon, también puedes usar httaccess para hacer esto y aquí hay muchas respuestas que lo contienen.

Solo agrega:

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

hasta el final de lo que tienes en tu .httaccess y eso es todo.

Aún así, no estamos tan seguros como posiblemente podamos estar con estas 2 herramientas.

El resto es simple. Si faltan atributos, es decir ...

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

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


También diga que ha actualizado su archivo httaccess y verifica:

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

Hay muchas más variables que puede verificar, es decir ...

HOST_URI (Si hay atributos estáticos al respecto para verificar)

HTTP_USER_AGENT (Misma sesión diferentes valores)

Entonces, todo lo que estoy diciendo es que no te conformes con uno u otro cuando la respuesta está en una combinación.

Para obtener más información sobre la reescritura de httaccess, consulte los documentos-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Algunas pilas aquí -> Fuerce SSL / https usando .htaccess y mod_rewrite
y
obtenga la URL completa del página actual (PHP)
para nombrar una pareja.

JSG
fuente
2
pero ahora me sale el siguiente error: ERR_TOO_MANY_REDIRECTS. ¿Cómo puedo solucionar esto?
Pathros
3

Úselo $_SERVER['HTTPS']para saber si es SSL y, de lo contrario , redirija al lugar correcto.

Y recuerde, la página que muestra el formulario no necesita ser alimentada a través de HTTPS, es la URL de publicación que más lo necesita.

Editar : sí, como se señala a continuación, es mejor tener todo el proceso en HTTPS. Es mucho más tranquilizador: estaba señalando que la publicación es la parte más crítica. Además, debe asegurarse de que las cookies estén configuradas para ser seguras, por lo que solo se enviarán a través de SSL. La solución mod_rewrite también es muy ingeniosa, la he usado para asegurar muchas aplicaciones en mi propio sitio web.

DGM
fuente
Es cierto que el formulario en sí no necesita ser https, aunque es una buena idea para la mayoría de las personas que no lo saben. Si están a punto de enviar el formulario y notan que el ícono del candado no está allí, podrían suponer erróneamente que el formulario es inseguro.
Graeme Perrow
1
@Graeme: además, nadie puede estar seguro de que el formulario se enviará a través de https. El formulario completo (que se muestra a través de http) puede ser falso, y se envía a un sitio desconocido o de texto sin formato http. Https no se trata solo de cifrado, sino que también autentica el servidor.
Olaf Kock
3

uso 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]
siavash bagheri
fuente
1

No mezcle HTTP y HTTPS en la misma página. Si tiene una página de formulario que se sirve a través de HTTP, voy a estar nervioso por el envío de datos: no puedo ver si el envío supera HTTPS o HTTP sin hacer un código fuente de vista y buscarlo.

Servir el formulario a través de HTTPS junto con el enlace de envío no es un gran cambio para la ventaja.

JBB
fuente
1

Si usa Apache o algo así como LiteSpeed, que admite archivos .htaccess, puede hacer lo siguiente. Si aún no tiene un archivo .htaccess, debe crear un nuevo archivo .htaccess en su directorio raíz (generalmente donde se encuentra su index.php). Ahora agregue estas líneas como las primeras reglas de reescritura en su .htaccess:

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

Solo necesita la instrucción "RewriteEngine On" una vez en su .htaccess para todas las reglas de reescritura, así que si ya la tiene, simplemente copie la segunda y tercera línea.

Espero que esto ayude.

Antonio
fuente
Esto es lo que funcionó para mí y lo que estoy usando en mis propios scripts en un Marco similar a Zend 2: no entiendo el voto negativo.
Antonio
¿Quizás te rechazaron porque la respuesta es prácticamente la misma que esta de @MatHatrik que se publicó hace más de un año?
marchita el
1

Usar esto NO es suficiente:

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

Si tiene contenido http (como una fuente de imagen http externa), el navegador detectará una posible amenaza. Así que asegúrese de que todos sus ref y src dentro de su código sean https

webmaster bourax
fuente
1

He pasado por muchas soluciones comprobando el estado de $ _SERVER [HTTPS] pero parece que no es confiable porque a veces no se establece o se activa, desactiva, etc., lo que hace que el script redirija al bucle interno.

Aquí está la solución más confiable si su servidor admite $ _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;
}

Tenga en cuenta que dependiendo de su instalación, su servidor podría no ser compatible con $ _SERVER [SCRIPT_URI], pero si lo hace, este es el mejor script para usar.

Puede verificar aquí: ¿Por qué algunas instalaciones PHP tienen $ _SERVER ['SCRIPT_URI'] y otras no?

Tarik
fuente
1

Para aquellos que usan IIS, agregar esta línea en web.config ayudará:

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

Un archivo de ejemplo 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>
Tschallacka
fuente
La pregunta se refiere específicamente a Apache, no a IIS.
Quentin
1
A) no está etiquetado apache. Apache se menciona entre comillas. B) es una pregunta genérica que no tiene nada que ver con apache en general. Es aplicable a múltiples servidores web compatibles con php
Tschallacka
0

No deberías por razones de seguridad. Especialmente si las cookies están en juego aquí. Te deja completamente abierto a ataques de repetición basados ​​en cookies.

De cualquier manera, debe usar las reglas de control de Apache para ajustarlo.

Luego puede probar si HTTPS está habilitado y redirigir según sea necesario donde sea necesario.

Debe redirigir a la página de pago solo con un FORM POST (no get), y los accesos a la página sin un POST deben dirigirse nuevamente a las otras páginas. (Esto atrapará a las personas simplemente saltando en caliente).

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

Es un buen lugar para comenzar, disculpas por no proporcionar más. Pero realmente deberías empujar todo a través de SSL.

Es sobreprotector, pero al menos tienes menos preocupaciones.

Kent Fredric
fuente
0

tal vez esto pueda ayudar, así es como lo hice para mi sitio web, funciona de maravilla:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

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

Si quieres usar PHP para hacer esto, esta manera me funcionó muy bien:


<?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;
}
?>

Comprueba la variable HTTPS en la matriz superglobal $ _SERVER para ver si es igual a "on". Si la variable no es igual a on.

squiremaldoon
fuente
-1

He usado este script y funciona bien a través del sitio.

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

Así de fácil.

Deletrear
fuente