-1

我想加密密码以防止 SQL 注入和其他攻击,我在 PHP 中使用了一个加密功能,但我不知道如何使用它来加密密码。

我希望对用户表中的每个密码进行加密,以便我可以连接到数据库并使用查询,但它不起作用。

任何人都可以帮助我吗?

ecnription.php

<?php
require_once('include/connect.php');

if(isset($_SESSION['user_id']))
{
    $id= $_SESSION['user_id'];


}
$sql = mysql_query("SELECT password FROM user WHERE user_id= '$id'")or die(mysql_error());
while($row = mysql_fetch_array($sql))
{
    $enc_pass= $row['password'];

}

error_reporting(0);

class Encryption
{
    const CYPHER = MCRYPT_RIJNDAEL_256;
    const MODE   = MCRYPT_MODE_CBC;
    const KEY    = 'somesecretphrase';

    public function encrypt($plaintext)
    {
        $td = mcrypt_module_open(self::CYPHER, '', self::MODE, '');
        $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        mcrypt_generic_init($td, self::KEY, $iv);
        $crypttext = mcrypt_generic($td, $plaintext);
        mcrypt_generic_deinit($td);
        return base64_encode($iv.$crypttext);
    }

    public function decrypt($crypttext)
    {
        $crypttext = base64_decode($crypttext);
        $plaintext = '';
        $td        = mcrypt_module_open(self::CYPHER, '', self::MODE, '');
        $ivsize    = mcrypt_enc_get_iv_size($td);
        $iv        = substr($crypttext, 0, $ivsize);
        $crypttext = substr($crypttext, $ivsize);
        if ($iv)
        {
            mcrypt_generic_init($td, self::KEY, $iv);
            $plaintext = mdecrypt_generic($td, $crypttext);
        }
        return trim($plaintext);
    }
}


$encrypted_string = Encryption::encrypt($enc_pass); 
$decrypted_string = Encryption::decrypt($encrypted_string);

echo $encrypted_string . "<br>" . PHP_EOL;
var_dump($id);
echo $decrypted_string . "<br>" . PHP_EOL;
4

1 回答 1

4

实际上密码加密与mysql注入没有任何共同之处。你应该(必须!)分开做这些事情。

密码加密(或者在这种情况下是散列)将使可能访问您的数据库的黑客无法使用您的用户密码。哈希函数是一种方法 - 您可以从密码创建哈希,但不能从哈希创建密码。从散列中获取密码的唯一方法是散列每个可能的字符组合,并检查这个散列是否等于 db 中的这个。大多数 uf 用户在 php 中使用简单的 md5() 或 sha256() 函数。事实上它可以工作,但这些功能的问题在于它们的简单性。创建它们是为了计算文件的校验和,所以它们一定很快。这就是为什么它更容易暴力破解。为避免被暴力破解,您可以:

a) 添加 'salt' 并继续使用 md5 / sha256。Salt 是在散列之前添加到用户密码的随机字符串。您必须在数据库中创建附加列,例如在“密码”附近。每个用户都应该随机获得至少 32 个字符长的盐。“密码”字段是使用 md5(salt . users_password) 创建的。如果您想在登录时检查密码 - 从数据库中获取密码和盐字段,从帖子中获取用户密码并比较:md5(salt.user_password_from_post) 到数据库中的“密码”。即使用户密码很短,由于盐的存在,它也会变得又长又复杂。要破解/暴力破解所有 8 字符密码,您只需要 ~80^8 哈希,但要暴力破解加盐 8 字符密码,您需要 ~80^40,即 80^32 倍。

b) 使用河豚算法http://php.net/manual/en/function.crypt.php 河豚是从加密密码开始创建的。您还必须使用盐,但您也可以指定“成本”参数,该参数指示哈希的复杂程度。更复杂 = 每次密码检查时使用更多 CPU,但也更安全。据说用河豚、16 字节盐和至少 10 个成本保护的密码是安全的。

为避免被 sql 注入,您应该转义传递给查询的每个参数。mysql_real_escape_string() 成为你的朋友。

$Query = sprintf("SELECT UserId, Password, Salt FROM Users WHERE Username='%s'", mysql_real_escape_string($_POST['Username']));
mysql_query($Query);

如果

$_POST['Username'] = "'; DROP TABLE Users; --"

您没有转义的查询将变为:

"SELECT UserId, Password, Salt FROM Users WHERE Username=''; DROP TABLE Users; --'

通过此查询,任何用户都可以毫无问题地破坏您的数据库。使用 mysql_real_escape_string,查询看起来很简单:

"SELECT UserId, Password, Salt FROM Users WHERE Username='\'; DROP TABLE Users; --'

现在您的数据库是安全的。

检查密码的完整代码(您应该在 DB 中有 username(128)、password(32)、salt(32)):

function CheckPassword($Username, $Password)
{
    list($Count) = mysql_fetch_array(mysql_query(sprintf("SELECT COUNT(*) FROM Users WHERE Username='%s'", mysql_real_escape_string($Username))));
    if(!$Count)
        return false; //No such user
    list($Password_Db, $Salt) = mysql_fetch_array(mysql_query(sprintf("SELECT Password, Salt FROM Users WHERE Username='%s'", mysql_real_escape_string($Username))));
    if(md5($Salt . $Password) == $Password_Db)
        return true;
    return false;
}
于 2013-05-11T11:47:24.750 回答