栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

双向加密:我需要存储可以检索的密码

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

双向加密:我需要存储可以检索的密码

就个人而言,我会

mcrypt
像其他人一样使用。但是还有更多需要注意的地方…

  1. 如何在PHP中加密和解密密码?

请参阅下面的强大课程,该课程可以为您解决所有问题:

  1. 什么是最安全的密码加密算法?

最安全
?任何一位。如果要加密,最安全的方法是防止信息泄露漏洞(XSS,远程包含等)。如果失败,攻击者最终可以破解加密(没有密钥,没有任何加密是100%不可逆的-
正如@NullUserException指出的那样,这并不完全正确。有一些无法破解的加密方案,例如OneTimePad) 。

  1. 我在哪里存储私钥?

我要做的是使用3个键。一个是用户提供的,一个是特定于应用程序的,另一个是特定于用户的(例如盐)。特定于应用程序的密钥可以存储在任何地方(在Web根目录之外的配置文件中,环境变量中等等)。用户专用密码将存储在数据库中加密密码旁边的一列中。用户提供的将不会被存储。然后,您将执行以下操作:

    $key = $userKey . $serverKey . $userSuppliedKey;

这样做的好处是,其中任何两个密钥都可以被破坏,而不会破坏数据。如果发生SQL注入攻击,则可以获取

$userKey
,但不能获取其他2。如果存在本地服务器利用,则可以获取
$userKey
$serverKey
,但不能获取
$userSuppliedKey
。如果他们用扳手殴打用户,他们可以拿到
$userSuppliedKey
,但不能拿到其他2(但是,如果用扳手殴打用户,无论如何你都来不及了)。

  1. 除了存储私钥之外,要求用户在需要解密密码的任何时间都输入私钥是一个好主意吗?(可以信任此应用程序的用户)

绝对。实际上,那是我要做的唯一方法。否则,您需要以持久存储格式(共享内存(例如APC或内存缓存)或会话文件)存储未加密的版本。这会使您面临更多的折衷。除本地变量外,切勿将未加密版本的密码存储在任何其他内容中。

  1. 密码可以通过什么方式被盗和解密?我需要注意什么?

系统的任何形式的破坏都会让他们查看加密的数据。如果他们可以注入代码或访问您的文件系统,则可以查看解密的数据(因为他们可以编辑对数据进行解密的文件)。任何形式的重播或MITM攻击也将使他们能够完全访问所涉及的密钥。嗅探原始HTTP流量也将为他们提供密钥。

对所有流量使用SSL。并确保服务器上没有任何漏洞(CSRF,XSS,SQL注入,权限提升,远程执行代码等)。

编辑: 这是一个强加密方法的PHP类实现:

class Encryption {        protected $cipher = '';        protected $mode = '';        protected $rounds = 100;        public function __construct($cipher, $mode, $rounds = 100) {        $this->cipher = $cipher;        $this->mode = $mode;        $this->rounds = (int) $rounds;    }        public function decrypt($data, $key) {        $salt = substr($data, 0, 128);        $enc = substr($data, 128, -64);        $mac = substr($data, -64);        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);        if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {  return false;        }        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);        $data = $this->unpad($dec);        return $data;    }        public function encrypt($data, $key) {        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);        $data = $this->pad($data);        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);        $mac = hash_hmac('sha512', $enc, $macKey, true);        return $salt . $enc . $mac;    }        protected function getKeys($salt, $key) {        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);        $length = 2 * $keySize + $ivSize;        $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);        $cipherKey = substr($key, 0, $keySize);        $macKey = substr($key, $keySize, $keySize);        $iv = substr($key, 2 * $keySize);        return array($cipherKey, $macKey, $iv);    }        protected function pbkdf2($algo, $key, $salt, $rounds, $length) {        $size   = strlen(hash($algo, '', true));        $len    = ceil($length / $size);        $result = '';        for ($i = 1; $i <= $len; $i++) { $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true); $res = $tmp; for ($j = 1; $j < $rounds; $j++) {      $tmp  = hash_hmac($algo, $tmp, $key, true);      $res ^= $tmp; } $result .= $res;        }        return substr($result, 0, $length);    }    protected function pad($data) {        $length = mcrypt_get_block_size($this->cipher, $this->mode);        $padAmount = $length - strlen($data) % $length;        if ($padAmount == 0) { $padAmount = $length;        }        return $data . str_repeat(chr($padAmount), $padAmount);    }    protected function unpad($data) {        $length = mcrypt_get_block_size($this->cipher, $this->mode);        $last = ord($data[strlen($data) - 1]);        if ($last > $length) return false;        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) { return false;        }        return substr($data, 0, -1 * $last);    }}

请注意,我正在使用PHP 5.6中添加的功能:

hash_equals
。如果低于5.6,则可以使用此替代函数,该函数使用双重HMAC验证实现定时安全比较功能:

function hash_equals($a, $b) {    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);}

用法:

$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);$encryptedData = $e->encrypt($data, $key);

然后,解密:

$e2 = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);$data = $e2->decrypt($encryptedData, $key);

请注意,我

$e2
第二次向您展示了不同的实例仍将正确解密数据。

现在,它是如何工作的/为什么要在另一个解决方案上使用它:

  1. 按键

    • 按键不直接使用。而是通过标准PBKDF2派生来扩展密钥。

    • 用于加密的密钥对于每个加密的文本块都是唯一的。因此,提供的密钥将成为“主密钥”。因此,此类为密码和身份验证密钥提供密钥轮换。

    • 重要说明 ,该

      $rounds
      参数配置为具有足够强度的真随机密钥(最少128位加密安全随机数)。如果要使用密码或非随机密钥(或者随机性较小,则CS随机性为128位),则 必须 增加此参数。我建议密码至少为10000(您能负担得起的越多越好,但是它将增加运行时的信息)…

  2. 数据的完整性

    • 更新版本使用ENCRYPT-THEN-MAC,这是确保加密数据真实性的更好方法。
    • 加密:

    • 它使用mcrypt实际执行加密。我建议使用

      MCRYPT_BLOWFISH
      MCRYPT_RIJNDAEL_128
      cypher和
      MCRYPT_MODE_CBC
      模式。它足够强大,并且仍然相当快(加密和解密周期在我的计算机上大约需要1/2秒)。

现在,从第一个列表的第3点开始,将为您提供的功能是这样的:

function makeKey($userKey, $serverKey, $userSuppliedKey) {    $key = hash_hmac('sha512', $userKey, $serverKey);    $key = hash_hmac('sha512', $key, $userSuppliedKey);    return $key;}

您可以在

makeKey()
函数中对其进行拉伸,但是由于稍后将对其进行拉伸,因此这样做没有太大意义。

至于存储大小,取决于纯文本。Blowfish使用8字节的块大小,因此您将拥有:

  • 盐16字节
  • hmac的64个字节
  • 数据长度
  • 填充,以便数据长度%8 == 0

因此,对于16个字符的数据源,将有16个字符的数据要加密。因此,由于填充,实际的加密数据大小为16个字节。然后为salt添加16个字节,为hmac添加64个字节,总存储大小为96个字节。因此充其量只有80个字符的开销,最糟糕的是87个字符的开销…

希望对您有帮助…

注意: 12/11/12:我刚刚使用更好的加密方法,使用更好的派生密钥并修复了MAC生成来更新此类。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/411988.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号