什么encryptionalgorithm最适合encryptioncookie?

由于这个问题比较stream行,所以我认为给它一个更新是很有用的。

让我强调AviD给这个问题的正确答案

你不应该在你的cookie中存储任何需要encryption的数据。 相反,在cookie中存储大小适中的(128位/ 16字节)随机密钥,并将要保持安全的信息存储在服务器上(由cookie的密钥标识)。


我正在寻找关于encryptioncookies的“最好的”encryptionalgorithm的信息。

我有以下要求:

  • 它一定是快的
    encryption和解密的数据将(几乎)完成每一个请求

  • 它将在小数据集上运行,通常是大约100个字符或更less的string

  • 它必须是安全的,但它不像我们正在确保银行交易

  • 我们需要能够解密这些信息,以便SHA1等等。

现在我读了Blowfish是快速和安全的,我已经读了AES是快速和安全的。 随着河豚具有较小的块大小。

我认为这两种algorithm都提供了足够的安全性? 所以速度会成为决定性的因素。 但是我真的不知道这些algorithm是否适合小string,以及是否有更好的algorithm来encryptioncookie。

所以我的问题是:
什么encryptionalgorithm最适合encryptioncookie数据?

更新
更准确地说,我们要encryption2个cookie:一个带有会话信息,另一个带有“记住我”的信息。

该平台是Linux上的VPS上的PHP作为apache模块。

更新2
我同意Cletus将任何信息存储在cookie中是不安全的。

但是,我们有要求实施“记住我”function。 接受的方法是设置一个cookie。 如果客户提供这个cookie,他/她可以(几乎)相同的权限访问系统,就像他/她提供有效的用户名密码组合一样。

所以我们至less要encryptioncookie中的所有数据,以便:
a)恶意用户无法读取其内容,
b)恶意用户不能制造自己的cookie或篡改它。

(在我们做任何事情之前,所有来自cookies的数据都经过了消毒和检查的有效性,但这是另一回事)

会话cookie只包含sessionId / timestamp。 它可能可以使用没有encryption,但我认为没有encryption的危害吗? (除了计算时间)。

所以鉴于我们必须在cookie中存储一些数据,encryption它的最好方法是什么?

更新3
对这个问题的回答使我重新考虑了所select的方法。 我确实可以做到这一点,而不需要encryption。 我不应该对数据进行encryption,而应该只发送没有意义的数据而无法猜测

不过,我也很茫然:
我认为encryption使我们能够将数据发送到BigBadWorld™,并且仍然(相当)地确信没有人能够读取或篡改数据。
难道那不是encryption的全部?

但是下面的反应会推动:不要相信encryption来实现安全。

我在想什么?

没有真正的理由不去与256位的AES 。 请确保在CBC模式下使用此和PKCS#7填充。 正如你所说,快速和安全。

我已经阅读(未testing)Blowfish可能会稍微快一些…但是Blowfish有一个主要的缺点是安装时间长,这会使您的情况变得糟糕。 另外,AES更“被certificate”。

这假设真的必要对您的Cookie数据进行对称encryption。 正如其他人所指出的,它确实不应该是必要的,只有less数边缘情况下没有别的select,只能这样做。 通常,更适合您更改devise,并返回随机会话标识符,或者必要时单向哈希(使用SHA-256)。
在你的情况下,除了“常规”随机会话标识符,你的问题是“记住我”function – 这也应该实现为:

  • 一个长的随机数,存储在数据库中并映射到一个用户帐户;
  • 或者包含例如用户名,时间戳,mebbe盐和密钥服务器密钥的密钥散列(例如HMAC)。 这当然可以全部validation服务器端…

好像我们已经从你原来的具体问题上得到了一些小题目 – 通过改变devise改变了你的问题的基础….
所以,只要我们这样做,我也会强烈build议对这个持久的“记住我”这个特征有几个理由,其中最大的一个:

  • 使人们更有可能窃取该用户的记忆密钥,从而允许他们欺骗用户的身份(然后可能更改其密码);
  • CSRF – 跨站请求伪造 。 您的function将有效地允许匿名攻击者导致不知情的用户向应用程序提交“已validation”请求,即使没有实际login。

这涉及到两个单独的问题。

首先, 会话劫持 。 这是第三方发现一个authentication的cookie,并获得访问其他人的细节。

其次, 会话数据安全 。 通过这个我的意思是你的数据存储在cookie(如用户名)。 这不是一个好主意。 任何这样的数据基本上是不可信的,就像HTML表单数据是不可信的(不pipe你使用什么Javascriptvalidation和/或HTML长度限制,如果有的话),因为客户可以自由地提交他们想要的。

您经常会发现人们(正确)提倡清理HTML表单数据,但Cookie数据将被盲目接受。 大错。 事实上,我从不在cookie中存储任何信息。 我认为它是一个会话密钥,这就是全部。

如果您打算将数据存储在cookie中,我强烈build议您重新考虑。

这种数据的encryption不会使信息更加可信,因为对称encryption容易受到powershell攻击。 显然,AES-256比DES(heh)要好,但是256位的安全性不一定象你想象的那么重要。

一方面,SALT通常是根据algorithm产生的,否则容易受到攻击。

另一方面,cookie数据是婴儿床攻击的主要候选者。 如果知道或怀疑encryption数据中的用户名是嘿,那么你的婴儿床。

这使我们回到第一点:劫持。

应该指出的是,在PHP中的共享主机环境(作为一个例子)中,会话数据只是存储在文件系统中,并且可以被同一主机上的任何其他人读取,尽pipe它们不一定知道它是用于哪个站点。 因此,不要存储明文密码,信用卡号码,广泛的个人信息或任何可能会被认为在这样的环境中的会话数据敏感,没有某种forms的encryption,或者更好的是,只是在会话中存储一个密钥,并存储实际的敏感数据库中的数据。

注意:上面的PHP不是唯一的。

但是这是服务器端encryption。

现在你可以争辩说,使用一些额外的数据encryption一个会话将使它更安全的劫持。 一个常见的例子是用户的IP地址。 问题是许多人在许多不同的地点使用相同的PC /笔记本电脑(例如Wifi热点,工作,家庭)。 许多环境也会使用各种IP地址作为源地址,特别是在企业环境中。

你也可以使用用户代理,但这是可以猜测的。

所以,据我所知,根本没有真正的理由使用cookieencryption。 我从来没有想过有这样的问题,但是我想要certificate这个问题是对的还是错的。 我发现了一些关于人们build议encryptioncookie数据的方法,透明地使用Apache模块等等,但是这些似乎都是为了保护存储在cookie中的数据(这是你不应该做的)。

我还没有看到一个安全参数来encryption一个代表会话密钥的cookie。

如果有人能指出一些相反的话,我会高兴地被certificate是错误的。

安全警告 :这两个function是不安全的。 他们使用ECB模式 ,无法validation密文 。 看到这个答案是一个更好的前进方向。

对于那些希望在PHP脚本中使用这种方法的人来说。 这是一个使用256位Rijndael(而不是AES)的工作示例。

function encrypt($text, $salt) { return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); } function decrypt($text, $salt) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); } 

然后保存该cookie

 setcookie("PHPSESSION", encrypt('thecookiedata', 'longsecretsalt')); 

并阅读下一页:

 $data = decrypt($_COOKIE['PHPSESSION'], 'longsecretsalt'); 

您可以通过在EAX模式下使用AES来实现您想要的安全。 密文将比明文大; 这对安全encryption是正常的。

攻击者当然会从密文中知道你的明文的长度,但是他们不应该能够确定其他的东西。

随机生成AES密钥。

请确保每次encryption都使用一个新的随机数,并使用“关联数据”字段来确保您为某一目的encryption的内容不会作为另一个目的显示(因此用户名和cookie名称可能会进入那里)

下面的反应会推动:不要相信encryption来实现安全。

更多的“如果你不是一个encryption专家,你会低估得到错误是多么容易”。 例如,AFAICT在这个线程中没有人讨论了链接模式或消息完整性,其中涵盖了两个常见的初学者的错误。

快速,与Libsodiumencryptioncookies

如果您需要在PHP中使用快速安全的encryptioncookie,请查看Halite如何实施它们。 Halite依靠libsodium PECL扩展来提供安全的encryption。

 <?php use \ParagonIE\Halite\Cookie; use \ParagonIE\Halite\Symmetric\Key; use \ParagonIE\Halite\Symmetric\SecretKey; // You can also use Key::deriveFromPassword($password, $salt, Key::CRYPTO_SECRETBOX); $encryption_key = new SecretKey($some_constant_32byte_string_here); $cookie = new Cookie($encryption_key); $cookie->store('index', $any_value); $some_value = $cookie->fetch('other_index'); 

如果您不能安装PECL扩展,请询问您的系统pipe理员或主机提供商为您做。 如果他们拒绝,你仍然有select。


在PHP中安全encryption的Cookie,请举行盐

其他答案指示您使用openssl或mcryptencryption数据,但是他们错过了一个关键的步骤。 如果你想在PHP中安全地encryption数据 ,你必须validation你的消息。

使用OpenSSL扩展,您需要遵循的过程如下所示:


前言

  • (甚至在考虑encryption之前)生成一个128位,192位或256位的随机string。 这将是你的主密钥

    不要使用人类可读的密码。 如果您出于某种原因必须使用人类可读的密码,请向Cryptography SE寻求指导。

    如果您需要特别注意,我的雇主提供技术咨询服务 ,包括密码学function的开发。

encryption

  1. 生成随机初始化向量(IV)或随机数。 例如random_bytes(openssl_cipher_iv_length('aes-256-cbc'))
  2. 使用HKDF或类似的algorithm将主密钥分成两个密钥:
    1. encryption密钥( $eKey
    2. authentication密钥( $aKey
  3. 用你的IV和适当的modate(例如aes-256-ctr )用你的encryption密钥( $eKey )encryption你的stringopenssl_encrypt() )从步骤2。
  4. 使用诸如HMAC-SHA256之类的密钥散列函数,从步骤3计算密文的authentication标记。 例如hash_hmac('sha256', $iv.$ciphertext, $aKey)encryption后进行身份validation以及封装IV /随机数非常重要。
  5. 将authentication标签,IV或随机数和密文一起打包,并可select使用bin2hex()base64_encode()进行编码。 (警告:这种方法可能会泄漏caching时间信息。)

解密

  1. 根据encryption步骤2分割您的密钥。 解密时我们需要相同的两个密钥!
  2. (可选地,解码并且)从打包的消息中解压缩MAC,IV和密文。
  3. 通过使用hash_equals()用用户提供的HMAC重新计算IV / nonce和密文的HMAC来validationauthentication标签。
  4. 当且仅当步骤3通过时,使用$eKey解密密文。

如果你想看看这一切如何在一起,看到这个答案,它有示例代码 。

如果这听起来像是太多的工作,可以使用defuse / php-encryption或者zend-crypt并且把它称为一天。


记住我的Cookies

但是,我们有要求实施“记住我”function。 接受的方法是设置一个cookie。 如果客户提供这个cookie,他/她可以(几乎)相同的权限访问系统,就像他/她提供有效的用户名密码组合一样。

encryption实际上不是这项工作的正确工具。 你想要遵循这个过程,以确保在PHP中记住我的cookies :

生成一个记住我的令牌

  1. 生成两个随机string:
    1. 将用于数据库查找的selector 。 (随机select器的目的是不要泄漏你的网站上有多less活跃用户,如果你愿意泄露这些信息,可以随意使用顺序ID。)
    2. validator将用于自动validation用户。
  2. 计算validator的散列(一个简单的SHA-256散列就足够了)。
  3. selectorvalidator selector的散列存储在为自动login保留的数据库表中。
  4. selectorvalidator存储在客户端的Cookie中。

兑现记住我的代币

  1. 将传入的cookie分成selectorvalidator
  2. 根据selector执行数据库查找(使用预准备语句 !)。
  3. 如果find一行,则计算validator的散列。
  4. 将步骤3中计算的散列与存储在数据库中的散列进行比较,再次使用hash_equals()
  5. 如果步骤4返回true,请将用户login到相应的帐户。

这是Gatekeeper采用的用于长期用户authentication的策略,并且是迄今为止提出的用于满足该要求的最安全的策略。

虽然都是非常强大的,但AES是一个标准。

至于小块数据的安全性:越小越好。 encryption的数据暴露的越less,使用密钥的时间就越长。 在给定algorithm的一个密钥内可以encryption多less数据总是存在理论上的限制,而不将系统暴露给风险。

如果您对cookie进行了encryption,服务器仍然需要对其进行解码才能读取(以检查相同的密钥),因此,任何encryption的cookie都是毫无意义的,因为如果被盗(未经编辑),它仍然会使黑客有权访问您的帐户。 它就像不encryption一样不安全。

我相信窃取你的cookie的真正问题是服务器和客户端之间的连接。 使用您的主机提供的SSL连接。

至于你的cookie,你需要在数据库中为每个用户build立一个很长的随机id(每次login都改变它),并将其设置为cookie或会话。 包含密钥的cookie可以通过php进行检查,如果它与数据库中的账户或表相同,则将数据转储到网页上。

为什么要encryptioncookie?

正如我所看到的,有两种情况:要么给客户钥匙,要么给客户钥匙。

如果你不把钥匙给客户,那么你为什么要给他们的数据? 除非你打破弱encryption(你明确地不encryption)玩一些奇怪的游戏,否则你可能会把数据存储在服务器上。

如果你把钥匙交给客户,那你为什么要把钥匙encryption呢? 如果你不encryption密钥的通信,那么encryptioncookie是没有意义的:一个MITM可以查看cookie并发送给你任何他想要的cookie。 如果您使用encryption通道到客户端,为什么encryption存储的数据的额外开销?

如果您担心客户机器上的其他用户正在读取cookie,请放弃并假定浏览器设置了良好的权限位:)

正如以前的评论中指出的那样,您必须对发送给用户的任何密文应用完整性保护 ,然后再接受。 否则,可以修改受保护的数据,或者恢复encryption密钥。

尤其是PHP世界充满了忽视这一点的不好的例子(请参阅PHP密码术 – 谨慎处理 ),但是这适用于任何语言。

我见过的几个很好的例子之一是PHP-CryptLib ,它使用组合的encryptionauthentication模式来完成这项工作。 对于Python pyOCB提供了类似的function。

AES(也被称为Rijndael)是最受欢迎的。 块的大小是128位,只有16个字节,而你说的是“大约100个字符”。

我认为,即使encryption的用户名和密码“送走”任何数据是不好的…有许多JS可以嗅探它…我build议你在用户数据库表中创build一个字段cookie_auth或任何.. 。

第一次login后收集:当前:浏览器,IP,一些自己的盐键,加上你的主机名变种…

创build一个哈希和存储在该字段中…设置一个cookie …当cookie“响应”比较所有这些与存储的哈希和完成…

即使有人“偷”了一个cookie,他们也无法使用它:-)

希望这可以帮助 :-)

feha vision.to

此外,我已经尝试了mcrypt_encrypt ,有一件事请记住。 如果你做base64_encode(mcrypt_encrypt(...))

然后再做base64_decode并输出encryption的数据( echo )。 你可能会被拧紧,没有看到任何东西。 但是,如果你做mcrypt_decrypt( ... base64_decode($value) ) 。 你会看到原始数据。