在密码学专家之中,“加密并不是认证”是一个简单的共识。但很多不了解密码学的开发者,并不知道这句话的意义。如果这个知识更广为人知和深入理解,那么将会避免很多的设计错误。
这一概念本身并不困难,但在表面之下,还有更多丰富的细节和玄妙之处有待发现。本文就是讲述开发者对于加密和认证二者的混淆与误用,并附上了优秀的解决方案。
0x01 加密与认证之间有哪些区别?
加密是呈现信息,使其在没有正确的密钥情况下,变得难以卒读的过程。在简单的对称加密中,同一个密钥被用于加密和解密。在非对称加密中,可以使用用户的公钥对信息加密,使得只有对应私钥的拥有者才能读取它。
认证是呈现信息,使其抗篡改(通常在某一非常低的概率之内,小于1除以已知宇宙中粒子的数量),同时也证明它起源于预期发送者的过程。
注意:当本文提及真实性时,是专门指的信息真实性,而不是身份真实性。这是一个PKI和密钥管理问题,我们可能在未来的博客中详细说明。
就CIA triad而言:加密提供机密性,认证提供完整性。
加密不提供完整性;被篡改的信息(通常)还能解密,但结果通常会是垃圾。单独加密也不抑制恶意第三方发送加密信息。
认证不提供机密性;可以为明文信息提供抗篡改。
在程序员中,常见的错误是混淆这两个概念。你能很容易找到这样的一个库或者框架:加密cookie数据,然后在仅仅解密它之后就无条件地信任与使用之。
0x02 加密
我们之前定义了加密,并且详细说明了它是提供机密性,但不提供完整性和真实性的。你可以篡改加密信息,并将产生的垃圾给予接收者。而且你甚至可以利用这种垃圾产生机制,来绕过安全控制。
考虑在加密cookie的情况下,有如下代码:
function setUnsafeCookie($name, $cookieData, $key)
{
$iv = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
return setcookie(
$name,
base64_encode(
$iv.
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$key,
json_encode($cookieData),
MCRYPT_MODE_CBC,
$iv
)
)
);
}
function getUnsafeCookie($name, $key)
{
if (!isset($_COOKIE[$name])) {
return null;
}
$decoded = base64_decode($_COOKIE[$name]);
$iv = mb_substr($decoded, 0, 16, '8bit');
$ciphertext = mb_substr($decoded, 16, null, '8bit');
$decrypted = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$key,
$ciphertext,
MCRYPT_MODE_CBC,
$iv
),
"
(责任编辑:安博涛)