其他金融平台中不同Google Payoneer平台的安全系统访问分析。
在以下分析中,我发现了这些特征:
- 在第一次失败的尝试中,它会显示验证码。
- 5 次尝试后,用户的帐户将被锁定 15 分钟。
- 当您有权访问是否存在故障历史时,您必须回答安全问题才能继续。
- 不允许双重记录。
其他参考: 创建安全登录脚本
我已经设法修复了我的旧代码。
注意:请编辑我的问题以避免可能的重复问题。
更正:
它将ip
继续被阻止,它不会影响任何事情,因为被阻止ip
只会显示验证码。
我创建了一个新的fail_attempt表,其中包含以下列:类似于我的想法。
id_fail_attempt id_user attempt ip datetime time
1 1 5 ::1 2017-08-23 17:57:46 2017-08-23 18:12:46
下表login_attempts
列出了失败的尝试ip
id ip attempts datetime
1 ::1 2 2017-08-23 17:57:46
董事会users
id username email password lastname active
1 Hola hola@ Hola Hola 1
如何在表fail_attempt
中插入id
用户、失败的尝试、ip
用户将被阻止访问的时间以及如何控制同一用户在同一系统中的双重登录。
完整的 PHP 代码
如何添加新功能并创建安全系统?
登录.php
<?php
session_start();
$message="";
$captcha = true;
//
$con = @new mysqli('localhost', 'root', '', 'systemuser');
if(count($_POST)>0 && isset($_POST["vcode"]) && $_POST["vcode"]!=$_SESSION["vcode"]) {
$captcha = false;
$message = "Los caracteres escritos no coinciden con la palabra de verificación. Inténtalo de nuevo.";
}
$ip = $_SERVER['REMOTE_ADDR'];
//Bloqueamos la ip por un día
$result = mysqli_query($con,"SELECT * FROM failed_login WHERE ip='$ip' AND date BETWEEN DATE_SUB( NOW() , INTERVAL 1 DAY ) AND NOW()");
$row = mysqli_fetch_assoc($result);
//Obtenemos datos para comprar intentos y para resetear intentos por su ultimo fecha.
$failed_login_attempt = mysqli_real_escape_string($con,$row['attempts']);
//Liberamos memoria.
mysqli_free_result($result);
if(count($_POST)>0 && $captcha == true) {
$username = mysqli_real_escape_string($con, $_POST["username"]);
$password = mysqli_real_escape_string($con, $_POST["password"]);
$username = htmlentities($username);
$password = htmlentities($password);
$save_passw = sha1($password);
$sql = "SELECT * fROM users where username='$username' AND password='$save_passw' AND active='1' ";
$query = mysqli_query($con, $sql);
$rowU = mysqli_fetch_assoc($query);
$UsernamaDB = mysqli_real_escape_string($con, $rowU["username"]);
$passwordDB = mysqli_real_escape_string($con, $rowU["password"]);
if($failed_login_attempt <1) {
//Si es su primer intento fallido, incluimos el primer registro en la BD
$con->query("INSERT INTO failed_login (ip,attempts,date) VALUES ('$ip', 1, NOW())");
} else {
if($failed_login_attempt <2){
//En caso de ya estar en la BD, sacamos el valor y agregamos +1
$contador = $row['attempts'] + 1;
$con->query("UPDATE failed_login SET attempts='$contador', date=NOW() WHERE ip = '$ip'");
}
}
if (empty($_POST) === false) {
$username = $_POST['username']; $password = $_POST['password'];
if (empty($username) === true || empty($password) === true) {
$message = "Es necesario introducir un nombre de usuario y contraseña";
} elseif ($username != $UsernamaDB) {
$message = "El 'Usuario' que has introducido no coincide. ";
} elseif ($save_passw != $passwordDB) {
$message = "Tu 'Contraseña' introducido no coincide. ";
} elseif($save_passw == $passwordDB && $username == $UsernamaDB) {
$_SESSION["id_user"] = 1;
$con->query("DELETE FROM login_attempts WHERE ip = '$ip'");
}
}
}
if(isset($_SESSION["id_user"])) {
header("Location:http://localhost/index.php");
}
?>
<h1><?php if($message!="") { echo $message; } ?></h1>
<form name="frmUser" method="post" action="">
<input type="text" name="username" placeholder="Usuario">
<input type="password" name="password" placeholder="Contraseña">
<!-- captcha-->
<?php if (isset($failed_login_attempt) && $failed_login_attempt >= 1) { ?>
<br><img src="image.php" id="phoca-captcha"/>
<input name="vcode" type="text" placeholder="Codigo captcha">
<?php } ?>
<!-- fin-->
<input type="submit" value="Iniciar sesión" id="button-login">
</form>
Desde mi punto de vista ante todo debes proteger su Base de datos ante posibles ataques de inyección, piensa, para que sirve crear un sistema de login avanzado si después uno podría modificar fácilmente su Base de datos. Para ello podrías usar mysqli::prepare o PDO.
Si quieres saber más como evitar la inyección SQL, te dejo esta pregunta con grandes respuestas en SOes.
En mi ejemplo utilizo
mysqli::prepare
, el principal y más esencial beneficio de las declaraciones preparadas es la eliminación de todos los peligros del formato manual.Otro factor importante es el almacenaje de contraseñas seguras. En mi ejemplo utilizo password_verify, para comprobar si la contraseña conciden, importante, cuando registras un nuevo usuario utiliza la función password_hash() para crear un hash de contraseña seguro (No utilice
sha1
omd5
, ya que son vulnerables).Mas información sobre Almacenamiento de contraseñas PHP y MYSQL en SOes.
Ejemplo crear un hash de contraseña:
Ejemplo completo:
Voy a poner un posible ejemplo a tus deseos.
Desde mi punto de vista al primer intento mostrar el código captcha, podría ser incomodo, ya que un usuario se equivoca fácilmente en el primer intento, vamos a poner en el 3 intento, aunque este valor se podría modificar como uno desea en realidad.
Compuse el sistema basándome en los siguientes puntos (probado en localhost):
login_Attempts
, se bloquea el login durante 1 día por IP.Lo del doble logueo, personalmente no lo veo cómodo para los usuarios, siempre hay que mirar la comodidad del usuario y en ocasiones depende la aplicación es más cómodo trabajar con dos sesiones abiertas en diferentes ordenadores, piensa que si uno realmente quiere podría también fácilmente, grabar la pantalla de su aplicación y dárselo a terceros XD.
Base de datos
index.php
conexion.php (Estilo orientado a objetos).
login.php
En mi ejemplo he usado en vede usuario el correo electrónico para iniciar sesión, ya que es unique como un usuario, aunque este valor es fácilmente modificable por usuario si uno desea.
login_control.php
captcha_code.php
logout.php
RAIZ
font / SpecialElite.ttf (font)
img / captcha.png (dimensiones: 250x60 pixeles)
captcha_code.php
conect.php
index.php
login.php
login_control.php
logout.php
你应该做的是
login_attempts
中的属性ip
改为user_id
或username
(不重复的情况下)以用户而不是IP建立关系。$result5
以获取user_id
正在建立连接的数据。login_attempts
属性中删除time
或在非常遥远的日期将其与锁一起分配。$message
它应该在遇到 5 个错误时显示联系管理员消息,然后才能显示失败的次数。我认为解决此类问题的最佳方法是使用一个能够具有最小抽象的类。
我将向您展示一个基本示例,尽量不要使其过于复杂,以便您可以轻松理解代码,快速完成,因此它有一些缺点。
该类允许我们:
拒绝访问和阻止访问是在不考虑 IP 的情况下对用户执行的,这并不意味着不能为此目的实施方法。
我们的数据库中应该有以下表:
用户
登录日志
我们为连接数据库创建一个基本类
类连接
登录控制器类
类的基本使用
Hola te comento como tenemos nosotros securizado un sistema que gestiona contenido de video premium y evitar el doble uso así como el uso ilegítimo.
Tablas:
Esta tabla reigstramos los diferentes usuarios, fecha de alta, fecha de modificación de password, etc.
Esta tabla la utilizamos para gestionar los fallos erróneos de login, guardamos los datos que ha enviado en el formulario, asociamos a un usuario si es posible, en nuestro caso utilizamos Cloudflare que nos provee un rico ID de usuario bastante acertado, y poco evitable, jeje, y para prevenir los logins incorrectos utilizamos estos datos, así como el user agent y los session id en vez de la ip. Nosotros utilizamos validación escalada, es decir vamos reduciendo factores para bloquear al usuario dependiendo del nº de intentos.
En esta tabla almacenamos las diferentes sesiones así como su estado, llamamos sesión al momento que el usuario hace login y es ok, primero verificamos que no haya sesiones activas, comparando el date de Fin para ver si está cerrada o no. En nuestro caso tenemos una opción para comprar una suscripción con acceso hasta 5 dispositivos, en este caso el número máximo de sessiones es de 5.
Dentro de nuestra plataforma al ser retransmisión en streaming se hacen peticiones continuas con lo que las sesiones con mas de 120 segundos desde el momento actual se entienden como cerradas
Otros sistemas de protección activa
Adicionalmente a lo anterior disponemos de varios sistemas de seguridad activa para prevenir usos no autorizados o compartición de cuentas.
Seguimiento de dispositivos.
Utilizando el user Agent y el proveedor de la IP (Movistar, Orange, Vodafone, etc) hemos creado una tabla devices que les asignamos a un usuario, de tal manera que cuando accede desde un dispositivo que anteriormente no ha accedido solicitamos una doble verificación del usuario. Otra funcionalidad es que no pueda acceder desde otros dispositivos. El asunto del proveedor de servicios aún está en pruebas pero apunta maneras XD Aquí también se ha planteado utilizar la resolución dela pantalla, ya que habitualmente vemos las series y películas en pantalla completa, pero aún estamos en pruebas.
Doble factor de autentificación
Para cosas "raras" cambio de password, cambio de email, nuevos dispositivos, ip de comunidad distinta, etc solicitamos una doble autentificación, bien por email, authy, SMS, llamada, etc.
Uso de WAF
No tengo acciones de Cloudflare, aunque me gustaría, pero en mi concepto de ciberseguridad es fundamental.
Por último te diría que la ciberseguridad hoy en día es fundamental en cualquier proyecto, por lo que debería ser gestionada y supervisada por una empresa especializada en este ámbito.
He realizado ajustes a tu código implementado lo que solicitas:
La cantidad de intentos esta en una variable así podrás ajustarlo. Si no quieres que bloquee la IP podrias ponerle a la variable
$intentosIP
= 1000 por ejemplo, o ajustar el codigo :)Me gustaría aclarar que para realizar esto hay muchas formas, frameworks, librerías, patrones, etc. Me he limitado a seguir el estilo de tu código y he trabajado sobre ello, pero queda la recomendación de usar por ejemplo Programación Orientada a Objetos, evitar Inyección SQL, etc.
Base de Datos Se mantuvo la Base de Datos publicada, solo a la tabla
users
se le agrego el campologindatetime
de tipodatetime
que servira para validar el doble logueo.fail_attempt
login_attempts
users
"4e46dc0969e6621f2d61d2228e3cd91b75cd9edc" es "Hola" en
sha1
, al loguerase solo escribir "Hola", PHP lo convertira en sha1 para la comparacion con BD.Cada vez que se agregue un usuario usar la funcion
sha1
, ejemplo:Doble logueo
Usara el campo
logindatetime
de la tablausers
. Cuando el usuario se loguea es redireccionado a la paginaindex.php
(codigo original).En la pagina index.php se invoca un
ajax
que actualiza el campologindatetime
para saber que el usuario ha sido logueado satisfactoriamente. Tambien hay un botonCerrar Sesion
que limpia el campologindatetime
, de modo que cuando el campo esta NULL sabemos que el usuario ya no esta logueado.Para el caso que el usuario cierre el navegador sin antes usar el boton
Cerrar Sesion
, ha considerado invocar alajax
cada 1 minuto. De modo que silogindatetime
tiene una hora de mas de 2 minutos se entenderia que fue una sesion abandonada y se consideraria como que el usuario ya no esta logueado.Solucion
Para correr este codigo, los archivos den estar dentro de una carpeta
login
captcha.php Para generar dinamicamente la imagen captcha
requiere de esta imagen
login.php Codigo publicado reajustado
index.php Pagina de Bienvenida, luego del login.
logueado.php Actualizara el campo
logindatetime
y cerrara sesionCaptura
Podrían surgir mas casos de uso o validaciones que ajustarían mas el código. Si tienes dudas, conversamos por lo comentarios.
实际上阻止 IP 并不是一个好主意,因为 99% 的用户都有动态 IP,只有重新启动路由器才能让我获得新的 IP。
一种选择是执行更具体的控制,但实施需要分析,因为与任何系统一样;越复杂,就越容易出错,维护成本也越高。
用户状态
执行登录时,用户可以将在线状态保存在基础中,并且当状态存在时,没有其他人可以连接到系统。它会在几分钟后刷新,而无需用户在网站上进行交互或在注销时。
活动分析
您可以为每个用户实施一个活动表,其中注册了他们连接到系统的 IP 和 GEOlocation,您必须从中生成报告并分析或购买执行此类分析的系统。
双重认证登录
有多种实现方式,例如带有一系列数字的令牌,您必须输入这些数字,这些可以通过电子邮件、APP 或短信发送。
社会工程学
通过 Facebook/Instagram/Linekdin/etc 帐户链接访问您的平台。这种与社交网络的联系减少了共享帐户的可能性。
根据系统的重要性和范围,这些安全项目不再是保护公司和客户的可选项目。