17

这是我在网站上控制身份验证的代码。我不确定我的逻辑是否正确。如果用户名和密码正确,则会发生以下情况:

if(session_start())
{
        session_regenerate_id(true);//without this the session ID will always be the same
        $_SESSION['loggedInUser'] = $uName;
        echo 'You are now logged in';
}
else echo 'Right password/username but session failed to start';

后续页面检查用户是否登录

session_start();
if(isset($_SESSION['loggedInUser'])
{
 //rest of page
}
else echo 'you must log in';

注销时我有

session_start();//if I don't have this the next line produces an error
session_unset();//destroys session variables
session_destroy();//ends session

我红色不在注销时调用 session_start() 但如果我没有它,我会收到消息Trying to destroy uninitialized session。我怎样才能解决这个问题?

是否建议根据 IP 地址和用户代理创建指纹?我认为这很糟糕,因为多台计算机可以共享相同的 IP 地址,例如计算机实验室,并且所有流量都通过代理,如果是动态的,同一台计算机可以更改其 IP 地址。另一方面,这种情况多久发生一次?阻止所有会话劫持可能是值得的。

即使您可以推荐信誉良好的文章,我也应该阅读以了解该主题,这将是很棒的,谢谢。

5/6 个答案的投票数少于 0 :( 可以否决选民评论,以便我知道要注意什么?

4

5 回答 5

28

首先,您应该阅读Mozilla WebAppSec 安全编码指南 - 会话管理OWASP A3-Broken Authentication and Session Management。您可以配置 PHP 的会话处理程序来满足这些要求。

您应该防止的第一个缺陷是A9-Insufficient Transport Layer Protection。简而言之,您不希望有人使用Firesheep 之类的工具劫持会话。可以通过强制浏览器仅通过 https 发送会话 id 来防止这种攻击:

session.cookie_secure=1

您可以通过设置httponly 标志来防止攻击者使用 XSS 获取会话 ID :

session.cookie_httponly=1

总是希望使用 cookie 来存储您的会话 ID。如果会话 ID 可以使用 GET 或 POST 变量传递,那么攻击者可以使用会话固定攻击来劫持会话。考虑这种攻击的另一种方式是,您不希望攻击者为另一个用户创建会话:

session.use_cookies=1
session.use_only_cookies=1

接下来,您要确保从 CSPRNG 中获得至少 128 位的熵。在 *nix 系统下,您可以使用/dev/urandom

session.entropy_file="/dev/urandom"
session.entropy_length=16

会话处理程序不是一切。您仍然需要担心跨站点请求伪造攻击(又名 CSRF 或“会话骑行”)和跨站点脚本 (XSS)。XSS 可用于破坏 CSRF 保护(即使使用 http_only cookie!)。 攻击者也可以使用点击劫持来执行未经授权的操作

设置这些配置选项后,只需调用session_start(). 至于session_destroy()在用户注销时销毁会话调用,就这么简单!

于 2013-03-24T07:13:08.333 回答
1

为了安全地销毁会话,我将使用以下代码:

session_start();
// Unset all session values
$_SESSION = array();
// get session parameters 
$params = session_get_cookie_params();
// Delete the actual cookie.
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
// Destroy session
session_destroy();

为了销毁会话,您需要先启动它,因为您发现如果不包含 session_start(); 它就不起作用;

session_regenerate_id(); 函数为用户生成一个新的会话 ID。如果与 true (session_regenerate_id(true);) 一起使用,则在生成新会话 ID 时,旧会话 ID 将从服务器中删除。在每个页面上生成新会话 ID 的原因是,由于用户不断更改会话 ID,它使会话劫持更​​难(几乎不可能?)执行。

(在session_regenerate_id();上查看 PHP.net 手册)

在对用户进行身份验证时,您应该始终检查 IP 地址或浏览器之类的内容,这些是在请求中发送到服务器的持续内容,在会话的生命周期内不会改变,如果他们这样做了,那么您就知道它正在发生一些狡猾的事情. 我总是创建两个会话变量,一个存储用户 ID,以便我可以查询数据库中的数据,另一个将用户密码、IP 地址和浏览器字符串存储在一个哈希 (sha512) 中。

$user_id = $_SESSION['user_id'];
$login_string = $_SESSION['login_string'];

// Query Database and get hashed password

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

if($login_check == $login_string) {
     // Logged In!!!!
     return true;
} else {
     // Not logged in
     return false;
}

密码是安全的,即使它存储在会话中。这是因为密码被散列(在这种情况下是两次),并且因为会话数据没有存储在用户计算机上(如 cookie),它存储在会话文件中。

我在 wikihow.com 上写了一篇关于安全登录和身份验证的文章,可以在这里找到。

于 2013-03-19T22:19:29.910 回答
0

你可以写:

session_start(); // session should be started before it can be used.

您可以分配登录成员的用户 ID。为此,您可以从用户输入中获取用户名和密码,并在您的数据库中检查并返回用户 ID。为了提高安全性,您可以使用字符串,例如。“演示”和“测试”都只是 md5,并以下列方式将其与用户 ID 混合。

$userid=md5("demo").$userid.md5("test");// you can set any string instead of demo and test.

$_SESSION['userid']=$userid;

在其他页面使用时,

session_start(); // If you are have not started it or included above code file in it.

正如您在使用时知道的字符串,只需匹配它并从中找到确切的用户 ID 并在您的代码中使用它。

要销毁它,只需使用:

session_unset($_SESSION['userid']); // It will only unset the session userid completely. 

确保在使用任何会话之前您需要启动它。以更好的方式,您可以在一个文件中启动会话,例如 init.php 并将其包含在您要使用会话的每个位置

于 2013-03-22T11:25:26.240 回答
0

您可以先使用session_id()来确定用户是否已经获得了会话,如果没有,则使用session_start().

来自 Lithium 框架的示例代码:

/**
 * Starts the session.
 *
 * @return boolean True if session successfully started (or has already been started),
 *         false otherwise.
 */
protected static function _start() {
    if (session_id()) {
        return true;
    }
    ...
    return session_start();
}

通话后_start(),您可以放心通话session_destroy()

于 2013-03-25T08:59:42.480 回答
0

要在不使用“start_session()”的情况下销毁会话,首先验证是否存在不如下所示的活动会话

$existingSessionId = session_id();
if ($existingSessionId != "")
{
     // Initialize the session.
     session_start();

     // Unset all of the session variables.
     $_SESSION = array();

     // If it's desired to kill the session, also delete the session cookie.
     // Note: This will destroy the session, and not just the session data!
     if (ini_get("session.use_cookies")) {
         $params = session_get_cookie_params();
         setcookie(session_name(), '', time() - 42000,
             $params["path"], $params["domain"],
             $params["secure"], $params["httponly"]
         );
     }

     // Finally, destroy the session.
     session_destroy();
}
else
{
     // No Active sessions
}

session_regenerate_id(true),只是用新的会话ID替换旧的会话ID,但它不会取消设置旧的会话ID。session_destroy 和删除会话 cookie 需要注意这一点。

一旦会话被破坏,浏览器就会向服务器发送会话 cookie。PHP 将获取此会话 ID,当您执行 start_session() 时,它将使用浏览器发送的会话 ID。如果您删除会话 cookie,session_start 将生成一个新的会话 id,您无需调用 session_regenerate_id()

于 2013-03-25T13:08:56.153 回答