这种用户身份验证方法有哪些缺点?

时间:2010-03-22 08:09:23

标签: php mysql security session

我正在开发自己的PHP框架。似乎我读过的所有安全文章都使用了与我不同的用户身份验证方法,因此我可以使用一些帮助来查找安全漏洞。

在我开始之前可能有用的一些信息。我使用mod_rewrite作为我的MVC网址。密码使用每个用户独有的24字符盐加密。 mysql_real_escape_string和/或变量类型转换所有内容,以及htmlspecialchars中的所有内容。

分步过程:

每页顶部:

session_start();
session_regenerate_id();

如果用户通过登录表单登录,则生成新的随机令牌以放入用户的MySQL行。哈希是根据用户的盐(从他们第一次注册时)和新令牌生成的。将哈希和明文用户名存储在会话变量中,如果选中“记住我”,则在cookie中复制。

在每个页面上,检查Cookie。如果设置了cookie,则将其值复制到会话变量中。然后将$ _SESSION ['name']和$ _SESSION ['hash']与MySQL数据库进行比较。如果它们不匹配,则销毁所有cookie和会话变量,以便它们必须再次登录。

如果登录有效,则MySQL数据库中的一些用户信息将存储在阵列中以便于访问。到目前为止,我假设这个数组是干净的,所以当限制用户访问时,我会引用user.rank并拒绝访问,如果它低于该页面所需的内容。

我试图测试像XSS和CSRF这样的所有常见攻击,但也许我只是不善于攻击我自己的网站!我的系统似乎太简单了,实际上并不安全(安全代码只有100行)。我错过了什么?

编辑:为了从控制器调用函数,除了用户等级要求之外,任何使用除SELECT查询以外的任何内容的东西都需要$ _POST数据来确认删除。

我也花了很多时间用mysql_real_escape字符串搜索漏洞,但我还没有找到任何最新的信息(一切都是几年前至少已经修复过的)。我所知道的是问题与编码有关。如果今天仍然存在这个问题,我该如何避免呢?

我从某处借来的加密函数并进行了修改:

public function encrypt($str, $salt = NULL) {
    if ($salt == NULL) $salt = substr(md5(uniqid(rand(), true)), 0, 24);
    else $salt = substr($salt, 0, 24);
    return $salt.sha1($salt.$str);
}

6 个答案:

答案 0 :(得分:4)

帮自己一个忙,并使用标准库来散列密码。

因为安全性往往要复杂得多,并且比大多数程序员单独解决的问题更加隐形,所以使用标准库几乎总是最简单,最安全(如果不是唯一的)可用选项。

标准库
请查看:Portable PHP password hashing framework phpass ,并确保尽可能使用CRYPT_BLOWFISH算法。

使用phpass(v0.2)的代码示例:

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass已在一些众所周知的项目中实施:

  • 。中文
  • WordPress 2.5+以及bbPress
  • Drupal 7发布,(可用于Drupal 5& 6的模块)
  • others

好消息是你不需要担心细节,这些细节是由有经验的人编制的,并且已经被互联网上的许多人评论过。

无论你做什么,如果你去'我会自己做,谢谢'方法,不再使用MD5 。这是一个很好的散列算法,但出于安全目的完全破坏了

目前,使用crypt和CRYPT_BLOWFISH是最佳做法 PHP中的CRYPT_BLOWFISH是Bcrypt哈希的实现。 Bcrypt基于Blowfish分组密码,利用它昂贵的密钥设置来减慢算法速度。

有关密码存储方案的更多信息,您还可以阅读Jeff关于它的博文:You're Probably Storing Passwords Incorrectly

答案 1 :(得分:2)

我认为没有任何真正的CSRF攻击预防措施。 CSRF(根据我的理解)是网站中最常被忽视/搞砸的漏洞。许多大家伙都是通过CSRF漏洞被黑客攻击的。

目前解决此问题的最佳方法是使用synchronizer tokens.

你最好还是非常虔诚地转义/编码用户输入。插入到数据库中的东西必须被转义,输出回用户的东西必须根据它们的上下文进行编码:CSS,HTML,JavaScript等都必须以不同的方式编码。

此外,您不应将SHA-1与MD5结合使用。虽然SHA-1比MD5更强,但通过将它与MD5结合起来,你实际上在削弱它。此外,建议不要将这些算法用于新应用程序。暂时你应该使用SHA-256(它在PHP中是开箱即用的)。

答案 2 :(得分:2)

通过尝试过度设计这种方法,您可能会破坏安全性。

您使用的会话处理程序是什么?您是否检查过session_regenerate_id()是否重命名现有会话而不是复制它?如果是后者,那么你创建了很多会话文件,通过随机搜索更容易找到。

您如何处理用户拆分会话?这行代码将根据浏览器以及用户如何拆分会话而中断。

您应该使用session_regenerate_id()的唯一地方是您对用户进行身份验证以及用户何时注销。

  

mysql_real_escape_string和/或对

中的所有内容进行变量类型转换

不,不,不。这一直在这里。

您不会更改传入数据的表示形式。无论如何/验证/输入,你应该总是/消毒/输出 - 你没有/消毒/输入。

  

如果用户通过登录表单登录,则生成新的随机令牌以放入用户的MySQL行。哈希是根据用户的盐(从他们第一次注册时)和新令牌生成的。将哈希和纯文本用户名存储在会话变量

这里没有什么可以提高您的安全性

  

将哈希和纯文本用户名存储在会话变量中,如果选中“记住我”,则将其复制到Cookie中

因此,您将明文密码存储在用户计算机上!这是所以不安全。如果你想要记住我的功能,那么用盐加密密码和有效期并存储。

  

在每个页面上,检查Cookie。如果设置了cookie,则将其值复制到会话变量中。

因此,用户可以通过返回具有相同名称的cookie来操纵会话中存储的任何值吗?好的,所以他们可能无法预测哈希,因此伪造用户会很棘手 - 但是还有很多其他方法可以用来危害你的系统。

你已经非常努力地使你的系统安全 - 但最好你所做的一切都是对系统中正常工作的部分进行模糊处理。

下进行。

答案 3 :(得分:0)

带有session_regenerate_id()的

;你将使浏览器中的“后退”按钮无法使用。但仍然与“记住我”功能相结合它变得毫无用处。
我在你的描述中看不到CSRF防御 mysql_real_escape字符串

没有一个问题

答案 4 :(得分:0)

您可能需要针对白名单检查user.rank,以确保该值存在于查找表中且有效(活动,未删除等),并且还强制进行类型转换和范围。

对于令牌,您需要为每个希望从表单接收GET / POST数据的页面生成新令牌。如果会话被劫持,则会话的令牌可能不足。为会话设置较短的超时可能会缓解。

不要立即信任cookie中的任何内容,请考虑在存储会话之前使用http://php.net/manual/en/book.filter.php

如果您计划拥有系统的管理面板,那么理想的情况是强制执行密码强度,手动管理员登录名选择(优先考虑设置时的管理员/密码库存登录)。

将通常的登录名列入黑名单,例如“a'; DROP DATABASE ...”和“管理员”,您知道该演习。

在设置数据库时使用最少权限帐户,您不希望访问者对您的表造成严重破坏。

答案 5 :(得分:0)

“密码是sha1和md5加密”

为什么需要使用两个哈希函数?我猜你是因为缺乏理解而做到的(没有冒犯!)。你应该阅读this article on secure password schemes(提示:使用bcrypt)。

相关问题