Jac*_*cco 48 php security encryption cookies remember-me
由于这个问题相当受欢迎,我认为给它更新很有用.
让我强调AviD给出的正确答案:
您不应该在cookie中存储任何需要加密的数据.相反,在cookie中存储一个大小合适的(128位/ 16字节)随机密钥,并将您想要保密的信息存储在服务器上,由cookie的密钥标识.
我正在寻找有关加密cookie的"最佳"加密算法的信息.
我有以下要求:
必须快速
加密和解密数据(几乎)每个请求都要完成
它将在小数据集上运行,通常是大约100个字符或更少的字符串
它必须是安全的,但它不像我们正在保证银行交易
我们需要能够解密信息,以便SHA1等出来.
现在我已经读过Blowfish快速而安全,我读过AES快速而安全.Blowfish的块大小较小.
我认为这两种算法都提供了足够的安全性?所以速度将成为决定性因素.但我真的不知道这些算法是否适合小字符串,以及是否有更适合加密cookie的算法.
所以我的问题是:
什么加密算法最适合加密cookie数据?
更新
更准确地说,我们要加密2个cookie:一个包含会话信息,另一个包含"记住我"信息.
该平台是PHP上作为VPS上的Linux上的apache模块.
更新2
我同意cletus,将任何信息存储在cookie中是不安全的.
但是,我们需要实现"记住我"功能.可接受的方法是设置cookie.如果客户端提供此cookie,则允许他或她以(几乎)相同的权限访问系统,就像他/她提供有效的用户名密码组合一样.
因此,我们至少要加密cookie中的所有数据,以便:
a)恶意用户无法读取其内容;
b)恶意用户无法制作自己的cookie或篡改它.
(在我们对它做任何事情之前,对所有来自cookie的数据进行消毒并检查其有效性,但这是另一个故事)
会话cookie不再包含sessionId/timestamp.它可以在没有加密的情况下使用,但我认为加密它没什么害处?(计算时间除外).
因此,鉴于我们必须在cookie中存储一些数据,加密它的最佳方法是什么?
更新3
对此问题的回答使我重新考虑所选择的方法.我确实可以做同样的事情而不需要加密.我不应该加密数据,而应该只发送没有上下文而无法猜到的数据.
然而,我也不知所措:
我认为加密使我们能够将数据发送到BigBadWorld™,并且仍然(相当)确定没有人可以阅读或篡改它......
不是全部加密点?
但下面的反应推动:不要相信加密来实现安全性.
我错过了什么?
Avi*_*viD 25
没有真正的理由不使用256位的AES.确保在CBC模式和PKCS#7填充中使用它.正如你所说,快速而安全.
我读过(未测试过)Blowfish的速度可能稍微快一些......但是Blowfish的主要缺点是设置时间长,这会使你的情况变得糟糕.此外,AES更"经过验证".
这是假设它确实是必要的对称加密您的cookie数据.正如其他人所指出的那样,它确实不是必要的,并且只有少数边缘情况除此之外别无选择.通常,它更适合您更改设计,并返回随机会话标识符,或者必要时单向哈希(使用SHA-256).
在您的情况下,除了"常规"随机会话标识符,您的问题是"记住我"功能 - 这也应该实现为:
好像我们对你原来的具体问题有点偏僻 - 并通过改变设计改变了你的问题的基础......
所以只要我们这样做,我也强烈建议反对这个功能坚持"记住我",有几个原因,其中最大的一个:
cle*_*tus 18
这涉及两个不同的问题.
首先,会话劫持.这是第三方发现经过身份验证的cookie并获取其他人详细信息的地方.
其次,有会话数据安全性.我的意思是你将数据存储在cookie中(例如用户名).这不是一个好主意.任何此类数据从根本上都是不值得信任的,就像HTML表单数据不可信(无论您使用什么Javascript验证和/或HTML长度限制,如果有的话),因为客户可以自由提交他们想要的内容.
您经常会发现人们(正确地)提倡对HTML表单数据进行清理,但cookie表面数据将被盲目接受.大错.事实上,我从不在cookie中存储任何信息.我将其视为会话密钥,就是这样.
如果您打算将数据存储在cookie中,我强烈建议您重新考虑.
加密此数据不会使信息更受信任,因为对称加密容易受到暴力攻击.显然,AES-256比DES(heh)要好,但256位的安全性并不一定意味着你的想法.
一方面,SALT通常根据算法生成或者易受攻击.
另一方面,cookie数据是婴儿床攻击的主要候选者.如果已知或怀疑加密数据中的用户名是嘿,那就是你的婴儿床.
这让我们回到第一点:劫持.
应该指出的是,在PHP的共享托管环境中(作为一个示例),您的会话数据只是存储在文件系统上,并且可以由同一主机上的任何其他人读取,尽管他们不一定知道它是用于哪个站点.因此,在没有某种形式的加密的情况下,永远不要存储明文密码,信用卡号,广泛的个人详细信息或在会话数据中可能被视为敏感的任何内容,或者更好的是,只需在会话中存储密钥并存储实际的敏感内容数据库中的数据.
注意:以上内容并非PHP独有.
但那是服务器端加密.
现在您可以争辩说,使用一些额外数据加密会话将使其更安全,免遭劫持.一个常见的例子是用户的IP地址.问题是很多人在许多不同的地方使用相同的PC /笔记本电脑(例如Wifi热点,工作,家庭).此外,许多环境将使用各种IP地址作为源地址,尤其是在企业环境中.
您也可以使用用户代理,但这是可猜测的.
实际上,据我所知,根本没有使用cookie加密的真正原因.我从来没有想过有这个问题,但鉴于这个问题,我一直在寻求证明是对还是错.我找到了一些关于人们建议加密cookie数据的方法的线程,透明地使用Apache模块,等等,但这些似乎都是通过保护存储在cookie中的数据(这是你不应该做的)来实现的.
我还没有看到加密cookie的安全性论据,该cookie只代表会话密钥.
如果有人可以指出相反的事情,我将很高兴被证明是错误的.
对于想要在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)));
}
Run Code Online (Sandbox Code Playgroud)
然后保存cookie
setcookie("PHPSESSION", encrypt('thecookiedata', 'longsecretsalt'));
Run Code Online (Sandbox Code Playgroud)
并在下一页阅读:
$data = decrypt($_COOKIE['PHPSESSION'], 'longsecretsalt');
Run Code Online (Sandbox Code Playgroud)
如果您需要 PHP 中快速、安全的加密 cookie,请查看Halite如何实现它们。Halite依靠libsodium PECL 扩展来提供安全加密。
<?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');
Run Code Online (Sandbox Code Playgroud)
如果您无法安装 PECL 扩展,请让您的系统管理员或托管服务提供商为您安装。如果他们拒绝,你仍然有选择。
其他答案指示您使用 openssl 或 mcrypt 加密数据,但它们缺少关键步骤。如果您想在 PHP 中安全地加密数据,您必须您的消息进行身份验证。
使用 OpenSSL 扩展,您需要遵循的过程如下所示:
(在考虑加密之前)生成 128 位、192 位或 256 位随机字符串。这将是您的主密钥。
不要使用人类可读的密码。如果您出于某种原因必须使用人类可读的密码,请向Cryptography SE寻求指导。
如果您需要特别关注,我的雇主提供技术咨询服务,包括密码学功能的开发。
random_bytes(openssl_cipher_iv_length('aes-256-cbc'))
$eKey
)$aKey
)openssl_encrypt()
与IV和适当的modate(如aes-256-ctr
使用加密密钥)($eKey
步骤 2 中的 )。hash_hmac('sha256', $iv.$ciphertext, $aKey)
。加密后进行身份验证以及封装 IV/nonce 非常重要。bin2hex()
或 对其进行编码base64_encode()
。(警告:这种方法可能会泄漏缓存时间信息。)hash_equals()
.$eKey
。如果您想看看这一切如何组合在一起,请参阅此答案,其中包含示例代码。
如果这听起来工作量太大,请使用defuse/php-encryption或zend-crypt并收工。
但是,我们需要实现“记住我”功能。解决此问题的公认方法是设置 cookie。如果客户端提供此 cookie,则允许他或她以(几乎)相同的权限访问系统,就好像他/她提供了有效的用户名密码组合一样。
加密实际上不是这项工作的正确工具。您想遵循此过程以在 PHP 中安全记住我的 cookie:
selector
将用于数据库查找的A。(使用随机选择器而不仅仅是顺序 ID 的目的是为了不泄露您网站上有多少活跃用户。如果您愿意泄露此信息,请随意使用顺序 ID。)validator
将用于自动验证用户身份的A。validator
(一个简单的 SHA-256 散列就足够了)。selector
和 的散列存储在validator
为自动登录保留的数据库表中。selector
和存储validator
在客户端的 cookie 中。selector
和validator
。selector
.validator
.hash_equals()
。这是Gatekeeper用于长期用户身份验证所采用的策略,也是迄今为止为满足此要求而提出的最安全的策略。
归档时间: |
|
查看次数: |
43311 次 |
最近记录: |