如何以更安全的方式检查 PHP 会话


How can I check PHP Session in a more secure way?

我目前有一个PHP登录系统,它通过验证用户输入的组织代码来登录,因此查询的数据库会有所不同。

includes.php

<?php
mysql_connect("mysql.example.com", $dbconn, "MySecurePassword");
mysql_select_db($dbconn);
?>

login.php

// $org is the Organisation Code, will be set when user clicks Login
$dbconn = $org;
include "includes.php";
// Omitted the $userid & $pw variables, assume there is no error, and that MySQL Injection is prevented already
    $query = "SELECT * FROM `Login` WHERE `userid`=TRIM('$userid') AND `password`=TRIM('$pw' )";
    $result = mysql_query($query);
    if(mysql_num_rows($result)>0){
        session_start();
        $_SESSION['logged_in'] = $username;
        header("Location: loggedinpage.php");
    }

loggedinpage.php

<?php
session_start(); 
// As there is no fixed database, I've omitted the DB Connection
 define('DS',  TRUE); // used to protect includes
 define('USERNAME', $_SESSION['logged_in']);
 define('SELF',  $_SERVER['PHP_SELF'] );
// Checks if user is logged in
 if (!USERNAME) {
     header("Location: login.php");
}
?>

采取的安全措施

  • 密码使用 SHA-512 进行哈希处理,不以明文形式存储。

  • 使用 mysql_real_escape_string() 阻止 MySQL 注入

为了便于阅读,我省略了一些代码,我可以知道这种检查用户是否登录的方式是否安全吗?如果没有,我该如何改进它?

提前感谢!

    更新
  • 了问题以反映评论中的更新

假设您的查询按预期工作,并且仅在匹配完全正确时才返回一行(例如,通过排序规则没有奇怪的模糊匹配,而是纯粹的bin比较(,身份验证部分几乎没问题。

(你已经被警告过很多SQL注入,你在那里靠自己。

然后,您的安全性归结为:

$_SESSION['logged_in'] = $username;

以及随后的:

define('USERNAME', $_SESSION['logged_in']);
if (!USERNAME) {
    header("Location: login.php");
}

我想你的问题是关于这部分的。
那么答案是:会话部分没问题,阻塞部分不行。

这就是会话的使用方式,是的,默认情况下它们是相当安全的;用户将无法以某种方式自己设置$_SESSION['logged_in']值,该值只能由您的服务器设置,并且可能您只有在成功进行身份验证时才这样做。请阅读有关会话劫持的信息,这是整个计划唯一真正的漏洞。

真正的问题是:

if (!USERNAME) {
    header("Location: login.php");
}

设置页眉不会终止当前页面。如果您在此行之后输出敏感信息,它将被发送给客户端!您需要在设置标头后显式exit

说了这么多,我们无法告诉您您的系统是否"安全",因为您可能创建了我们没有看到的任意数量的 facepalm 后门。一般来说,我会从以下内容开始:

  • 停止使用mysql,使用PDOmysqli
  • 绑定你的参数,不要mysql_real_escape_string它们;那里有安全陷阱
  • 使用password_hash密码哈希,而不是 SHA;特别是如果您只执行一次 SHA 传递
小心

SQL注入:

如果您在密码字段中输入:

 ''='' 
密码

的规则将为真,因为密码 = TRIM(''='( 为真。您必须控制密码的字符串:

  • 最小长度
  • 没有空格(得益于修剪功能(

而且您不必像这样存储密码,您必须创建密码的哈希