在密碼學(xué)專家之中,“加密并不是認證”是一個簡單的共識。但很多不了解密碼學(xué)的開發(fā)者,并不知道這句話的意義。如果這個知識更廣為人知和深入理解,那么將會避免很多的設(shè)計錯誤。
這一概念本身并不困難,但在表面之下,還有更多豐富的細節(jié)和玄妙之處有待發(fā)現(xiàn)。本文就是講述開發(fā)者對于加密和認證二者的混淆與誤用,并附上了優(yōu)秀的解決方案。
0x01 加密與認證之間有哪些區(qū)別?
加密是呈現(xiàn)信息,使其在沒有正確的密鑰情況下,變得難以卒讀的過程。在簡單的對稱加密中,同一個密鑰被用于加密和解密。在非對稱加密中,可以使用用戶的公鑰對信息加密,使得只有對應(yīng)私鑰的擁有者才能讀取它。
認證是呈現(xiàn)信息,使其抗篡改(通常在某一非常低的概率之內(nèi),小于1除以已知宇宙中粒子的數(shù)量),同時也證明它起源于預(yù)期發(fā)送者的過程。
注意:當(dāng)本文提及真實性時,是專門指的信息真實性,而不是身份真實性。這是一個PKI和密鑰管理問題,我們可能在未來的博客中詳細說明。
就CIA triad而言:加密提供機密性,認證提供完整性。
加密不提供完整性;被篡改的信息(通常)還能解密,但結(jié)果通常會是垃圾。單獨加密也不抑制惡意第三方發(fā)送加密信息。
認證不提供機密性;可以為明文信息提供抗篡改。
在程序員中,常見的錯誤是混淆這兩個概念。你能很容易找到這樣的一個庫或者框架:加密cookie數(shù)據(jù),然后在僅僅解密它之后就無條件地信任與使用之。
0x02 加密
我們之前定義了加密,并且詳細說明了它是提供機密性,但不提供完整性和真實性的。你可以篡改加密信息,并將產(chǎn)生的垃圾給予接收者。而且你甚至可以利用這種垃圾產(chǎn)生機制,來繞過安全控制。
考慮在加密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
),
"