php安全性令牌_现代PHP中的密码安全性

php安全性令牌

PHP从一开始就是一种用于构建网站的编程语言。 这个想法比任何其他编程语言都更深入地存在于PHP的核心中,这也许就是PHP在构建Web应用程序后变得如此流行的原因之一。 但是,在1990年代中期首次制作PHP时, Web应用程序一词甚至还不存在。 因此,密码保护不是PHP创建者投入资源的功能之一。 毕竟,当您使用PHP只是在网站上放置一个站点访问计数器或一个日期已修改的戳记时,您不必担心密码。

但是20年过去了,现在创建一个不包含受密码保护的用户帐户的Web应用程序几乎是不可想象的。 PHP程序员使用最新和最安全的方法来保护帐户密码是至关重要的。 为此,PHP 5.5添加了由Anthony Ferrara( @ircmaxell )创建的新的密码哈希库。 该库提供了几种可用的功能,您可以使用这些功能以当前的最佳实践方法来处理单向密码加密。 其他功能可以满足未来的安全需求,因此随着计算机和黑客的发展,您可以领先于坏人。 本文为您提供了有关库函数以及如何充分利用它们的深入介绍。

安全哈希的重要性

像牙刷一样对待您的密码。 不要让其他人使用它,并且每六个月换一个新的。

克利福德·斯托尔

这可能不用说(至少我希望如此):切勿将用户密码存储为纯文本。 始终使用单向加密算法(例如哈希算法)存储密码的加密版本,以使任何有权访问您的帐户数据库的人都无法发现您的用户密码。 此警告不仅是为了保护您的用户免受通过破坏您的网站而获得对数据库的访问权的人。 您还需要保护自己组织内的人员可能怀有恶意。

由于许多用户不幸的是对多个网站使用相同的密码,所以这种需求就更大了。 如果某人可以访问您的一个用户的电子邮件地址和原始密码,则很有可能他们可以访问其他网站上该用户的帐户。

开裂速度

并非所有哈希值均相等。 您可以使用各种算法来创建哈希。 过去常用的两个是MD5SHA-1 。 当今功能强大的计算机可以很容易地破解这两种算法。 例如,在单个GPU上,存在针对MD5破解哈希的软件 ,每秒针对SHA-1破解哈希的速率为13.60亿。 以这种速度,取决于密码的复杂性和长度,可以在不到一个小时的时间内破解一个密码。

因此,使用更多计算复杂的哈希算法很重要。 您不仅需要更长的哈希值(这会减少哈希值冲突的机会-两个短语生成相同的哈希值),而且还希望它花尽可能长的时间来生成哈希值。 为什么? 对于您自己的Web应用程序,用户每次登录仅需等待一次密码哈希生成。如果这种等待持续一秒钟(甚至几秒钟),则用户将不会在乎,甚至不会注意到。 但是,通过将破解尝试从每秒36亿次计算降低到每秒1次,您的尝试难度将成倍增加。

彩虹桌

您还需要保护自己免受彩虹桌伤害。 Rainbow表是用于哈希表的反向查找表。 表格的创建者会针对所有常见单词,词组,修饰词甚至随机字符串预先计算MD5哈希值。 有权访问哈希的人可以将其输入查询以发现用于生成哈希的密码,从而有效地逆转了单向过程。 破解MD5哈希的处理成本相对较低,因此可以创建此Rainbow表。

为计算复杂的算法生成彩虹表需要更长的时间。 但这仍然是可能的,对创作者来说只是一次痛苦。 适当的对策是在哈希中添加盐 。 在这种情况下, salt指的是在您首先创建哈希之前添加到您的密码中的任何短语。 通过使用盐,您最终会击败(实际上)彩虹表。 有人需要生成特定于您的应用程序的Rainbow表,然后通过破解多个密码来弄清楚您的盐分是什么—困难而昂贵的情况。

改进过去PHP密码做法

现在看一下清单1,该示例展示了几年前PHP中良好的密码惯例。

清单1.以前在PHP中被认为是良好的密码安全性
<?php
// Create a password class to handle management of this:
class Password {
    const SALT = 'MyVoiceIsMyPassport';

    public static function hash($password) {
        return hash('sha512', self::SALT . $password);
    }

    public static function verify($password, $hash) {
        return ($hash == self::hash($password));
    }
}

// Hash the password:
$hash = Password::hash('correct horse battery staple');

// Check against an entered password (This example will fail to verify)
if (Password::verify('Tr0ub4dor&3', $hash)) {
    echo 'Correct Password!\n';
} else {
    echo "Incorrect login attempt!\n";
}

清单1之类的示例将Web称为最佳实践。 长期以来,这种方法是最佳实践-肯定比使用MD5更好,并且比将密码存储为纯文本更好。 清单1使用了更为复杂的SHA-512算法,并迫使所有密码都撒了盐,以破坏预制的Rainbow表。 但是这种方法仍然存在一些问题。

转向随机盐

清单1使用了一个盐,但是每个密码都使用了完全相同的盐。 因此,一旦有人破解了一个密码(或者更糟的是,通过访问代码库发现了盐),就可以通过将盐添加到每个彩虹表条目中来创建自定义的彩虹表。 破坏彩虹表的解决方案是在创建每个密码时对每个密码使用随机盐,并以一种可以检索的方式将盐与密码一起存储。

进一步增加成本

清单1还使用SHA-512(一种PHP附带的更为复杂的算法)代替了MD5或SHA-1。 但是,即使SHA-512哈希也可以以大约每秒4,600万次计算的速度被破解。 尽管比MD5或SHA1速率慢,但该速率仍不足以充分保证安全性。 解决此问题的方法是使用计算复杂性更高的算法,并多次运行这些算法。 例如,通过SHA-512 100分别连续运行每个密码的时间将大大减慢任何黑客尝试的速度。

好消息是您无需尝试使用自己的代码来实现此解决方案。 PHP 5.5中新的密码哈希库满足了这一需求。

介绍password_hash()

密码哈希扩展程序会为您创建计算复杂的安全密码哈希,包括在后台生成和处理随机盐。 在最简单的用例中,您使用想要哈希值的密码调用password_hash() ,该扩展将为您处理所有事情。 您还需要提供第二个参数:您要扩展使用的哈希算法。 您有两种选择,但是指定PASSWORD_DEFAULT常数是目前的最佳选择(我将在稍后解释原因):

<?php
$hash = password_hash('correct horse battery staple', PASSWORD_DEFAULT);

指定费用

您还可以提供第三个参数,它是一组选项,可更改散列的生成方式。 您可以在此处指定盐,但最好不要这样做,并允许为您生成随机盐。 更重要的是,在此数组中,您可以指定cost值。 该值(默认为10 )决定了算法应该有多复杂,并因此需要多长时间来生成哈希。 (将此值视为改变算法在其自身之上重新运行的次数以减慢计算速度。)如果您想要一个更安全的密码并且您的硬件能够处理该密码,则可以这样进行调用:

<?php
$hash = password_hash('correct horse battery staple', PASSWORD_DEFAULT, ['cost' => 14]);

使用我自己的MacBook Pro作为测试环境,生成成本为10 (默认值)的password_hash大约需要0.085秒。 将成本增加到14会使每次计算的时间大大缩短为1.394秒。

验证生成的密码

因为前两个示例中的密码是通过我随机生成的盐生成的,所以我不直接知道有问题的盐。 因此,如果我尝试再次运行password_hash()并比较字符串作为验证密码的方法,则结果将不匹配。 每次调用该函数时,都会生成一个新的盐,并且返回的哈希值也不同。 因此,该扩展程序提供了第二个功能,称为password_verify() ,它可以为您处理验证过程。 您调用password_verify() ,传入用户提供的密码和存储的哈希值,如果密码正确,则函数返回布尔值TRUE否则返回FALSE

<?php
if (password_verify($password, $hash)) {
    // Correct Password
}

现在,我可以重构清单1中的类,以使用内置的密码哈希扩展,如清单2所示。

清单2.清单1的Password类的重构
<?php
class Password {
    public static function hash($password) {
        return password_hash($password, PASSWORD_DEFAULT, ['cost' => 14]);
    }

    public static function verify($password, $hash) {
        return password_verify($password, $hash);
    }
}

处理不断变化的安全需求

通过使用新的密码哈希扩展,您可以使您的代码库达到当今的安全标准。 但是仅仅几年前,专家们才说SHA-1是最佳实践的解决方案。 那么,如果(不, 何时 )密码加密需要增强,会发生什么? 幸运的是,新扩展具有内置功能,可以将这种可能性考虑在内。

password_needs_rehash()函数可用于在幕后检测-如果存储的密码与您指定的当前安全需求不匹配。 原因可能是您增加了cost参数,或者是新PHP版本在幕后更改为其他哈希算法。 这就是为什么PASSWORD_DEFAULT应该是您的算法选择的原因; 该选项将始终使您的软件使用当前的最佳实践版本。

使用此功能稍微有些复杂,但并不过分。 当检查用户的密码时(例如,当用户尝试登录时),您将执行一项额外的任务:调用password_needs_rehash() ,该参数采用与password_hash()类似的参数。 password_needs_rehash()函数根据新请求的安全设置检查提供的密码哈希。 如果密码哈希与这些设置不匹配,该函数会向您报告该事实。

一些程序员对此感到困惑,因为password_needs_rehash()函数所做的全部只是让您知道密码是否需要重新哈希。 然后完全由您决定是否生成密码的新哈希值并保存它-因为密码扩展名不知道您可能需要如何存储密码。

在清单3中,我提供了一个完整的模型User类,其中使用我已经讨论过的工具,既可以安全地处理用户的密码,又可以满足将来不断变化的安全需求。

清单3.模拟User类显示了密码扩展的全部使用
<?php
class User {
    // Store password options so that rehash & hash can share them:
    const HASH = PASSWORD_DEFAULT;
    const COST = 14;

    // Internal data storage about the user:
    public $data;

    // Mock constructor:
    public function __construct() {
        // Read data from the database, storing it into $data such as:
        //  $data->passwordHash  and  $data->username
        $this->data = new stdClass();
        $this->data->passwordHash = 'dbd014125a4bad51db85f27279f1040a';
    }

    // Mock save functionality
    public function save() {
        // Store the data from $data back into the database
    }

    // Allow for changing a new password:
    public function setPassword($password) {
        $this->data->passwordHash = password_hash($password, self::HASH, ['cost' => self::COST]);
    }

    // Logic for logging a user in:
    public function login($password) {
        // First see if they gave the right password:
        echo "Login: ", $this->data->passwordHash, "\n";
        if (password_verify($password, $this->data->passwordHash)) {
            // Success - Now see if their password needs rehashed
            if (password_needs_rehash($this->data->passwordHash, self::HASH, ['cost' => self::COST])) {
                // We need to rehash the password, and save it.  Just call setPassword
                $this->setPassword($password);
                $this->save();
            }
            return true; // Or do what you need to mark the user as logged in.
        }
        return false;
    }
}

结论

现在,您知道了新的密码哈希库如何用于PHP,以及它将如何继续帮助保护您的用户免遭安全破坏。 在下一期PHP更新的文章中 ,我将把讨论从PHP语言本身的演变转移到围绕它演化的生态系统和工具-从Composer开始,它是PHP的依赖管理器,席卷了整个社区。 。


翻译自: https://www.ibm.com/developerworks/security/library/wa-php-renewed_2/index.html

php安全性令牌

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值