segura en mysql php

21
7/24/2019 segura en mysql php http://slidepdf.com/reader/full/segura-en-mysql-php 1/21 Cómo crear un script de inicio de sesión segura en php y MySQL 8 partes: Configurar tu servidor Configurar la base de datos MySQL Crear la página de conexión para la base de datos Crear funciones PHP Crear páginas de procesamiento Crear archivos de Javascript Crear páginas HTML Proteger páginas Con más y más historias de la piratería en las noticias, los desarrolladores buscan mejores maneras de asegurar su sitio. Si tu sitio tiene un sistema de miembros, podría estar en riesgo de ser crackeado y los datos de los usuarios podrían verse comprometidos. La presente guía te mostrará un intento de crear un inicio de sesión segura con PHP. Hemos puesto nuestro mejor esfuerzo en programar el código, pero la seguridad y sobre todo la encriptación son temas complejos que cambian todo el tiempo y no podemos decir que dominamos todo ese campo. Por lo tanto, podríamos haber obviado unos cuantos trucos en nuestra programación. De ser así, háznoslos saber y trataremos de incorporar toda mejora a lo que tenemos. Seguir la presente guía te ayudará a cuidarte de muchos tipos de ataques que podrían emplear los crackers para apoderarse del control de las cuentas de otros usuarios, eliminar cuentas y/o cambiar datos. A continuación te presentaremos un lista de posibles ataques de los cuales la presente guía procura defenderse: SQL Injections Session Hijacking Network Eavesdropping Cross Site Scripting Brute Force Attacks El enfoque consiste en emplear una combinación de filtros de datos, encriptación y otros métodos para hacerles la vida un poco más difícil a quienes piensen atacarte. Tratamos de mejorar continuamente el presente script. La versión más reciente del código está disponible en github. Podría haber algunas diferencias entre el código que descargues en esa página y el código citado en el presente artículo. Deberás tener presente que nuestro objetivo no ha sido que la presentación de las páginas HTML hecha por la aplicación se vea bonita en lo absoluto. También deberás tener presente que no cerramos las etiquetas PHP en los archivos que contienen solamente código PHP. Esto está en línea con la mayoría de recomendaciones de formato de código. Por último, es necesario que sepas que te pedimos crear todos los archivos no-HTML de la aplicación en diversos directorios dentro del directorio raíz de la aplicación. La manera más fácil de crear la estructura del directorio correcto consiste en descargar el código más reciente haciendo clic en uno de los enlaces antes mencionados. Por favor, siéntete con la libertad de usar la presente aplicación como base para tu propia implementación, pero no la uses a modo de ejemplo de una buena práctica de programación.

Transcript of segura en mysql php

Page 1: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 1/21

Cómo crear un script de inicio desesión segura en php y MySQL8 partes: Configurar tu servidor Configurar la base de datos MySQL

Crear la página de conexión para la base de datos Crear funciones PHP Crear páginas de procesamiento

Crear archivos de Javascript Crear páginas HTML Proteger páginas

Con más y más historias de la piratería en las noticias, los desarrolladores

buscan mejores maneras de asegurar su sitio. Si tu sitio tiene un sistema de

miembros, podría estar en riesgo de ser crackeado y los datos de los usuarios

podrían verse comprometidos. La presente guía te mostrará un intento de

crear un inicio de sesión segura con PHP. Hemos puesto nuestro mejor

esfuerzo en programar el código, pero la seguridad y sobre todo la encriptación

son temas complejos que cambian todo el tiempo y no podemos decir que

dominamos todo ese campo. Por lo tanto, podríamos haber obviado unos

cuantos trucos en nuestra programación. De ser así, háznoslos saber y

trataremos de incorporar toda mejora a lo que tenemos. Seguir la presente

guía te ayudará a cuidarte de muchos tipos de ataques que podrían emplear

los crackers para apoderarse del control de las cuentas de otros usuarios,

eliminar cuentas y/o cambiar datos. A continuación te presentaremos un lista

de posibles ataques de los cuales la presente guía procura defenderse:

SQL Injections

Session Hijacking

Network Eavesdropping

Cross Site Scripting

Brute Force Attacks

El enfoque consiste en emplear una combinación de filtros de datos,

encriptación y otros métodos para hacerles la vida un poco más difícil a

quienes piensen atacarte.

Tratamos de mejorar continuamente el presente script. La versión más reciente

del código está disponible en github. Podría haber algunas diferencias entre el

código que descargues en esa página y el código citado en el presente

artículo. Deberás tener presente que nuestro objetivo no ha sido que la

presentación de las páginas HTML hecha por la aplicación se vea bonita en lo

absoluto.

También deberás tener presente que no cerramos las etiquetas PHP en los

archivos que contienen solamente código PHP. Esto está en línea con la

mayoría de recomendaciones de formato de código.

Por último, es necesario que sepas que te pedimos crear todos los archivos

no-HTML de la aplicación en diversos directorios dentro del directorio raíz de la

aplicación. La manera más fácil de crear la estructura del directorio correcto

consiste en descargar el código más reciente haciendo clic en uno de los

enlaces antes mencionados.

Por favor, siéntete con la libertad de usar la presente aplicación como basepara tu propia implementación, pero no la uses a modo de ejemplo de una

buena práctica de programación.

Page 2: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 2/21

Debido a que estaremos utilizando mysqli_* que es un conjunto de clasesPHP para acceder a nuestra base de datos mySQL, necesitarás las

siguientes versiones de PHP y MySQL.

PHP versión 5.3 o posterior

MySQL versión 4.1.3 o posterior

Evidentemente, también necesitarás un servidor web configurado para usar

PHP para alojar tus páginas. Este será muy probablemente el servidor web

de alojamiento de tu página, a menos que estés alojando tú mismo el sitio.

Para revisar la versión de PHP y MySQL en tu servidor, emplea la función

phpinfo();.

1 Instala un servidor web, PHP y MySQL en tu servidor.

La mayoría de los servicios de alojamiento tiene PHP y mySQL ya instalados, pero

tendrás que revisar que tengan las versiones más recientes de PHP y mySQL para que

la presente guía pueda serte de ayuda. Si no tienen al menos PHP5.3 y MySQL5,

podrías poner en tela de juicio su compromiso con la seguridad. Mantener tu software

actualizado es parte del proceso de seguridad.

Si tienes tu propio servidor o computadora, deberás instalar el software requerido

normalmente según tu sistema. En general, si no vas a usar la configuración por

motivos de producción y vas a desarrollar en Windows o OS X, instalar un paquete de

aplicaciones (stack) XAMPP será lo más recomendable. Consigue la versión apropiada

para tu sistema operativo en:

http://www.apachefriends.org/en/xampp.html

Sin embargo, ten presente que bajo ninguna circunstancia deberás utilizar XAMPP para

crearte un ambiente de servidor de producción.

En Linux, usa el gestor de paquetes para descargar e instalar los paquetes necesarios.

Algunas distribuciones, como Ubuntu, contienen todas las aplicaciones necesarias en

un solo paquete. Tan solo tendrás que hacer lo siguiente en una ventana de terminal de

Ubuntu:

sudo apt-get install lamp-server^ phpmyadmin

Pero aunque instales los elementos necesarios, asegúrate de configurar MySQL con

una contraseña de raíz segura.

Anuncio

Cosas que necesitarás

Parte 1 de 8: Configurar tu servidor

Page 3: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 3/21

Anuncio

1 Crea una base de datos MySQL.

Inicia la sesión en tu base de datos como usuario administrador (normalmente “raíz”).

En la presente guía crearemos una base de datos llamada “inicio_seguro”.

Ve cómo crear una base de datos en phpMyAdmin.

Podrás usar el código a continuación o hacer lo mismo en phpMyAdmin o en tu cliente

GUI MySQL favorito, si lo deseas:

CREATE DATABASE `secure_login`;

Nota: algunos servicios de alojamiento no te permitirán crear una base de datos con

phpMyAdmin, por eso aprende hacerlo en cPanel.

2 Crea un usuario solo con los privilegios SELECCIONAR, ACTUALIZAR e

INSERTAR.

Crear un usuario con privilegios restringidos significa que en el caso de que alguna vez

se viole la seguridad en tu secuencia de comandos, el hacker no podrá borrar ni dejar

nada desde nuestra base de datos. Al utilizar este usuario podrás hacer casi lo que

quieras con tu aplicación. Si eres realmente paranoico, crea un usuario diferente para

cada función.

Claro que necesitarás haber iniciado sesión en MySQL como un usuario con los

privilegios suficientes para poder crear otro usuario. Por lo general, este usuario será

raíz.

Los siguientes detalles son del usuario que hemos creado:

Usuario: "sec_user"

Parte 2 de 8: Configurar la base de datos MySQL

Page 4: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 4/21

Nota: te recomendamos cambiar la contraseña del que mencionamos anteriormente

cuando vayas a ejecutarlo en tu propio servidor. Si lo haces, asegúrate también de

cambiar el código a continuación y el código de conexión de la base de datos PHP en la

aplicación que crearemos.

Recuerda que no tendrá que ser una contraseña que puedas recordar, así que hazla lo

más complicada posible. Por ejemplo, este es un generador de contraseñas aleatorias.

A continuación también estará el código SQL para crear el usuario de base de datos y

otorgarle los permisos necesarios. Si lo prefieres, también podrías hacerlo en un cliente

de base de datos GUI como phpmyadmin:

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';

GRANT SELECT, INSERT, UPDATE ON `secure_login`.* TO 'sec_user'@'localhost';

Si ves que vas a eliminar registros de cualquiera de las tablas del presente módulo,

deberás agregar ELIMINAR a la lista de privilegios o sino podrías crear un usuario

diferente que tenga solamente el privilegio ELIMINAR y solo en la tabla en la quequieras borrar registros, si no quieres hacerlo en ambas. No es necesario que otorgues

el privilegio ELIMINAR en lo absoluto para el presente ejemplo de script.

Contraseña: "eKcGZr59zAa2BEWU"

3 Crea una tabla MySQL que lleve por título "miembros".

El código a continuación creará una tabla con cinco campos (identificación, nombre de

usuario, correo electrónico, contraseña, sal). Utilizaremos el tipo de datos CHAR para

los campos cuya extensión conozcamos, ya que los campos “contraseña” y “sal”

siempre tendrán 128 caracteres de largo. Utilizar CHAR en esos casos ahorrará energíade procesamiento:

CREATE TABLE `secure_login`.`members` (

  `id` INT NOT NULL  AUTO_INCREMENT PRIMARY KEY,

  `username` VARCHAR(30) NOT NULL,

  `email` VARCHAR(50) NOT NULL,

  `password` CHAR(128) NOT NULL,

  `salt` CHAR(128) NOT NULL 

) ENGINE = InnoDB;

Como lo hemos mencionado anteriormente, podrás hacerlo en cualquier tipo de cliente

que prefieras.

4 Crea una tabla para almacenar intentos de inicio de sesión.

Utilizaremos esta tabla para almacenar los intentos de inicio de sesión de un usuario.

Esta es una manera con la que dificultaremos los ataques de fuerza bruta:

CREATE TABLE `secure_login`.`login_attempts` (

  `user_id` INT(11) NOT NULL,

  `time` VARCHAR(30) NOT NULL

) ENGINE=InnoDB

Crea una fila de prueba en la tabla “miembros”.

Page 5: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 5/21

5 Será importante poder ser capaz de probar el script de inicio de sesión, así que a

continuación te presentaremos el script para crear un usuario con detalles conocidos:

El código que necesitarás para poder iniciar sesión como este usuario es:

INSERT INTO `secure_login`.`members` VALUES(1, 'test_user', '[email protected]','00807432eae173f652f2064bdca1b61b290b52d40e429a7d295d76a71084aa96c0233b82f1feac

'f9aab579fc1b41ed0c44fe4ecdbfcdb4cb99b9023abb241a6db833288f4eea3c02f76e0d35204a

Anuncio

Username: test_user

Email: [email protected]

Password: 6ZaxN2Vzm9NUJT2y

1Crea una página de configuraciones globales.

Crea una carpeta llamada “includes” en el directorio raíz de la aplicación y luego crea

un archivo PHP nuevo en ese directorio. Ponle el nombre “psl-config.php”. En un

ambiente de producción, deberás ubicar ese archivo y todos los demás archivos

“include” fuera de la raíz de documentos del servidor web. Si lo haces, cosa que te

recomendamos, tendrás que alterar el “include” o las declaraciones requeridas tanto

como sea necesario para que la aplicación pueda encontrar los archivos “include”.

Si ubicas estos archivos fuera de la raíz de documentos del servidor web, no se podrá

encontrar tu archivo con un URL. Entonces, en el caso de que alguien haya dejado la

extensión PHP por error o haya echado a perder los permisos de archivo, el archivo no

podrá mostrarse en texto en una ventana del buscador.

El archivo tendrá variables de configuración global. Aspectos como si alguien puede

registrarse, si es una conexión (HTTPS) segura, entre otros, además de los detalles de

la base de datos podrían ir a ese lugar.

<?php

/**

 * Estos son los detalles de inicio de sesión de la base de datos:

*/  

define("HOST", "localhost");  // El alojamiento al que deseas conectarte 

define("USER", "sec_user");  // El nombre de usuario de la base de datosdefine("PASSWORD", "4Fa98xkHVd2XmnfK");  // La contraseña de la base de datos

define("DATABASE", "secure_login");  // El nombre de la base de datos

 

define("CAN_REGISTER", "any");

define("DEFAULT_ROLE", "member");

 

define("SECURE", FALSE);  // ¡¡¡SOLO PARA DESARROLLAR!!!!

Parte 3 de 8: Crear la página de conexión para la base de datos

Page 6: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 6/21

2 Crea la página de conexión para la base de datos.

Este será el código PHP que tendrás que utilizar para conectarte a la base de datos

mySQL. Crea un nuevo archivo PHP llamado “db_connect.php” en el directorio de

“includes” de la aplicación y agrega el código a continuación. Luego podrás incluir el

archivo en cualquier página en la que desees conectarte con la base de datos.

<?php

include_once 'psl-config.php';  // Ya que functions.php no está incluido.

$mysqli = new  mysqli(HOST, USER, PASSWORD, DATABASE);

Anuncio

Estas funciones harán todo el procesamiento del script de conexión. Agrega

todas las funciones a la página llamada “functions.php” en el directorio

“includes” de la aplicación.

1 Inicia de manera segura la sesión PHP.

Las sesiones PHP tienen fama de no ser muy seguras, por eso será importante no

solo poner “session_start();” en la parte superior de cada página que quieras usar para

las sesiones PHP. Crearemos una función llamada “sec_session_start()”, ella iniciará

una sesión PHP de manera segura. Deberás llamar esta función en la parte superior de

toda página en la que quieras tener acceso a una variable de sesión PHP. Si estás

realmente preocupado por la seguridad y la privacidad de las cookies, échale un vistazo

al siguiente artículo: Cómo crear un sistema de administración de sesión segura en

PHP y MySQL.

Esta función hará que tu script de inicio de sesión sea mucho más seguro. Hará que los

crackers dejen de acceder al cookie de identificación de la sesión con JavaScript (por

ejemplo en un ataque XSS). A su vez, la función “session_regenerate_id()”, la cual

regenera la identificación de la sesión en cada carga de la página, ayudará a prevenir

un robo de sesión. Nota: si vas a usar HTTPS en tu aplicación de inicio de sesión,

configura la variable “$secure” a “verdadero”. En un ambiente de producción, será

esencial que emplees HTTPS.

Crea un nuevo archivo llamado “functions.php” en el directorio “includes” de tu

aplicación y agrégale el código a continuación.

<?phpinclude_once 'psl-config.php';

 

function sec_session_start() {

  $session_name = 'sec_session_id';  // Configura un nombre de sesión personalizado.

  $secure = SECURE;

  // Esto detiene que JavaScript sea capaz de acceder a la identificación de la sesión.

  $httponly = true;

  // Obliga a las sesiones a solo utilizar cookies.

Parte 4 de 8: Crear funciones PHP

Page 7: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 7/21

  if (ini_set('session.use_only_cookies', 1) === FALSE) {

  header("Location: ../error.php?err=Could not initiate a safe session (i

  exit();

  }

  // Obtiene los params de los cookies actuales.

  $cookieParams = session_get_cookie_params();

  session_set_cookie_params($cookieParams["lifetime"],

  $cookieParams["path"], 

$cookieParams["domain"], 

$secure,

  $httponly);

  // Configura el nombre de sesión al configurado arriba.

  session_name($session_name);

  session_start();  // Inicia la sesión PHP.

  session_regenerate_id();  // Regenera la sesión, borra la previa.

}

2 Crea la función de inicio de sesión.

Esta función comparará el correo electrónico y la contraseña con la base de datos

y, si hay una coincidencia, aparecerá como verdadero (true). Agrega esta función a tu

archivo “functions.php”:

function login($email, $password, $mysqli) {

  // Usar declaraciones preparadas significa que la inyección de SQL no será posible.  if ($stmt = $mysqli->prepare("SELECT id, username, password, salt

FROM members

  WHERE email = ?

  LIMIT 1")) {

  $stmt->bind_param ('s', $email);  // Une “$email” al parámetro.

  $stmt->execute();  // Ejecuta la consulta preparada.

  $stmt->store_result();

 

// Obtiene las variables del resultado.

  $stmt->bind_result($user_id, $username, $db_password, $salt);

  $stmt->fetch();

 

// Hace el hash de la contraseña con una sal única.

  $password = hash('sha512', $password . $salt);

  if ($stmt->num_rows == 1) {

  // Si el usuario existe, revisa si la cuenta está bloqueada

  // por muchos intentos de conexión.

 

if (checkbrute($user_id, $mysqli) == true) {

  // La cuenta está bloqueada.

  // Envía un correo electrónico al usuario que le informa que su cuenta está bloqueada.

  return false;

  } else {

  // Revisa que la contraseña en la base de datos coincida

// con la contraseña que el usuario envió.

  if ($db_password == $password) {

  // ¡La contraseña es correcta!

  // Obtén el agente de usuario del usuario.

  $user_browser = $_SERVER['HTTP_USER_AGENT'];  // Protección XSS ya que podríamos imprimir este valor.

  $user_id = preg_replace("/[^0-9]+/", "", $user_id);

  $_SESSION['user_id'] = $user_id;

  // Protección XSS ya que podríamos imprimir este valor.

  $username = preg_replace("/[^a-zA-Z0-9_\-]+/", 

"", 

$username);

  $_SESSION['username'] = $username;

  $_SESSION['login_string'] = hash('sha512', 

$password . $user_browser);

  // Inicio de sesión exitoso 

  return true;

  } else {

  // La contraseña no es correcta.  // Se graba este intento en la base de datos.

  $now = time();

  $mysqli->query("INSERT INTO login_attempts(user_id, time)

  VALUES ('$user_id', '$now ')");

  return false;

  }

  }

  } else {

Page 8: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 8/21

  // El usuario no existe.

  return false;

  }

  }

}

3 La función de fuerza bruta.

Los ataques de fuerza bruta se dan cuando un hacker intenta acceder a una

cuenta con 1000 contraseñas diferentes, ya sean generadas al azar o de un diccionario.

En nuestra secuencia de comandos, si la cuenta de un usuario no inicia la sesión

después de más de 5 intentos, su cuenta se bloqueará.

Los ataques de fuerza bruta son difíciles de prevenir, para hacerlo podrías utilizar

pruebas de CAPTCHA, bloquear las cuentas de usuario y agregar un retraso en los

inicios de sesión fallidos, así el usuario no podrá acceder por otros 30 segundos.

Recomendamos enfáticamente usar un CAPTCHA. Como no hemos implementado esta

funcionalidad en nuestro código ejemplo, esperamos hacerlo próximamente con

SecureImage, ya que no requiere inscripción. Podrías preferir algo más conocido como

reCAPTCHA de Google.

Sea cual sea el sistema que decidas usar, te sugerimos mostrar la imagen de

CAPTCHA después de dos inicios de sesión fallidos para evitar incomodar al usuario

innecesariamente.

Cuando nos enfrentamos a este problema, la mayoría de los desarrolladores

simplemente bloquea la dirección IP después de cierta cantidad de inicios de sesión

fallidos. Sin embargo, existen muchas herramientas para automatizar el proceso. Estas

pueden pasar por una serie de proxies e incluso cambiar la IP en cada solicitud.

Bloquear todas estas direcciones IP podría bloquear las cuentas de tus usuarios

legítimos también. En nuestro código registraremos los intentos fallidos y bloquearemos

la cuenta del usuario después de cinco intentos sin éxito. Esto hará que se envíe un

correo electrónico al usuario con un enlace para resetearlo, pero no hemos

implementado este punto en nuestro código. A continuación te presentaremos la función

“checkbrute()” hasta la fecha. Agrégaselo a tu código “functions.php”:

function checkbrute($user_id, $mysqli) {

  // Obtiene el timestamp del tiempo actual.

  $now = time();

 

// Todos los intentos de inicio de sesión se cuentan desde las 2 horas anteriores.

  $valid_attempts = $now - (2 * 60 * 60);

 

if ($stmt = $mysqli->prepare("SELECT time

FROM login_attempts

WHERE user_id = ?

AND time > '$valid_attempts'")) {

  $stmt->bind_param ('i', $user_id);

 

// Ejecuta la consulta preparada.

  $stmt->execute();

  $stmt->store_result();

 

// Si ha habido más de 5 intentos de inicio de sesión fallidos.

  if ($stmt->num_rows > 5) {

  return true;

  } else {

  return false;

  }

  }

}

Page 9: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 9/21

4 Revisa el estado de la sesión iniciada.

Lo haremos mediante la comprobación de “user_id” y las variables de sesión

“login_string”. La variable SESSION “login_string” tiene la información del navegador de

los usuarios junto con la contraseña unida mediante una función hash. Utilizamos la

información del navegador, ya que es muy poco probable que el usuario lo vaya a

cambiar a la mitad de la sesión. Hacerlo ayudará a prevenir un robo de sesión. Agrega

esta función a tu archivo “functions.php” en la carpeta “includes de tu aplicación:

function login_check($mysqli) {

  // Revisa si todas las variables de sesión están configuradas.

  if (isset($_SESSION['user_id'], 

$_SESSION['username'], 

$_SESSION['login_string'])) {

 

$user_id = $_SESSION['user_id'];

  $login_string = $_SESSION['login_string'];

  $username = $_SESSION['username'];

 

// Obtiene la cadena de agente de usuario del usuario.

  $user_browser = $_SERVER['HTTP_USER_AGENT'];

 

if ($stmt = $mysqli->prepare("SELECT password

FROM members

WHERE id = ? LIMIT 1")) {

  // Une “$user_id” al parámetro.  $stmt->bind_param ('i', $user_id);

  $stmt->execute();  // Ejecuta la consulta preparada.

  $stmt->store_result();

 

if ($stmt->num_rows == 1) {

  // Si el usuario existe, obtiene las variables del resultado.

  $stmt->bind_result($password);

  $stmt->fetch();

  $login_check = hash('sha512', $password . $user_browser);

 

if ($login_check == $login_string) {

  // ¡¡Conectado!!

return true;

  } else {

  // No conectado.

  return false;

  }

  } else {

  // No conectado.

  return false;

  }

  } else {

  // No conectado.

  return false;

  }

  } else {

  // No conectado.

  return false;

  }

}

5 Sanea la URL de PHP_SELF

Esta función sanea la salida de la variable del servidor PHP_SELF. Es una

modificación de una función del mismo nombre usada por el sistema de gestión de

contenido WordPress:

function esc_url($url) {

 

if ('' == $url) {

  return $url;

  }

 

$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i' , '', 

$strip = array('%0d', '%0a', '%0D', '%0A');

Page 10: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 10/21

  $url = (string) $url;

 

$count = 1;

   while ($count) {

  $url = str_replace($strip, '', $url, $count);

  }

 

$url = str_replace(';//', '://', $url);

 

$url = htmlentities($url);

 

$url = str_replace('&amp;', '&#038;', $url);

  $url = str_replace("'", '&#039;', $url);

 

if ($url[0] !== '/') {

  // Solo nos interesan los enlaces relativos de $_SERVER['PHP_SELF']

  return '';

  } else {

  return $url;

  }

}

El problema de usar una variable de servidor no filtrada es que podría usarse en un

ataque de secuencias de comandos en sitios cruzados. Según la mayoría de

referencias, solo tendrás que filtrarla con “htmlentities()”, sin embargo, sigue siendo

insuficiente, por eso existen excesivas medidas de seguridad para esta función.

Otros sugieren dejar en blanco el atributo de acción del formulario o configurarlo a una

cadena vacía. Pero hacerlo así podría dar lugar a un ataque de secuestro de clic iframe.

Anuncio

1 Crea la página de procesamiento de inicio de sesión (process_login.php)

Crea un archivo para procesar los inicios de sesión, con el nombre

“process_login.php”, en el directorio “includes” de la aplicación. Tendrá que ir a

este directorio porque no tiene ningún formato HTML.

Usaremos la serie de funciones PHP mysqli_*, puesto que esta es una de las

extensiones mySQL más actualizadas.

<?php

include_once 'db_connect.php';include_once 'functions.php';

 

sec_session_start(); // Nuestra manera personalizada segura de iniciar sesión PHP.

 

if (isset($_POST['email'], $_POST['p'])) {

  $email = $_POST['email'];

  $password = $_POST['p']; // La contraseña con hash

 

Parte 5 de 8: Crear páginas de procesamiento

Page 11: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 11/21

  if (login($email, $password, $mysqli) == true) {

  // Inicio de sesión exitosa

  header('Location: ../protected_page.php');

  } else {

  // Inicio de sesión exitosa

  header('Location: ../index.php?error=1');

  }

} else {

  // Las variables POST correctas no se enviaron a esta página.

  echo 'Solicitud no válida';

}

2 Crea una secuencia de comandos para cerrar sesión.

El script para el cierre de sesión deberá iniciar sesión, destruirla y luego redireccionarla

a otro lugar. Nota: te recomendamos añadir una protección CSRF aquí en el caso de

que alguien logre enviar un enlace oculto a esta página. Para mayor información sobre

CSRF, visita Coding Horror.

El código actual para desconectar al usuario, el cual deberás agregar al archivo titulado

“logout.php” en el directorio “includes” de la aplicación, es el siguiente:

<?php

include_once 'includes/functions.php';

sec_session_start();

 

// Desconfigura todos los valores de sesión.

$_SESSION = array();

 

// Obtiene los parámetros de sesión.

$params = session_get_cookie_params();

 

// Borra el cookie actual.

setcookie(session_name(),

  '', time() - 42000, 

$params["path"], 

$params["domain"], 

$params["secure"], 

$params["httponly"]);

 

// Destruye sesión.

session_destroy();

header('Location: ../ index.php');

3 Página de registro.

Deberás incluir el código de registro en dos archivos nuevos, llamados “register.php” en

el directorio raíz de la aplicación y “register.inc.php” en el directorio “includes”, lo cual

hará lo siguiente:

La mayoría de la validación se hace en JavaScript, del lado del cliente. Esto se debe aque el usuario no tiene la motivación para burlar estas verificaciones. ¿Por qué querría

el usuario crearse una cuenta que no sería tan segura? Hablaremos de JavaScript en la

siguiente sección.

Por ahora, solo tendrás que crear el archivo “register.php” e incluye el código a

continuación:

Obtiene y valida el nombre de usuario que el usuario desea adoptar.

Obtiene y valida la dirección de correo electrónico del usuario.

Obtiene y valida la contraseña que el usuario desea usar.

Pone la contraseña con hash y la devuelve a la página “register.php” (o sea, la

envía a sí misma).

Page 12: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 12/21

<?php

include_once 'includes/register.inc.php';

include_once 'includes/functions.php';

?>

<!DOCTYPE html>

<html>

  <head>

  <meta charset="UTF-8">

  <title>Secure Login: Formulario de registro</title>

  <script type="text/JavaScript" src="js/sha512.js"></script>

<script type="text/JavaScript" src="js/forms.js"></script>

  <link rel="stylesheet" href="styles/main.css" />

  </head>  <body>

  <!-- Formulario de registro que se emitirá si las variables POST no se

  establecen o si la secuencia de comandos de registro ha provocado un

<h1>Regístrate con nosotros</h1>

  <?php

  if (!empty($error_msg)) {

  echo $error_msg;

  }

  ?>

  <ul>

  <li> Los nombres de usuario podrían contener solo dígitos, letras m

<li> Los correos electrónicos deberán tener un formato válido. </li

  <li> Las contraseñas deberán tener al menos 6 caracteres.</li>

  <li>Las contraseñas deberán estar compuestas por:  <ul>

  <li> Por lo menos una letra mayúscula (A-Z)</li>

  <li> Por lo menos una letra minúscula (a-z)</li>

  <li> Por lo menos un número (0-9)</li>

  </ul>

  </li>

  <li> La contraseña y la confirmación deberán coincidir exactamente.

  </ul>

  <form action="<?php echo esc_url($_SERVER['PHP_SELF']); ?>"

method="post"

name="registration_form">

  Nombre de usuario: <input type='text'

name='username'

id='username' /><br>

  Correo electrónico: <input type="text" name="email" id="email" /><b

  Contraseña: <input type="password"

  name="password"

id="password"/><br>

  Confirmar contraseña: <input type="password"

name="confirmpwd"

id="confirmpwd" /><br>

  <input type="button"

value="Register"

onclick="return regformhash(this.form,

  this.form.username,

  this.form.email,

  this.form.password,

  this.form.confirmpwd);" />

</form>  <p>Return to the <a href="index.php">login page</a>.</p>

  </body>

</html>

El archivo “register.inc.php” en el directorio “includes” deberá tener el código a

continuación:

<?php

include_once 'db_connect.php';

include_once 'psl-config.php'; 

$error_msg = "";

 

if (isset($_POST['username'], $_POST['email'], $_POST['p'])) {

  // Sanear y validar los datos provistos.

  $username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

  $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);

  $email = filter_var($email, FILTER_VALIDATE_EMAIL);

Page 13: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 13/21

  if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {

  // No es un correo electrónico válido.

  $error_msg .= '<p class="error">The email address you entered is not va

  }

 

$password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);

  if (strlen($password) != 128) {

  // La contraseña con hash deberá ser de 128 caracteres.

  // De lo contrario, algo muy raro habrá sucedido.

$error_msg .= '<p class="error">Invalid password configuration.</p>';

  }

 

// La validez del nombre de usuario y de la contraseña ha sido verificada en el cliente.

  // Esto será suficiente, ya que nadie se beneficiará de 

  // violar estas reglas.

  // 

 

$prep_stmt = "SELECT id FROM members WHERE email = ? LIMIT 1";

  $stmt = $mysqli->prepare($prep_stmt);

 

// Verifica el correo electrónico existente.

if ($stmt) {

  $stmt->bind_param ('s', $email);

  $stmt->execute();

  $stmt->store_result();

 

if ($stmt->num_rows == 1) {

  // Ya existe otro usuario con este correo electrónico.

  $error_msg .= '<p class="error">A user with this email address alre$stmt->close();

  }

  $stmt->close();

  } else {

  $error_msg .= '<p class="error">Database error Line 39</p>';

  $stmt->close();

  }

 

// Verifica el nombre de usuario existente.

$prep_stmt = "SELECT id FROM members WHERE username = ? LIMIT 1";

  $stmt = $mysqli->prepare($prep_stmt);

 

if ($stmt) {

  $stmt->bind_param ('s', $username);

  $stmt->execute();

  $stmt->store_result();

 

if ($stmt->num_rows == 1) {

  // Ya existe otro usuario con este nombre de usuario.

  $error_msg .= '<p class="error">A user with this userna

$stmt->close();

  }

  $stmt->close();

  } else {

  $error_msg .= '<p class="error">Database error line 55</p>';

  $stmt->close();

  }

 

// Pendiente:

// También habrá que tener en cuenta la situación en la que el usuario no tenga

  // derechos para registrarse, al verificar qué tipo de usuario intenta

  // realizar la operación.

 

if (empty($error_msg)) {

  // Crear una sal aleatoria.

  //$random_salt = hash('sha512', uniqid(openssl_random_pseudo_bytes(16), TRUE)); // Did not work 

  $random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true)

 

// Crea una contraseña con sal.

$password = hash('sha512', $password . $random_salt);

 

// Inserta el nuevo usuario a la base de datos.

if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, ema$insert_stmt->bind_param ('ssss', $username, $email, $password, $ran

  // Ejecuta la consulta preparada.

  if (! $insert_stmt->execute()) {

  header('Location: ../error.php?err=Registration failure: INSERT

  }

  }

  header('Location: ./register_success.php');

  }

Page 14: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 14/21

}

Si no hay ningún dato POST provisto al formulario, se mostrará el formulario de registro.

El botón de envío del formulario llama a la función de JavaScript “regformhash()”. Esta

función realizará las verificaciones de validación necesarias y enviará el formulario

cuando todo sea correcto. Hablaremos de las funciones de JavaScript en la siguiente

sección.

Si existen datos POST, se realizarán algunas verificaciones del servidor para sanearlos

y validarlos. TEN PRESENTE que estas verificaciones no están culminadas hasta la

fecha. Algunos de los problemas se mencionan en los comentarios en el archivo. A la

fecha, solo verificamos que la dirección de correo electrónico tenga el formato correcto,

que la contraseña con hash tenga la extensión correcta y que el usuario no trate de

registrar un correo electrónico ya registrado.

Si todo es correcto, se registrará al nuevo usuario y se escribirá un registro nuevo en la

tabla de miembros.

Anuncio

1 Crea el archivo “sha512.js”.

Este archivo es una implementación en JavaScript del algoritmo hash sha512. Haremos

uso de la función hash para que las contraseñas no se envíen en texto simple.

Podrás descargar el archivo de pajhome.org.uk

(también se guardará en el repositorio de github).

Guarda tu copia de este archivo en un directorio titulado “js” en el directorio de raíz de la

aplicación.

2 Crea el archivo “forms.js”.

Este archivo, el cual deberás crear en el directorio “js”de la aplicación, se

encargará del hash de las contraseñas para los formularios de inicio de sesión

(formhash()) y de registro (regformhash()):

function formhash(form , password) {

  // Crea una entrada de elemento nuevo, esta será nuestro campo de contraseña con hash.

var p = document.createElement("input");

 

// Agrega el elemento nuevo a nuestro formulario.

Parte 6 de 8: Crear archivos de Javascript

Page 15: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 15/21

  form.appendChild(p);

  p.name = "p";

  p.type = "hidden";

  p.value = hex_sha512(password.value);

 

// Asegúrate de que la contraseña en texto simple no se envíe.

password.value = "";

 

// Finalmente envía el formulario.

form.submit();

}

 

function regformhash(form , uid, email, password, conf) {

  // Verifica que cada campo tenga un valor 

  if (uid.value == ''  || 

email.value == ''  || 

password.value == ''  || 

conf.value == '') {

 

alert('Deberá brindar toda la información solicitada. Por favor, intent

return false;

  }

 

// Verifica el nombre de usuario 

 

re = /^\w+$/ ; 

if(!re.test(form.username.value)) { 

alert("El nombre de usuario deberá contener solo letras, números y guio

form.username.focus();  return false; 

}

 

// Verifica que la contraseña tenga la extensión correcta (mín. 6 caracteres)

  // La verificación se duplica a continuación, pero se incluye para que el

  // usuario tenga una guía más específica.

  if (password.value.length < 6) {

  alert('La contraseña deberá tener al menos 6 caracteres. Por favor, int

form.password.focus();

  return false;

  }

 

// Por lo menos un número, una letra minúscula y una mayúscula

// Al menos 6 caracteres

 

var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/ ; 

if (!re.test(password.value)) {

  alert('Las contraseñas deberán contener al menos un número, una letra m

return false;

  }

 

// Verifica que la contraseña y la confirmación sean iguales

  if (password.value != conf.value) {

  alert('La contraseña y la confirmación no coinciden. Por favor, inténte

form.password.focus();

  return false;

  }

 

// Crea una entrada de elemento nuevo, esta será nuestro campo de contraseña con hash.

var p = document.createElement("input");

 

// Agrega el elemento nuevo a nuestro formulario.

form.appendChild(p);

  p.name = "p";

  p.type = "hidden";

  p.value = hex_sha512(password.value);

 

// Asegúrate de que la contraseña en texto simple no se envíe.

password.value = "";

  conf.value = "";

 

// Finalmente envía el formulario.

form.submit();  return true;

}

En ambos casos, JavaScript le pone un hash a la contraseña y la transfiere a los datos

POST al crear y rellenar un campo escondido.

Page 16: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 16/21

Anuncio

1 Crea el formulario de inicio de sesión (login.php).

Esta es una forma de HTML con dos campos de texto, titulados “correo electrónico” y

“contraseña”. El botón de envío del formulario llamará a la función de JavaScript

“formhash()”, la cual generará una contraseña con hash y enviará el contenido de

“correo electrónico” y “p” (contraseña con hash) al servidor. Deberás crear este archivo

en el directorio de raíz de la aplicación.

Al iniciar la sesión, lo más recomendable será utilizar algo que no sea público. En la

presente guía usaremos el correo electrónico como ID de inicio de sesión, pero el

nombre de usuario podrá utilizarse después para identificar al usuario. Si el correo

electrónico se oculta en alguna página dentro de la aplicación más amplia, se añadirá

otra variable desconocida para crackear las cuentas.

Nota: pese a que hemos encriptado la contraseña de modo que no se envíe en texto

simple, será vital que uses el protocolo HTTPS (TLS/SSL) a la hora de enviar las

contraseñas a un sistema de producción. No está por demás insistir en que

simplemente poner un hash a la contraseña será insuficiente. Podrías sufrir un ataque

“man-in-the-middle” que podría leer el hash enviado y usarlo para iniciar sesión.

<?php

include_once 'includes/db_connect.php';

include_once 'includes/functions.php';

 

sec_session_start();

 if (login_check($mysqli) == true) {

  $logged = 'in';

} else {

  $logged = 'out';

}

?>

<!DOCTYPE html>

<html>

  <head>

  <title>Secure Login: Log In</title>

  <link rel="stylesheet" href="styles/main.css" />

  <script type="text/JavaScript" src="js/sha512.js"></script>

<script type="text/JavaScript" src="js/forms.js"></script>

</head>

  <body>

  <?php

  if (isset($_GET['error'])) {

  echo '<p class="error">Error Logging In!</p>';

  }

  ?> 

<form action="includes/process_login.php" method="post" name="login_for

Correo electrónico: <input type="text" name="email" />

Parte 7 de 8: Crear páginas HTML

Page 17: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 17/21

  Contraseña: <input type="password"

name="password"

id="password"/>

  <input type="button"

value="Login"

onclick="formhash(this.form, this.form.password);" />

</form>

  <p> Si no tiene una cuenta, por favor<a href="register.php">regístrese.

  <p> Si ha terminado, por favor<a href="includes/logout.php">cierre la s

  <p>Está conectado.<?php echo $logged ?>.</p>

  </body>

</html>

2 Crea la página “register_success.php.

Crea una página web PHP nueva que lleve por nombre “register_success.php” en el

directorio raíz de la aplicación. Esta es la página a donde se le redireccionará al usuario

después de haberse registrado con éxito. Claro que podrás hacer esta página como

quieras o podrás redireccionarlo a otra página (o no). Dependerá de ti. Deberás ubicar

la página en el directorio raíz de la aplicación. La página actual “register_success.php”

que hemos escrito se ve así:

<!DOCTYPE html>

<html>

  <head>

  <meta charset="UTF-8">

  <title>Inicio de sesión segura: Registro exitoso</title>

  <link rel="stylesheet" href="styles/main.css" />

  </head>

  <body>

  <h1>¡Registro exitoso!</h1>

  <p>Ahora podrás regresar a<a href="index.php">la página de inicio de se

</body>

</html>

3 Crea la página de error.

Crea una página HTML nueva en el directorio raíz de la aplicación y ponle por nombre

“error.php”. Esta es la página a donde se le redireccionará al usuario en el caso de que

ocurra algún error durante el proceso de inicio de la sesión, de registro o cuando se

trate de establecer una sesión segura. El código a continuación simplemente mostrará

una página de error general. Tal vez necesites algo un poco más sofisticado. No

obstante, ten presente que todo lo que se agregue a la página se deberá filtrar

adecuadamente para protegerse contra posibles ataques XSS. El código de ejemplo de

la página es el siguiente:

<?php

$error = filter_input(INPUT_GET, 'err', $filter = FILTER_SANITIZE_STRING);

 

if (! $error) {

  $error = “Ocurrió un error desconocido”;

}

?>

<!DOCTYPE html><html>

  <head>

  <meta charset="UTF-8">

  <title>Secure Login: Error</title>

  <link rel="stylesheet" href="styles/main.css" />

  </head>

  <body>

  <h1>Hubo un problema.</h1>

Page 18: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 18/21

  <p class="error"><?php echo $error; ?></p>

</body>

</html>

Anuncio

1 Secuencia de comandos para la protección de páginas.

Uno de los problemas más comunes con los sistemas de autenticación es que el

desarrollador olvida verificar si el usuario está conectado. Será de suma importancia

que emplees el código a continuación en cada página protegida para verificar que el

usuario esté conectado. Asegúrate de emplear esta función.

// Agrega la conexión y las funciones de la base de datos aquí. Ver 3.1.

sec_session_start(); 

if(login_check($mysqli) == true) {

  // ¡Agrega el contenido de tu página protegida aquí!

} else { echo “No está autorizado para acceder a esta página. Por favor, inicie

}

Como ejemplo de lo que deberás hacer, hemos incluido una página protegida de

muestra. Crea un archivo con nombre “protected_page.php” en el directorio raíz de la

aplicación. El archivo deberá ser parecido a lo que mostraremos a continuación:

<?php

include_once 'includes/db_connect.php';

include_once 'includes/functions.php';

 sec_session_start();

?>

<!DOCTYPE html>

<html>

  <head>

  <meta charset="UTF-8">

  <title>Inicio de sesión segura: Página protegida</title>

  <link rel="stylesheet" href="styles/main.css" />

  </head>

  <body>

  <?php if (login_check($mysqli) == true) : ?>

  <p>¡Bienvenido, <?php echo htmlentities($_SESSION['username']); ?>!

  <p>

  Este es un ejemplo de página protegida. Para acceder a esta pá

deberán iniciar su sesión. En algún momento, también verificar

del usuario para que las páginas puedan determinar el tipo de u

autorizado para acceder a la página.

  </p>

  <p>Regresar a la<a href="index.php">página de inicio de sesión.</a>

  <?php else : ?>

  <p>

  <span class="error">No está autorizado para acceder a esta pági

Parte 8 de 8: Proteger páginas

Page 19: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 19/21

  </p>

  <?php endif; ?>

  </body>

</html>

Nuestra aplicación redireccionará al usuario a esta página tras haberse registrado con

éxito. Evidentemente, tu implementación no tendrá que ser igual.

Anuncio

Aléjate de la función md5 en los scripts de inicio de sesión, el algoritmo

hash md5 se considera inseguro.

Con muy pocos cambios en estos scripts de ejemplos podrás trabajar

con otros sistemas SQL, tales como SQLite o PostgreSQL.

Usa HTML y CSS para dar formato al formulario de acceso y de salida

de las páginas de tu agrado.

Si quieres usar un algoritmo hash diferente en lugar de sha512, prueba

Whirlpool. Evita usar Gost, sha1 (a menos que esté bien salado y tenga

varias iteraciones) y, como ya lo hemos mencionado, md5. Incentiva a

tus usuarios a crear contraseñas únicas, seguras, con letras

mayúsculas, minúsculas, números y símbolos. Considera la posibilidad

de pedirles a tus usuarios crear un nombre de inicio de sesión aparte

de su nombre de usuario para que sea más seguro.

Anuncio

Consejos

Page 20: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 20/21

La página de inicio y de registro deberán emplear HTTPS. Los scripts

del presente artículo no te obligan a hacerlo y, en realidad, sería más

fácil no hacerlo durante el desarrollo, pero no deberás usar estos

scripts en un ambiente de producción a menos que utilices HTTPS.

Asegúrate de que el usuario no pueda ver tus scripts PHP, lo cualpodría ocurrir debido a una configuración incorrecta del servidor. Existe

la posibilidad de que los usuarios recojan información acerca de tu

base de datos como los nombres y contraseñas si tu código PHP es

visible. Lo ideal sería que todas las secuencias de comandos incluidas

en otras secuencias o páginas estén ubicadas en un directorio fuera del

sistema de archivos del servidor y que se haga referencia a ellas con

un camino relativo, por ejemplo, agrega: “../../includes/myscript.inc.php”.

Nada es 100% seguro. Recuerda mantenerte al tanto de las últimas

noticias de seguridad para seguir mejorando la seguridad de tus scripts.

Esta secuencia de comandos anti fuerza bruta que bloquea la cuenta

de un usuario podría emplearse de manera errónea muy fácilmente. Te

recomendamos firmemente usar una técnica anti fuerza bruta como

CAPTCHA.

Te recomendamos usar un CAPTCHA en la página de inicio de sesión

para dificultar los ataques de fuerza bruta y DoS. El CAPTCHA deberá

aparecer en el formulario después de dos intentos de inicio de sesión

fallidos, aunque todavía no está implementado en el código de ejemplo.

Podrías conseguir una mejor solución con un marco como Zend 2,

Symfony o CakePHP. Todos estos marcos tienen arreglos para las

sesiones seguras y módulos de seguridad para ayudar con el proceso

de inicio de sesión. También, si utilizas un marco, probablemente veasque escribes mejores aplicaciones.

http://crackstation.net/hashing-security.htm Hash de contraseña

https://www.owasp.org/index.php/SQL_Injection Información sobre

inyección SQL

Categorías: Computadoras y electrónica

Otros idiomas:

English: Create a Secure Login Script in PHP and MySQL, Português: Criar um Script

de Login Seguro em PHP e MySQL, Italiano: Creare uno Script Sicuro per il Login

Usando PHP e MySQL, Deutsch: Ein sicheres Login Skript mit PHP und MySQL

erstellen, Français: créer un script de connexion sécurisée avec PHP et

MySQL, !"##$%&: #'()*+, -.('/*#01& 2'3%0 #$4%/+ 5 PHP % MySQL, Bahasa

Advertencias

Referencias

Acerca del artículo

Page 21: segura en mysql php

7/24/2019 segura en mysql php

http://slidepdf.com/reader/full/segura-en-mysql-php 21/21

Esta página se ha visitado 106 753 veces.

Indonesia: Membuat Skrip Log Masuk yang Aman di PHP dan MySQL