2013-03-19 88 views
16

这是我的代码来控制网站上的身份验证。我不确定我的逻辑是否正确。如果用户名和密码是否正确下面发生了:安全地创建和销毁PHP中的登录会话

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 :(选民可能下降发表评论,所以我知道看出来

+0

。 destroy.php)'只对不使用$ _SESSION'的较旧的不推荐使用的代码使用session_unset() – bitWorking

+0

只要可能,您应该重新使用现有的身份验证框架,因为它确实很复杂。例如,看看https://github.com/delight-im/PHP-Auth – caw

回答

24

首先你应该阅读Mozilla WebAppSec Security Coding Guideline - Session ManagementOWASP A3-Broken Authentication and Session Management。您可以通过configure PHP's session handler来满足这些要求。

您应该防止的第一个缺陷是A9-Insufficient Transport Layer Protection。总之,你不希望有人使用a tool like Firesheep劫持会话。这种攻击可以通过强制浏览器只发送通过https会话ID防止:

session.cookie_secure=1 

您可以通过设置httponly flag防止攻击者获得使用XSS会话ID:

session.cookie_httponly=1 

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

session.use_cookies=1 
session.use_only_cookies=1 

接下来,你要确保你有熵ATLEAST 128位来自CSPRNG。在* nix系统你可以使用/dev/urandom

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

会话处理器并不代表一切。您仍然需要担心Cross-Site Request Forgery attacks(又名CSRF或“会话骑马”)和跨站点脚本(XSS)。 XSS可以用来击败CSRF保护(即使使用http_only cookie也是如此!)。 Clickjacking也可以被攻击者用来执行未经授权的操作。

设置完这些配置选项后,请致电session_start()。至于销毁用户注销时的会话呼叫session_destroy(),那简单!

+0

跨站请求伪造并不依赖会话,因为“会话骑马”可能会提示。但是,具有认证会话的用户比“匿名”用户更有价值。同样适用于点击劫持。 – Gumbo

+0

@Rook:我想强调你的最后一段! PHP中的会话很简单。始终假定已经存在会话cookie并存储了会话数据。刚开始会话。然后查看$ _SESSION并查看是否有任何成功登录的痕迹。进行会话应该在安全级别上没有任何意义。它不能证明用户已登录。只有存储的会话数据可以执行此操作。 – Sven

+0

@Gumbo:该方法不依赖于会话,但CSRF在实现此验证方法的情况下依赖于会话。因为,正如您已经说过的那样,需要经过身份验证的用户才能使用特定的URL执行请求/操作。 (只是为了让TS清楚)。 –

0

什么安全销毁会话我会用下面的代码:

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);)一起使用,则t他会生成一个新的旧会话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上写了一篇关于安全登录和认证的文章,可以找到here

0

你可以这样写:

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

您可以指定的登录会员用户ID。为此,您可以从用户输入中获取用户名和密码,并在您的数据库中检查并返回用户ID。为了更安全,你可以为例如字符串。 “demo”和“test”只是md5,并按照以下方式与userid混合使用。

$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,包括它的每一个地方,你要使用的会话

+2

为什么会话数据中的md5内容?这只会扩大数据从硬盘到硬盘,但是由于会话内容不会暴露给外部世界,它根本不会增加任何安全性。这只会让事情变得复杂。 – Sven

0

您可以先使用session_id()来确定用户是否已获得会话,如果没有,则使用session_start()。从锂framewrok

例如代码:

/** 
* 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()

+1

欢迎来到SO。这个问题有一个安全标签,答案应该是安全特定的。 – rook

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,并且您不需要从[php.net](http://php.net/manual/en/function.session-)中调用session_regenerate_id()

+0

所以你的代码被用来销毁会话?这是目的吗?为什么要麻烦检查一下会议是否存在,如果你正要毁掉它? – Celeritas

+1

为了使用session_destroy(),你需要先发出session_start(),否则会引发错误。根据session_destroy文档“session_destroy()销毁与当前会话关联的所有数据,它不会取消设置与会话相关联的任何全局变量,或取消设置会话cookie 为了完全消除会话,要将用户登录出去,还必须取消设置会话ID。如果使用cookie传播会话ID,则必须删除会话cookie。“ – Amit

+0

好的感谢解释。还有一个问题,'time() - 42000'是做什么的? – Celeritas