Mostrando entradas con la etiqueta cookies. Mostrar todas las entradas
Mostrando entradas con la etiqueta cookies. Mostrar todas las entradas

domingo, 18 de enero de 2015

[Parte 2] Web Scraping

HTTP: un resumen rapido

La primera tarea de una aplicacion de web scraping es la de recuperar documentos que contienen informacion para ser extraida. Para los sitios webs que constan de varias paginas o que requieren la mantencion de la sesion entre solicitudes o informacion de autenticacion, un cierto nivel de ingieneria inversa es a menudo necesaria para desarrollar una aplicacion web de web scraping correspondiente. Este tipo de exploracion requiere un buen conocimiento del protocolo de transferencia de hipertexto o HTTP el protocolo que da poder a la internet.


HTTP es un protocolo  de solicitud/respuesta concebido como un protocolo de comunicaciones entre clientes y servidor web.  Los clientes son programas o scripts que envian peticiones a los servidores, algunos ejemplo de clientes se incluyen los navegadores, tal como firefox, internet explorer o crawlers, como los utilizados por Yahoo!, Google y web scrapers. 

Siempre que su navegador web obtiene un archivo (una pagina, una foto, etc) de un servidor web, lo hace utilizando HTTP. Esa solicitud que su ordenador envia al servidor web contiene todo tipo de informacion interesante. HTTP define metodos (aveces denominados verbs) para indicar la accion deseada a realizar por el servidor web en el recurso solicitado. Lo que este recurso representa, ya sea datos o datos preexistentes que son generados dinamicamente, depende de la aplicacion del servidor. A menudo, el recurso corresponde a un archivo o salida de un ejecutable que reside en el servidor. Una peticion HTTP consta de un metodo de peticion, un URL de solicitud, los campos de cabecera, y un cuerpo. 

HTTP 1.1 define los siguientes metodos de peticion, de los cuales solo dos metodos de peticion seran de interes para nosotros - GET y POST.

GET: Recupera el recurso identificado por la URL de la solicitud.
HEAD: Devuelve las cabeceras identificadas por la URL de la solicitud. 
POST: Envia los datos de longitud ilimitada en el servidor web.
PUT: Almacena un recurso bajo el URL de la solicitud.
DELETE: Elimina el recurso identificado por la URL de la solicitud.
OPTIONS: Devuelve los metodos HTTP que soporta el servidor.
TRACE: Devuelve los campos de cabecera que han sido enviados con la peticion TRACE.

Peticiones GET

Comencemos con una simple peticion HTTP GET, una pagina que devuelva el index ficticio del tal pagina:

el sitio es - ejemplo.com. La siguiente es la peticion que su navegador envia al servidor para recuperar el archivo index:

GET /index.html HTTP 1.1
Host: www.ejemplo.com

Los componentes individuales de la solicitud anterior se detallan a continuacion:

GET es el metodo o la operacion que debe aplicarse sobre el recurso del servidor. Piense en ello como un verbo en una frase, una accion que desea realizar en algo.

index.html es el identificador uniforme de recursos o URI. Proporciona un punto unico de referencia para el recurso, el objeto o destino de la operacion. 

HTTP 1.1 especifica la version del protocolo HTTP en uso por el cliente.

El metodo, URI, y la especificacion HTTP juntos conforman la linea de peticion. 

En un unico encabezado Host y su valor asociado www.ejemplo.com siguen la linea de la peticion.

Mas pares de cabecera : Valor pueden seguir.

Basado en el recurso, el valor de la cabecera Host y el protocolo en uso http://www.ejemplo.com/index, Es la url completa del recurso solicitado resultante. 

La mayoria de las solicitudes de las cabeceras de los sitios son sin embargo mas complejas que contienen muchos campos adicionales.

Puede utilizar herramientas como Firebug, Live HTTP Headers Plugin de firefox, para comprobar las cabeceras que son enviadas por el navegador y las respuestas correspondientes recibidas desde el servidor. Un encabezado que ha sido capturado con Live HTTP Headers para el sitio yahoo.com se muestra a continuacion. Como se puede ver hay muchos campos adicionales junto con la accion GET.

GET /?p=us HTTP/1.1
Host: in.yahoo.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: B=1mjov258ke&b=4&d=g2uJ6p15tCRXz. (truncated)
Cache-Control: max-age=0


Cadenas de consulta

Otra disposicion de URL es un mecanismo que se llama cadena de consulta (query string), que se utiliza para pasar parametros de la peticion a aplicaciones web. A continuacion se muestra una peticion GET que incluye una cadena de consulta se utiliza para solicitar una determinada pagina de ejemplo.com.

GET /index.php?page=3&limit=10
Host: ejemplo.com


Hay algunos puntos notables que tenemos que tomar en cuenta en la URL:

Un signo de interrogacion indica el final de la ruta del recurso y de ahi comienza la cadena de consulta.

La cadena de consulta se compone de pares clave-valor, donde cada pareja esta separada por un signo (&).

Las claves y los valores estan separados por un signo igual. Las cadenas de consulta no son especificas de operaciones GET y pueden ser utilizadas en otras operaciones como POST, que miraremos a continuacion.


Peticiones POST

La adicion del metodo POST es quizas una de las mas grandes mejoras del HTTP especificadas hasta la fecha. Este metodo puede ser acreditado con la transicion de la web para una verdadera plataforma de desarrollo de aplicaciones web interactivas.

Cuando se utiliza un navegador web como cliente, esto mas a menudo se utiliza en formularios HTML. Si un formulario HTML especifica un metodo POST, el navegador enviara los datos de los campos del formulario en una peticion POST en lugar de una peticion GET.

Una gran diferencia entre una solicitud GET y una solicitud POST es que el POST incluye un cuerpo siguiendo los encabezados de solicitud para contener los datos que se presentaran. POST pretende añadir o modificar los datos expuestos por la aplicacion, un resultado posible es que se crea un nuevo recurso o se cambia un recurso existente.

Sintaxis de URL

La URL proporciona un medio de localizar cualquier recurso de internet, pero estos recursos pueden accederse por diferentes esquemas (Por ejemplo: HTTP, FTP, SMTP), y la sintaxis de la URL varia de esquema a esquema. A pesar de las diferencias entre varios esquemas, las URLS se adhieren a una sintaxis general de URL, y existe una superposicion significativa en el estilo y la sintaxis entre distintos esquemas de URL. 

Todos los mensajes HTTP, con la posible excepcion del contenido del mensjae, utilizan el conjunto de caracteres ISO-8859-1 (ISO-Latin). Una solicitud HTTP puede incluir un encabezado de peticion Accept-Encoding que identifica codificaciones de caracteres alternativos que no sean aceptables para el contenido de la respuesta HTTP. La mayoria de los esquemas HTTP basan su sintaxis en este formato general de nueve partes:

<scheme>://<user>:<pass>@<host>:<port>/<path>?<query>#<frag>

La mayoria de las URLs no contienen todos estos componentes. Las tres partes mas importantes de una URL son scheme, host y path (esquema, servidor y ruta). Las distintas partes se explican a continuacion.

 

+------------+-----------------------------------------------------------------------+----------------------+
| Componente | Descripcion                                                           | Valor por defecto    |
+------------+-----------------------------------------------------------------------+----------------------+
| scheme     | Protocolo utilizado para a obtener un recurso                         | Ninguno              |
+------------+-----------------------------------------------------------------------+----------------------+
| user       | El nombre de usuario, algunos scheme requieren                        | anonymous            |
|            | acceso anonimo para acceder a un recurso                              |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| pass       | La contraseña se puede incluir despues del nombre                     | <correo electronico> |
|            | de usuario, separados por dos puntos(:)                               |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| host       | El nombre del servidor o direccion IP que aloja                       | Ninguno              |
|            | el recurso                                                            |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| port       | El numero de puerto en el que el servidor que aloja                   | Especifico al scheme |
|            | el recurso esta escuchando. Muchos schemes tienen                     |                      |
|            | numeros de puerto por defecto (el numero de puerto                    |                      |
|            | predeterminado para HTTP es el 80)                                    |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| path       | El nombre local para el recurso en el servidor, separado              | Ninguno              |
|            | por los componentes de la URL anteriores por una                      |                      |
|            | barra (/), la sintaxis del componente path  es servidor y             |                      |
|            | especifico al scheme.                                                 |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| query      | Utilizado por algunos schemes para pasar parametros a                 | Ninguno              |
|            | las aplicaciones activas (como base de datos, bulletin boards,        |                      |
|            | motores de busqueda y otros portales de internet). No hay             |                      |
|            | un formato comun para el contenido del componente de query.           |                      |
|            | Esta separado por el resto de la URL por el caracter "?".             |                      |
+------------+-----------------------------------------------------------------------+----------------------+
| frag       | Un nombre para una pieza o parte del recurso. El campo frag           |                      |
|            | no se pasa al servidor cuando hace referencia al objeto; es utilizado | Ninguno              |
|            | internamente por el cliente. Esta separado del resto de la URL        |                      |
|            | por el caracter "#".                                                  |                      |
+------------+-----------------------------------------------------------------------+----------------------+

Gestion de estados HTTP y Cookies


La tarea principal de un servidor web es satisfacer cada solicitud HTTP recibida del cliente. Todo lo que el servidor web considera al generar la respuesta HTTP esta incluido en la peticion. Si dos clientes web completamente diferentes envian solicitudes HTTP identicas al mismo servidor web, el servidor web usara el mismo metodo para generar la respuesta, que puede incluir la ejecucion de algunas aplicaciones del lado del servidor. 

Los sitios webs modernos sin embargo tienen que proporcionar un toque personal a los clientes. Ellos quieren saber mas acerca de los usuarios sobre los otros extremos de las conexiones y poder hacer un seguimiento de los usuarios mientras navegan. Las transacciones HTTP son sin estado. Cada peticion/respuesta ocurre en el aislamiento. Muchos sitios web quieren construir un estado gradual a medida que interactuan con el sitio (por ejemplo, llenar un carrito de compras en linea). Para ello, los sitios webs necesitan una manera de distinguir una transaccion HTTP de otra. 

Las cookies son la mejor manera de identificar los diferentes usuarios y permitir sesiones persistentes. Las cookies se desarrollaron por primera vez por Netscape pero ahora son compatibles con todos los navegadores principales. Puede clasificar las cookies generalmente en dos tipos: las cookies de sesion y las cookies persistentes. Una cookie de sesion es una cookie temporal que mantiene un registro de configuracion y las preferencias de como un usuario navega en el sitio. Una cookie de sesion se elimina cuando el usuario cierra el navegador. Las cookies persistentes pueden vivir mas tiempo; se almacenan en el disco y sobreviven despues de salir del navegador e incluso reiniciar el equipo. Las cookies persistentes a menudo se utilizan para mantener un perfil de configuracion o un nombre de usuario para un sitio que un usuario visita periodicamente. La unica diferencia entre las cookies de sesion y las cookies persistentes es cuando caducan. 

Ahora que hemos tenido un breve resumen de HTTP, podemos proceder a lo que vamos - web scraping.! En la proxima parte.

jueves, 18 de septiembre de 2014

[Parte 7] PHP

Cookies y Sesiones

Http es un protocolo sin estado por lo cual no puede identificar que usuario es cual, ni darle seguimiento. En PHP existen dos herramientas para este proposito las cookies y las sesiones, con las cuales podemos identificar al usuario y darle seguimiento.

Las diferencias entre las cookies y las sesiones es que las cookies se guardan en el navegador del cliente y las sesiones se guardan en el servidor. Las sesiones son generalmente mas seguras que las cookies y pueden almacenar mucha mas informacion. Ambas son tecnologias faciles de utilizar usando PHP para demostrarlo crearemos un sistema de inicio de sesion.

Crear una pagina de inicio de sesion

El proceso de inicio de sesion envuelve algunos componentes:

* Un formulario envia la informacion de inicio de sesion
* Una rutina de validacion se asegura de que los datos necesarios se han enviado
* Una consulta a la base de datos compara que la informacion enviada sea igual a la informacion almacenada en la base de datos
* Las cookies o sesiones son almacenadas reflejando un inicio de sesion correcto

Subsecuente a esto las paginas pueden tener una restriccion por la cual solo se mostraran a usuarios que hayan iniciado sesion, en las cuales pueden agregar caracteristicas especiales.

Crearemos varios archivos rompiendo la logica y haciendola mas facil para que nuestro codigo sea mas facil de escribir y leer y tenga menos redundancia. El script va contener la pagina de inicio de sesion, la cabecera, el reporte de errores, el formulario y el pie de pagina.

Creamos la pagina de inicio de sesion:

login _page.inc.php



<?php
 # Esta pagina imprime cualquier error y esta asociado con la pagina de inicio
 # Y crea la pagina de inicio de sesion entera, incluyendo el formulario.

 # incluir la cabecera
 $page_title = 'Inicio de sesion';
 include('includes/header.html');

 # Imprime cualquier mensaje de error, si existe:
 if (isset($errors) && !empty($errors)) {
   echo '<h1>Error!</h1>
   <p class="error">Los siguientes errores han ocurrido:<br />';
   foreach ($errors as $msg) {
    echo "- $msg<br />\n";
   }
   echo "</p><p>Por favor intente de nuevo.</p>";
  } 

  # Mostrar el formulario:
?>
<h1>Iniciar sesion</h1>
<form action="login.php" method="post">
 <p>Correo electronico: <input type="text" name="email" size="20" maxlength="60" /></p>
 <p>Clave: <input type="password" name="pass" size="20" maxlength="20" /></p>
 <p><input type="submit" name="submit" value="Iniciar sesion!" /></p>
</form>
<?php 
 include('includes/footer.html');
?>


1.- Incluimos el header.html y el titulo al inicio (el header.html lo veremos mas adelante)

2.- Si ocurre algun error imprimimos el error recorriendolo con foreach
3.- Mostramos el formulario
4.- Incluimos footer.html

Nota: estamos utilizando .inc.php para los archivos que iran dentro de otros archivos (seran incluidos), y tambien crearemos una carpeta llamada includes/ donde se encontraran cada uno de ellos.

En el proceso de la creacion de la pagina de inicio de sesion, hay 2 cosas que se repiten, las cuales son :

- Verificacion de correo electronico y clave en la base de datos
- Redirecciones

Es por eso que para comenzar crearemos un script php con el cual evitaremos la redundancia del codigo, nuestro script se llamara login_functions.inc.php:


<?php
 # Esta pagina define dos funciones usadas para el inicio y cierre de sesion
 /*
  Esta funcion determina la URL absoluta y redirige al usuario
  * Esta funcion toma un argumento para que sea redirigido
  * El argumento por defecto es index.php
 */
 function redirect_user ($page = 'index.php'){
  // comienza definiendo la url
  // la url es http:// agregando el nombre del host y el directorio actual
  $url = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);

  // remueve cualquier barra invertida
  $url = rtrim($url,'/\\');

  // Agrega la pagina:
  $url .= '/' . $page;

  // Redirige al usuario:

  header("Location: $url");
  exit(); // Quita el script
 } // Fin de la funcion redirect_user()

 /*
  Esta funcion valida los datos del formulario (el correo electronico y la clave).
  * Si ambos estan presentes, la base de datos es consultada
  * La funcion requiere coneccion a la base de datos
  * La funcion devuelve un arrat de informacion, incluyendo:
   -  Una variable TRUE/FALSE que indica si fue correcto
   - Un array para los errores o resultados de la base de datos
 */
 function check_login($dbc,$email='',$pass=''){
  $errors = array(); // Inicializamos un array de errores

  // Validamos el correo electronico
  if (empty($email)) {
   $errors[] = 'Olvidastes poner el correo electronico';
  }else{
   $e = mysqli_real_escape_string($dbc,trim($email));
  }
  // Validamos la clave
  if (empty($pass)) {
   $errors[] = 'Olvidastes poner la clave';
  }else{
   $p = mysqli_real_escape_string($dbc,trim($pass));
  }

  if(empty($errors)){
   // Si todo esta bien
   // Devolvemos el id de usuario, el primer nombre de usuario con la combinacion de
   // correo electronico/clave

   $q = "SELECT user_id, first_name FROM login WHERE email='$e' AND pass=SHA1('$p')";
   $r = @mysqli_query($dbc,$q);
   // Correr la consulta
   // verificamos el resultado

   if (mysqli_num_rows($r) == 1) {
    // devolvemos los registros
    $row = mysqli_fetch_array($r,MYSQLI_ASSOC);
    // devuelve true y los registros:
    return array(true,$row);

   }else{ // No coincide
    $errors[] = 'El correo electronico y la clave no coinciden con el archivo';
   }
  } // final de si empty($errors)
  // devuelve falso y los errores:
  return array(false,$errors);
 } // final de la funcion check_login().
?>

Explicando un poco el codigo:

La primera funcion:

1.- Creamos una funcion redirect_user() con la cual podemos redirigir a los usuarios a la pagina que le demos como parametro, pero por defecto es index.php

2.- Creamos la variable $url la cual contiene, primero agregamos el http:// por si nos encontramos en localhost, despues el host seria la url actual, al final agregamos el directorio actual del archivo donde nos encontramos con PHP _SELF.

3.- Removemos las barras

4.- Agregamos la pagina que le dimos para redirigir a la variable $url

5.- Redirigimos a la $url final con header()

6.- Paramos el script con exit()

La segunda funcion:

1.- Se crea la funcion check_login() que lleva tres argumentos, la coneccion a la base de datos, el correo electronico (este es opcional) y la clave (tambien es opcional).

2.- Validamos el correo y la clave, si algun problema ocurre mostrara los errores.

3.- Verificamos que el correo y la clave sea correcta esto lo hacemos de manera que si arroja 1 resultado significa que lo es. Luego devolvemos el resultado en un array como verdadero.

4.- Si el resultado no es correcto devolvemos el array en falso y el inicio de sesion fallará.


Usando Cookies

Las cookies es una forma de que el servidor guarde informacion en la maquina del usuario. Esta es una forma de que el servidor recuerde o siga al usuario. Piensa que la cookie es como un identificador personal, en la cual tu llamas al servidor con tu nombre y el te da una identificacion (pasé o pulsera). Entonces con eso ya sabe a quien se esta refiriendo. En este apartado veremos como establecer una cookie, devolver informacion almacenada por la cookie, alterar la configuracion de la cookie, y tambien eliminar la cookie.


Establecer cookies

La cosa mas importante para aprender acerca de las cookies es que ellas son enviadas desde el servidor hasta el cliente antes que cualquier otra informacion. Ya que si envias una cookie despues esto causaria un error. Incluso si es un espacio en blanco.

Las cookies se envian con la funcion setcookie():

setcookie('nombre','valor');

setcookie('nombre','arthusu');


Como ves esto enviaria una cookie al navegador de nombre le pusimos nombre (valga la redundancia) y de valor le pusimos arthusu. De igual manera si quisieramos agregar mas cookies solamente las seguimos estableciendo con la misma funcion:

setcookie('ID',250);
setcookie('email','arthusu@gmail.com');

Es recomendable no utilizar espacios ni puntuaciones en el nombre establecido.

Veamos como establecer una cookie utilizando todo el codigo del ejemplo anterior...

login.php


<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:
  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   setcookie('user_id',$data['user_id']);
   setcookie('first_name',$data['first_name']);

   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>


Explicando el codigo anterior:

1.- Creamos la pagina login.php que requiere de los dos archivos que creamos anteriormente para poder funcionar.

2.- Verificamos que el formulario haya sido enviado y si es asi, entonces agregamos dos script el de las funciones por que lo necesitaremos y el de la coneccion a la base de datos, de forma que verificaremos el inicio de sesion y ademas enviaremos las cookies.

Antes de seguir agregare el codigo de los demas archivos que nos faltan para poder seguir trabajando con nuestros scripts:

1.- Vamos a crear la base de datos la cual llamaremos "usuarios", esto lo hacemos ingresando a phpmyadmin:
http://localhost/phpmyadmin/

2.- Donde dice crear nueva base de datos, colocamos y nombre y le damos crear.

3.- Creamos una nueva tabla dentro que se va llamar login, en la cual agregaremos 5 campos los cuales seran:

* user_id (int not null autoincrement primary key)
* first_name (varchar 70 not null)
* last_name (varchar 70 not null)
* email (varchar 20 not null)
* password (varchar 40 not null)



4.- Insertamos un nuevo registro dando clic en insertar, ahi llenamos los datos, en mi caso puse lo siguiente :

user_ id : 1first_name:  arthusulast _name:  xdemail: arthusu@gmail.compassword: utilize la funcion sha1 y puse clave 123

El archivo php para la coneccion a la base de datos la tenemos fuera del directorio publico de manera que nadie mas lo podra ver a menos que tengan permisos:

mysqli_connect.php


<?php
 
 // Este archivo contiene acceso a la informacion de la base de datos
 // Esta archivo tambien establece coneccion con MySQL
 // selecciona la base de datos, y establece una codificacion

 
 // establecemos la informacion en constantes:
 define('DB_USER', 'tusuario');
 define('DB_PASSWORD', 'tucontraseña');
 define('DB_HOST', 'localhost');
 define('DB_NAME', 'usuarios');

 // creamos una coneccion:
 $dbc = @mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) OR die('No se pudo conectar a MySQL: '.mysqli_connect_error());

 // esablecemos la codificacion:
 mysqli_set_charset($dbc,'utf-8');
?>

En el codigo del archivo anterior definimos en constantes los datos para una coneccion, con mysqli_connect() establecemos una coneccion con la base de datos con mysqli_set_charset() establecemos una codificacion para la base de datos.


El archivo header y footer son los siguientes: 

header.html


<!DOCTYPE html>
<html>
<head>
 <title><?php echo $page_title; ?></title>
 <link rel="stylesheet" href="includes/styles.css" type="text/css" media="screen" />
 <meta http-equiv="content-type" content="text/html;charset=utf8" />
</head>
<body>
 <header>
  <h1>Tu sitio web</h1>
  <h2>Tu slogan...</h2>
 </header>
 <nav>
  <ul>
   <li><a href="#">Inicio</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
  </ul>
 </nav>



footer.html
 <footer>
  <p><b>Copyright 2014</b></p>
 </footer>
</body>
</html>


Ya terminado nuestro codigo para continuar con la explicacion con el codigo de las cookies, por cierto el estilo no se ha agregado, esto lo veremos mas adelante...

3.- Validamos los datos enviando estableciendo la coneccion a la base de datos, y los datos que se pasan que estan en el formulario. Como en la funcion check_login() devolvemos un array entonces lo recojemos en variables utilizando la funcion list(). De esta manera sabremos si el login es correcto o no, y asi poder utilizar los datos.

4.- Si el inicio de sesion es correcto, establecemos las cookies user_id y first_name para ello utilizaremos los datos de la base de datos arrojados por la funcion check_login(). Y haremos una redireccion a un archivo que todavia no existe llamado loggedin.php

5.- Si el inicio de sesion no es correcto arrojamos los errores.

6.- Cerramos la base de datos utilizando mysqli_close(). Incluimos el archivo que contiene nuestro formulario.


De todas formas aunque el archivo loggedin.php no exista en los navegadores podemos ver como las cookies se han establecido correctamente:



Algunas notas importantes sobre las cookies es que estan limitadas a 4KB y que cada navegador recuerda un numero limitado de cookies para cada sitio. Los mayoria de los navegadores actuales soportan hasta 50 cookies por sitio. La funcion setcookie() es una de las pocas funciones en php que podria tener diferentes resultados en diferentes navegadores, desde cada navegador las cookies son tratadas de diferente manera. Para estar seguros podemos probar nuestro sitio web en diferentes navegadores y diferentes plataformas.

Accediendo a las cookies

Para devolver una valor desde la cookie, tu solo debes referirte al array superglobal $_COOKIE, usando apropiadamente el nombre de la cookie como clave, por ejemplo para devolver el valor de una cookie establecida:


setcookie('username','arthusu');

tu puedes referirte a ella como $_COOKIE['username']




<?php
 // el usuario es redirigido aqui desde login.php
 
 // si la cookie no esta presente, redirigimos al usuario
 if (!isset($_COOKIE['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }

 // establecemos el titulo de la pagina en la cabecera html
 $page_title = 'Sesion iniciada';
 include('includes/header.html');

 // mostramos un mensaje personalizado

 echo "<h1>Sesion iniciada correctamente</h1>
 <p>Tu sesion esta iniciada como, {$_COOKIE['first_name']}!
 <a href=\"logout.php\">Salir</a></p>";

 include('includes/footer.html');
?>

1.- verificamos si existe la cookie, en caso de no existir redirigimos al inicio de la pagina. Antes para ello es necesario agregar donde se encuentran las funciones para llamar a la pagina y redirigir.

2.- Si el inicio de sesion es correcto, creamos una variable con el titulo e incluimos el header.html el cual contiene un codigo para nuestra variable. Despues de eso mostramos un mensaje de bienvenida con el nombre del usuario haciendo referencia a el con el array superglobal $_COOKIE.

3.- Creamos un enlace de Salida (logout.php) que mas adelante veremos como crear.

Estableciendo parametros a las cookies

Nosotros solo hemos pasado el nombre y el valor como parametros en la funcion setcookie(), pero hay otros argumentos disponibles que puede tomar y cada uno altera la definicion de la cookie.


setcookie(nombre,valor,expiracion,ruta,servidor,secure,httponly)

El argumento expiracion es usado para establecer el tiempo de duracion para que una cookie exista. Este tiempo se especifica en segundos. Si este valor se deja en 0 no se especifica nada y la cookie es eliminada hasta que el navegador es cerrado. Podremos agregar un tiempo de expiracion especifico utilizando la funcion time(), por ejemplo si quisieramos agregar 30 minutos en tiempo de expiracion de la cookie seria de la siguiente manera:


setcookie(nombre,valor,time()+1800);

Donde 1800 es el tiempo en segundos.
La ruta y el servidor son usados para limitar la cookie a una ruta especificada o servidor, por ejemplo: www.ejemplo.com o 192.168.0.1. Y en la ruta por ejemplo si tu quieres que esa cookie solo exista en la ruta del administrador admin/ se la especificas ahi mismo.
Si nosotros establecemos en la ruta / se podra usar la cookie en todo el sitio, y si ponemos en el servidor .ejemplo.com se puede usar la cookie en todo el sitio y subdominios.

El valor secure dice que la cookie solo puede ser enviada por conecciones seguras https. Con 1 la activamos y con 0 dejamos la coneccion estandar. En caso de que tu sitio tenga activado https puedes activar para que las cookies sean seguras estableciendo el valor 1.


setcookie(nombre,valor,expiracion,ruta,servidor,1);
En la version de php 5.2 fue agregado el argumento httponly. Este es un valor Booleano que es usado para crear una cookie accesible mediante HTTP (y HTTPS). Reforzando la restriccion de la cookie haciendola mas segura (ante intentos de hackers) pero no es soportada por todos los navegadores. 


setcookie(nombre,valor,expiracion,ruta,servidor,secure,TRUE);

Como la mayoria de las funciones en setcookie() para no establecer ninguna valor a alguno de los parametros solo es necesario utilizar NULL, 0 o una cadena vacia (No usar FALSE). La expiracion y secure ambos son valores enteros por lo cuales no deben ir entre comillas. 

Vamos a demostrar todo lo visto en el script anterior modificando la cookie haciendo que expire en 1 hora.

Abrimos el archivo login.php y le agregamos lo siguiente:


setcookie('user_id',$data['user_id'],time()+3600,'/','',0,0);setcookie('first_name',$data['first_name'],time()+3600,'/','',0,0);




<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {

  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:

  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   setcookie('user_id',$data['user_id'],time()+3600,'/','',0,0);
   setcookie('first_name',$data['first_name'],time()+3600,'/','',0,0);

   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>


Para sacar los segundos es tan facil como multiplicar 60 minutos que es una hora por 60 segundos que es 1 minuto.


Eliminar las cookies

Lo ultimo para terminar de saber como se usan las cookies es eliminar una. Ya sabemos que hay cookies que tienen un tiempo de expiracion pero incluso si tu quisieras simplemente salir de alguna pagina y que tu sesion ya no este iniciada por alguna razon podrias cerrar tu sesion eliminado la cookie.

Para eliminar la cookie solo es necesario el nombre, el valor dejarlo vacio y el tiempo de expiracion ponerlo hacia atras el tiempo que le hayas dado. Un ejemplo para eliminar la cookie first_name:


setcookie('first_name','',time()-3600);
Para que todo esto quede mas claro vamos a crear nuestra pagina de logout.php:



<?php
 // esta pagina deja al usuario cerrar sesion
 // si la cookie no esta presente, redirige al usuario:

 if (!isset($_COOKIE['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }else{
  // Eliminamos las cookies:
  setcookie('user_id','',time()-3600,'/','',0,0);
  setcookie('first_name','',time()-3600,'/','',0,0);
 }
 // Establecemos un titulo a la pagina
 $page_title = 'Cerrar sesion';
 include('includes/header.html');

 // Imprimimos un mensaje personalizado

 echo "<h1>Cierre de sesion!</h1>
 <p>Tu cesion ha sido cerrada correctamente, {$_COOKIE['first_name']}</p>";

 include('includes/footer.html');
?>


Usando sesiones

Otro metodo para crear datos disponibles en multiples paginas de un sitio web es utilizar sesiones. La premisa de una sesion es que los datos son almacenados en el servidor, no en el navegador web, y el identificador de sesion es usado para identificar a un usuario en particular (datos de sesion). Este identificador de sesion es almacenado en el navegador comunmente cuando utilizamos cookies, pero los datos son sensibles, como el ID de usuario, el nombre y demas, por eso los datos siempre deben de mantenerse en el servidor.

La pregunta surge aqui: ¿para que usamos sesiones si podemos usar cookies y funcionan correctamente? primero que todo, las sesiones son mas seguras al almacenar los datos en el servidor,y no continua enviando atras y adelante entre servidor y cliente. En segunda tu puedes guardar mas datos en las sesiones. En tercera algunos usuarios rechazan las cookies o simplemente las mantienen apagadas. Mientras que las sesiones estan diseñadas para trabajar con cookies pueden funcionar sin ellas, tambien.

Para demostrar las sesiones y compararlas con las cookies, reescribiremos los scripts creados anteriormente...

Estableciendo sesiones

La mas importante regla respecto a las sesiones es que cada pagina que vayan a llamarlas deben usar la funcion session_start() al comienzo. Esta funcion es llamada en PHP ya sea cuando comienzas una nueva sesion o accedes a una existente. Esta funcion debe ser llamada antes que cualquier cosa sea enviada al navegador.
La primera vez que esta funcion es usada, session_start() intentara enviar una cookie con el nombre PHPSESSID (nombre por defecto de una sesion) y un valor parecido al este 7d9d0e1d7a8e37f6feb9967ac0a5b445 (32 letras hexadecimales, ID de sesion). El por que de este intento para enviar la cookie, session_start() es enviada antes que cualquier dato sea enviado al naveador web, hasta ese caso nosotros podemos usar las funciones setcookie() y header().

Incluso si la sesion ya ha comenzado, los valores pueden ser registrados para la sesion usando la sintaxis normal del array, usando el array superglobal $_SESSION.

1.- abrimos el archivo login.php y reemplazamos las lineas de setcookie() por el siguiente codigo:

session_start();
$_SESSION['user_id'] = $data['user_id'];
$_SESSION['first_name'] = $data['first_name'];
El primer paso para comenzar la sesion. Es que no debe de haber ninguna declaracion echo, inclusion de archivos HTML o espacios en blanco. Para que la funcion session_start() este segura, tambien podriamos ponerla al inicio de todo el script, nuestro array $_SESSION tiene dos pares de claves con sus valores, first_name y user_id.


<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {

  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:

  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   session_start();
   $_SESSION['user_id'] = $data['user_id'];
   $_SESSION['first_name'] = $data['first_name'];
   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>

Obviamente el script loggedin.php debe ser modificado ya que esta esperando la precencia de una cookie.

Tips:

Puedes establecer session.auto_start a 1 en el archivo php.ini de esta manera no es necesario agregar session_start() en cada pagina. Aunque esto tambien hace que el servidor este enviando sesion nueva cada vez y solo debe utilizarse cuando sea realmente necesario.



Accediendo a las sesiones

Incluso las sesiones que ya han sido creadas y las variables que ya han sido registradas, tu puedes acceder desde otros scripts a estas variables, esto lo podemos hacer con cada script iniciando la sesion con session_start().

Esta funcion nos da acceso a la sesion anteriormente almacenada (puede leer el PHPSESSID almacenado en la cookie) o crear una nueva sesion si no esta creada. Comprendiendo que si el ID de sesion no es encontrado y un nuevo ID de sesion es generado, ninguno de los datos almacenados en el ID de sesion viejo estaran disponibles. Lo mencionado aqui puede causarte problemas con sesiones, para verificar el valor de el ID de la sesion podemos verlo en una pagina con el paso a debugear.

Asumiendo que no tienes problemas con la sesion, nos referimos a la variable de la sesion, usando $_SESSION['var'], tu podrias referirte a cualquier otro array. 

1.- abrimos el archivo loggedin.php y agregamos al inicio session_start() que debe ser llamada antes que header.html.

2.- reemplazamos $_COOKIE por $_SESSION y guardamos el archivo.






<?php
 // iniciamos la sesion
 session_start();
 // el usuario es redirigido aqui desde login.php
 
 // si la cookie no esta presente, redirigimos al usuario
 if (!isset($_SESSION['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }

 // establecemos el titulo de la pagina en la cabecera html
 $page_title = 'Sesion iniciada';
 include('includes/header.html');

 // mostramos un mensaje personalizado

 echo "<h1>Sesion iniciada correctamente</h1>
 <p>Tu sesion esta iniciada como, {$_SESSION['first_name']}!
 <a href=\"logout.php\">Salir</a></p>";

 include('includes/footer.html');
?>

Tips:

Recuerda que como ya dijimos, si en tu aplicacion no ves los datos de sesion en otra pagina, esto puede ser por que se ha creado una nueva sesion en otra pagina. Para verificar esto podemos comprobar el ID de sesion (mirando los ultimos caracteres comprobando si son iguales) tambien puedes ver el ID de sesion utilizando la funcion session_id():

echo session_id();

Eliminando sesiones

Cuando utilizamos sesiones usted debe de tener un metodo para poder eliminarlas, esto es necesario para que el usuario cierre sesion. 
Para eliminar una variable de sesion individual podemos utilizar la funcion unset() que es valida para cualquier variable:

 unset($_SESSION['var'])

Para eliminar cualquier variable de la sesion tu no deberias utilizar unset() sino reestablecer la sesion de la siguiente manera:

$_SESSION = array();

Y finalizamos borrando cualquier dato de sesion en el servidor utilizando la funcion session_destroy():

session_destroy();
Nota que la prioridad para utilizar cualquiera de estos metodos es siempre iniciar session_start(), para que los datos de sesion sean recogidos.

1.- abrimos el archivo logout.php
2.- agregamos al inicio del archivo session_start();
3.- Cambiamos la condicional en lugar de $_COOKIE usamos $_SESSION
4.- reemplazamos las lineas de setcookie() por $_SESSION = array(); session_destroy(); y eliminamos del mensaje de cerrado de sesion {$_COOKIE['first_name']}:


<?php

 // iniciamos sesion
 session_start();

 // esta pagina deja al usuario cerrar sesion
 // si la cookie no esta presente, redirige al usuario:

 if (!isset($_SESSION['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }else{
  // Eliminamos las cookies:
  $_SESSION = array();
  session_destroy();
 }
 // Establecemos un titulo a la pagina
 $page_title = 'Cerrar sesion';
 include('includes/header.html');

 // Imprimimos un mensaje personalizado

 echo "<h1>Cierre de sesion!</h1>
 <p>Tu cesion ha sido cerrada correctamente</p>";

 include('includes/footer.html');
?>

Hasta aqui termina la septima parte de PHP, nos vemos en la proxima parte :).

sábado, 19 de abril de 2014

[Parte 3] CURL en PHP

Cookies

El medio por el cual los navegadores web hacen "client side state control (control del estado del lado del cliente)" es por medio de cookies. Las cookies solo son nombres asociadas con contenido. Las cookies son enviadas desde el cliente al servidor. El servidor llama al cliente para saber que ruta y hostname quiere el cliente, devolviendoles asi una fecha de expiracion y unas propiedades mas.

Cuando el cliente se comunica con el servidor con el nombre y ruta previamente especificado y recibido en la cookie, el cliente envia de regreso las cookies y su contenido para el servidor, a menos que claro estas hayan expirado. 

Muchas aplicaciones y servidores usan este metodo para conectar una serie de peticiones dentro de una sola sesion. Para ser capaces de usar curl en tales ocasiones, nosotros deberiamos ser capaces de guardar y enviar de regreso las cookies a la aplicacion web.

Esto es muy importante para script en cURL para verificacion de inicios de sesion o paginas con una seccion segura en el sitio web. Estas son 3 cosas que requerimos implementar:

1.- La ruta del archivo para la cookie en tu servidor:


 <?php
 $cookie_file_path = "C:/xampp/htdocs/cookie/cook"; // Este archivo debe tener permisos chmod 777 (leer / escribir)
?>

2.- Las funciones cURL:


 <?php
 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_path); // el nombre del archivo contiene los datos de la cookie. La cookie puede ser en formato netscape, o solo texto plano http-style con las cabeceras puestas dentro del archivo
 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_path); // el nombre del archivo guarda todas las cookies internas para cuando la conexion cierra.
?>

Por favor realice lo siguiente:

1.- Suba este archivo prueba.php a su servidor con el siguiente codigo:

 <?php
 print realpath('prueba.php');
?>

2.-  Accede al archivo tuhost.com/prueba.php y copia la ruta que arroja, en este ejemplo:

/home/a8131XXX/public_html/prueba.php  

3.- Crea un archivo .txt y ponle de nombre cookie.txt y subelo a tu servidor

4- Dale permisos CHMOD 777. En windows no es necesario realizar esto.

5.- Ahora simplemente formas una cadena con lo que salio en el paso 2 y con el archivo del paso 3, quedando de la siguiente forma:


/home/a8131XXX/public_html/cookie.txt





 <?php
 // ejemplo 8
 $user = "tusuario";
 $pass = "tucontraseña";
 $url = "https://www.facebook.com/login.php";
 $post_fields = 'lsd=AVolpnen&email='.$user.'&pass='.$pass.'&default_persistent=0&timezone=360&lgnrnd=222458_oW23&lgnjs=1397971500&locale=es_LA';
 $referer = "https://www.facebook.com/login.php";
 $agent = "Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0";
 $cookie_file_path = "C:/xampp/htdocs/cookie.txt";

 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, $url);
 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 curl_setopt($ch, CURLOPT_POST, 1);
 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
 curl_setopt($ch, CURLOPT_REFERER, $referer);
 curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_path);
 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_path);

 $result = curl_exec($ch);
 curl_close($ch);

 echo $result;
?>


CURLOPT_COOKIEFILE - Nombre del fichero que contiene datos de las cookies. El fichero de las cookies puede estar en formato Netscape, o simplemente tipo HTTP plano dentro de un fichero. Si el nombre es una cadena vacia, no se cargaran cookies, aunque el manejo de cookies aun esta habilitado.

CURLOPT_COOKIEJAR - Nombre del fichero donde guardar cookies internas cuando se cierra se cierra, por ejemplo: despues de llamar a curl_close().

HTTPS (SSL)

Hay varias formas de realizar transferencias HTTP seguras. A lo lejos el protocolo mas comun que realiza esto es conocido como HTTPS, HTTP encima de SSL. SSL encripta todos los datos que son enviados y recibidos atraves de la red, asi hace mas dificil que los atacantes espien la informacion sensitiva.

SSL (o TLS como la ultima version del estandar es llamada) ofrece un camino para caracteristicas avanzadas para permitir estas encriptaciones y claves de mecanismos de infraestructura para encriptar HTTP como es requerido.

cURL soporta recuperaciones encriptadas gracias a las librerias OpenSSL.

En el ejemplo anterior de la peticion con cURL a facebook, usamos esto que eran las opciones CURLOPT_SSL_VERIFYPEER y CURLOPT_SSL_VERIFYHOST.

CURLOPT_SSL_VERIFYPEER - FALSE para que cURL no verifique el PEER del certificado. Para usar diferentes certificados para la verificacion se puede especificar con la opcion CURLOPT_CAINFO o se puede especificar el directorio donde se encuentra el certificado con la opcion CURLOPT_CAPATH. TRUE por omision desde cURL 7.10. Paquete instalado por defecto en la version de CURL 7.10.


CURLOPT_SSL_VERIFYHOST - 1 para comprobar que existe un nombre comun en el peer del certificado SSL.  2 para comprobar que existe un nombre comun y tambien para verificar que el hostname coincide con el proporcionado. En entornos de produccion el valor de esta opcion debe de mantenerse en 2 (valor por omision).

Depuracion

Muchas veces cuando corremos curl en un sitio, tienes un aviso de que el sitio no se muestra, para responder de la misma forma las peticiones curl tu debes hacer como el navegador.

Entonces tu necesitas empezar a crear tus peticiones mas similar a tus peticiones del navegador:

- Estar seguro que checa las cookies cuando son necesarias
- Establecer User-Agent de los navegadores mas actuales y populares
- Establecer el Referer como esta establecido en el navegador
- Si contiene datos POST, debes acomodarlos de la misma manera que lo hace el navegador.

CURLOPT_HEADER - TRUE para incluir el header (encabezado) en la salida
CURLOPT_VERBOSE - TRUE para mostrar informacion verbose. Escribe la salida en STDERR, o el fichero especificado usando CURLOPT_STDERR.




sábado, 29 de marzo de 2014

[Parte 4] Seguridad en PHP

Sesiones y cookies

HTTP es un protocolo sin estado, es decir, que no guarda informacion sobre conexiones anteriores. El desarrollo de aplicaciones web necesita frecuentemente mantener estado. Para eso se usan las cookies, que es informacion que un servidor puede almacenar en el sistema cliente. Esto les permite a las aplicaciones web instruir la nocion de "sesion", y tambien permite rastrear a usuarios ya que las cookies pueden guardarse en el cliente por tiempo indeterminado.

 Figura que muestra el intercambio de cookies

Como estamos hablando de PHP entonces hablaremos sobre sesion_start() la cual inicia una sesion o reanuda una existente...

session_start() crea una sesion o reanuda la actual basada en un identificador de sesion pasado mediante una peticion GET o POST, o pasado mediante una cookie. 
Cuando session_start() es llamada o cuando se autoinicia una sesion, PHP llamara a los gestores de almacenamiento de sesiones open y read. Estos seran un gestor de almacenamiento proporcionado por omision o por extensiones de PHP (Como SQLite o Memcached); o pueden ser un gestor personalizado como esta definido en session_set_save_handler(). La llamada de retorno read recuperara cualquier informacion de sesion existente (almacenada en un formato serializado especial) y sera deserializada y usada para rellenar automaticamente la variable superglobal $_SESSION cuando la llamada de retorno read devuelva la informacion de sesion guardada a la gestion de sesiones PHP. 



Robo de cookies

Al usar cookies uno de los riesgos que conlleva es que pueden ser robadas por un atacante y llevar a un secuestro de sesion.

Los dos metodos mas famosos para el robo de cookies es alguna vulnerabilidad en el navegador o el cross site scripting (XSS).

Para firefox tenemos disponible el complemento noscript que nos ayuda a ver cual script podria ser un riesgo ejecutar y nos pide permiso si deseamos ejecutarlo o no (aveces puede ser un poco molesto pero es una de las maneras de obtener un poco mas de seguridad ante este tipo de ataques).

Otra manera de evitar este tipo de ataques en el navegador es mantenerlo actualizado, ya que cada cierto tiempo realizan la actualizacion incluyen nuevas funciones y parches para las vulnerabilidades de tal.



Para poder evitar este tipo de ataques a nivel web que seria el cross site scripting (XSS) podemos recurrir a la parte 2 de seguridad en PHP.



Datos de sesion expuestos

Los datos de sesion muchas veces contiene informacion confidencial por lo que es una buena practica implementar SSL.

Secure Sockets Layer (SSL; en español <<capa de conexion segura>>) y su sucesor Transport Layer Security (TLS; en español <<Seguridad de la capa de transporte>>) son protocolos criptograficos que proporcionan comunicaciones seguras por una red, comumente internet.

Uno de los usos mas importantes es junto a HTTP para formar HTTPS es usado para asegurar paginas World Wide Web para aplicaciones de comercio electronico, utilizando certificados de clave publica para verificar la identidad de los externos.

O simplemente podemos usar nuestra propia funcion con session_set_save_handler(), pueden ver un ejemplo en wikihow.


Fijacion de sesion

Una de las preocupaciones de las sesiones es el identificador de sesion, ya que un atacante con un identificador de sesion valido podria secuestrar practicamente la sesion del usuario en si.

Un atacante puede obtener un identificador de sesion valido usando:

* Prediccion de sesion (Conjeturas)
* Capturar la sesion (MITM)
* Fijacion de sesion 


Fijacion de sesion es un ataque que engaña a la victima para el uso de un identificador de sesion elegida por el atacante. Es el metodo mas simple por el cual el atacante puede obtener un identificador de sesion valido.


Un ejemplo muy basico seria el siguiente:



Otro enfoque es realizar una redireccion:



El objetivo del ataque es conseguir que el usuario visite una URL que incluye un identificador de sesion de la eleccion del atacante. 





Antes de seguir quiero comentarles que este tipo de vulnerabilidad esta corregida desde la version 5.5.2: http://unaaldia.hispasec.com/2013/08/solucionada-la-fijacion-de-sesiones-en.html

En caso de que funcionara en su servidor la sesion deberia reanudarse (reemplazar tuhost.com por tu URL):

fixation.php


fixation_echo.php


Primero antes que nada nos aseguramos de que no tengamos cookies para el host actual, ahora visitamos tuhost.com/fixation.php?PHPSESSID=1234

Esto crea una variable de sesion con un valor de arthusu...



El segundo script fixation_echo.php, muestra si el valor $_SESSION['username'] existe. Visitamos la misma la siguiente URL utilizando un navegador o equipo diferente...

tuhost.com/fixation_echo.php?PHPSESSID=1234

Esto hace que se reanude la sesion cuando se visito fixation.php, y el equipo o navegador diferente imitan la posicion del atacante, y con esto la sesion ha sido secuestrada.

Para prevenir este tipo de ataque usamos session_regenerate_id() que lo que hace es actualizar el id de sesion actual con uno mas reciente.



Un ejemplo seria el siguiente:



Esto asegura que siempre que se inicie una nueva sesion el identificador se renueve.
Pero como esto no elimina del todo la vulnerabilidad ya que un atacante puede "capturar" el PHPSESSID que manda PHP y enviarselo a la victima...





Lo mas conveniente seria regenerar el identificador cada vez que haya un cambio en el nivel de privilegio, de esta manera:



En este caso check_login() seria nuestra funcion personalizada...



Secuestro de sesion

Como comentamos anteriormente el secuestro de sesion se puede llevar a cabo por prediccion, capturar y fijar la sesion, y tambien esta por medio de ataques XSS, bueno pero lo importante aqui, es que si te estan "olfateando la red" como te proteges? Hay un ataque conocido como MITM (Man in the middle, es español <<Hombre en el medio>>), lo que realiza este tipo de ataque es infectar las tablas ARP quedando como si fuera un proxy asi todas las peticiones que haga la victima pasaran por el...


Algunas de las prevenciones que podemos agregar seria, registrar el navegador que estamos usando en la sesion actual, de esta manera si alguien llega y nos atrapa la sesion al querer mandarla por las cabeceras HTTP por medio de Google Chrome mientras la persona real esta usando Mozilla Firefox, entonces que muestre un campo donde introduzca su contraseña. 



Pero esto tiene un inconveniente, ya que puede manejar las cabeceras HTTP podemos predecir que se trata del navegador y realizar el ataque es por eso que es mas recomendable usar un token, de esta manera, no sabria realmente como predecirlo...


Si no quisieramos depender del navegador simplemente podemos usar un token aleatorio...



Los tokens se usan para verificar la autenticidad del usuario, de esta manera sabriamos decir si es realmente el o no, esto verificando el token actual...

Y como comentamos anteriormente el uso de SSL podria ayudarnos en el momento de que nos esten "olfateando la red", aunque no es tan seguro como se dice ser pero sirve de mucho, y como vemos siempre es bueno tener un "safeguard" por si no funciona uno como en este caso SSL, tenemos los tokens con los cuales no pueden pasar, el objetivo es "hacerle la vida dificil" al atacante...

Referencias:

* Essential PHP Security
* OWASP
* Wikipedia
* PHP.net
* hispaSEC