<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/6042

                    在密碼學專家之中,“加密并不是認證”是一個簡單的共識。但很多不了解密碼學的開發者,并不知道這句話的意義。如果這個知識更廣為人知和深入理解,那么將會避免很多的設計錯誤。

                    這一概念本身并不困難,但在表面之下,還有更多豐富的細節和玄妙之處有待發現。本文就是講述開發者對于加密和認證二者的混淆與誤用,并附上了優秀的解決方案。

                    0x01 加密與認證之間有哪些區別?


                    加密是呈現信息,使其在沒有正確的密鑰情況下,變得難以卒讀的過程。在簡單的對稱加密中,同一個密鑰被用于加密和解密。在非對稱加密中,可以使用用戶的公鑰對信息加密,使得只有對應私鑰的擁有者才能讀取它。

                    認證是呈現信息,使其抗篡改(通常在某一非常低的概率之內,小于1除以已知宇宙中粒子的數量),同時也證明它起源于預期發送者的過程。

                    注意:當本文提及真實性時,是專門指的信息真實性,而不是身份真實性。這是一個PKI和密鑰管理問題,我們可能在未來的博客中詳細說明。

                    CIA triad而言:加密提供機密性,認證提供完整性。

                    加密不提供完整性;被篡改的信息(通常)還能解密,但結果通常會是垃圾。單獨加密也不抑制惡意第三方發送加密信息。

                    認證不提供機密性;可以為明文信息提供抗篡改。

                    在程序員中,常見的錯誤是混淆這兩個概念。你能很容易找到這樣的一個庫或者框架:加密cookie數據,然后在僅僅解密它之后就無條件地信任與使用之。

                    0x02 加密


                    我們之前定義了加密,并且詳細說明了它是提供機密性,但不提供完整性和真實性的。你可以篡改加密信息,并將產生的垃圾給予接收者。而且你甚至可以利用這種垃圾產生機制,來繞過安全控制。

                    考慮在加密cookie的情況下,有如下代碼:

                    #!php
                    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
                            ),
                            "\0"
                        );
                    
                        return json_decode($decrypted, true);
                    }
                    

                    上面的代碼提供了在密碼段鏈接模塊的AES加密,如果你傳入32字節的字符串作為$key,你甚至可以聲稱,為你的cookie提供了256位的AES加密,然后人們可能被誤導相信它是安全的。

                    0x03 如何攻擊未經認證的加密


                    比方說,在登錄到這個應用程序之后,你會發現你收到一個會話cookie,看起來就像

                    kHv9PAlStPZaZJHIYXzyCnuAhWdRRK7H0cNVUCwzCZ4M8fxH79xIIIbznxmiOxGQ7td8LwTzHFgwBmbqWuB+sQ==

                    讓我們改變一個字節的第一塊(初始化向量),并反復發送我們的新的cookie,直到出現一些變化。應該采取共4096次HTTP請求,以嘗試變量IV所有可能的單字節變化。在上面的例子中,經過2405次請求后,我們得到一個看起來像這樣的字符串:

                    kHv9PAlStPZaZZHIYXzyCnuAhWdRRK7H0cNVUCwzCZ4M8fxH79xIIIbznxmiOxGQ7td8LwTzHFgwBmbqWuB+sQ==

                    相比之下,在base64編碼的cookie中只有一個字符不同(kHv9PAlStPZaZ J vs kHv9PAlStPZaZ Z):

                    - kHv9PAlStPZaZJHIYXzyCnuAhWdRRK7H0cNVUCwzCZ4M8fxH79xIIIbznxmiOxGQ7td8LwTzHFgwBmbqWuB+sQ==
                    
                    + kHv9PAlStPZaZZHIYXzyCnuAhWdRRK7H0cNVUCwzCZ4M8fxH79xIIIbznxmiOxGQ7td8LwTzHFgwBmbqWuB+sQ==
                    

                    我們存儲在這個cookie里的原始數據,是看起來像這樣的數組:

                    #!php
                    array(2) {
                      ["admin"]=>
                      int(0)
                      ["user"]=>
                      "aaaaaaaaaaaaa"
                     }
                    

                    但在僅僅改變初始化向量的一個字節之后,我們就能夠改寫我們的閱讀信息:

                    #!php
                    array(2) {
                      ["admin"]=>
                      int(1)
                      ["user"]=>
                      "aaaaaaaaaaaaa"
                    }
                    

                    根據底層應用程序的設置方法,你或許可以翻轉一位進而提升成為一名管理員。即使你的cookie是加密的。 如果你想再現我們的結果,我們的加密密鑰是十六進制下的:000102030405060708090a0b0c0d0e0f

                    0x04 認證


                    如上所述,認證旨在提供信息的完整性(我們指顯著抗篡改能力),而這證明它來自預期的源(真實性)。這樣做的典型方法是,為信息計算一個密鑰散列消息認證碼(HMAC的簡稱),并將信息與它連結。

                    #!php
                    function hmac_sign($message, $key)
                    {
                        return hash_hmac('sha256', $message, $key) . $message;
                    }
                    function hmac_verify($bundle, $key)
                    {
                        $msgMAC = mb_substr($bundle, 0, 64, '8bit');
                        $message = mb_substr($bundle, 64, null, '8bit');
                        return hash_equals(
                            hash_hmac('sha256', $message, $key),
                            $msgMAC
                        );
                    }
                    

                    重要的是,這里使用一個適當的哈希工具,如HMAC,而不僅僅是一個簡單的散列函數。

                    #!php
                    function unsafe_hash_sign($message, $key)
                    {
                        return md5($key.$message) . $message;
                    }
                    function unsafe_hash_verify($bundle, $key)
                    {
                        $msgHash = mb_substr($bundle, 0, 64, '8bit');
                        $message = mb_substr($bundle, 64, null, '8bit');
                        return md5($key.$message) == $msgHash;
                    }
                    

                    我在這兩個函數名前面加了unsafe,是因為它們還是易受到一些缺點的危害:

                    1. Timing Attacks

                    2. Chosen Prefix Attacks on MD5 (PDF)

                    3. Non-strict equality operator bugs (largely specific to PHP)

                    現在,我們有點接近我們強大的對稱加密認證的目標。目前仍有幾個問題,如:

                    1. 如果我們的原始信息以空字節結尾會發生什么?

                    2. 有沒有一個比mcrypt擴展庫默認使用的更好的填充策略?

                    3. 由于使用AES,有哪些通信方面是易受攻擊的?

                    幸運的是,這些問題在現有的加密函數庫中已有了解答。我們強烈推薦你使用現有的庫,而不是寫自己的加密功能。對于PHP開發人員來說,你應該使用defuse/php-encryption(或者libsodium)。

                    0x05 用Libsodium安全加密Cookies


                    #!php
                    
                    /*
                    // At some point, we run this command:
                    $key = Sodium::randombytes_buf(Sodium::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
                    */
                    
                    /**
                     * Store ciphertext in a cookie
                     * 
                     * @param string $name - cookie name
                     * @param mixed $cookieData - cookie data
                     * @param string $key - crypto key
                     */
                    function setSafeCookie($name, $cookieData, $key)
                    {
                        $nonce = Sodium::randombytes_buf(Sodium::CRYPTO_SECRETBOX_NONCEBYTES);
                    
                        return setcookie(
                            $name,
                            base64_encode(
                                $nonce.
                                Sodium::crypto_secretbox(
                                    json_encode($cookieData),
                                    $nonce,
                                    $key
                                )
                            )
                        );
                    }
                    
                    /**
                     * Decrypt a cookie, expand to array
                     * 
                     * @param string $name - cookie name
                     * @param string $key - crypto key
                     */
                    function getSafeCookie($name, $key)
                    {
                        $hexSize = 2 * Sodium::Sodium::CRYPTO_SECRETBOX_NONCEBYTES;
                        if (!isset($_COOKIE[$name])) {
                            return array();
                        }
                    
                        $decoded = base64_decode($_COOKIE[$name]);
                        $nonce = mb_substr($decoded, 0, $hexSize, '8bit');
                        $ciphertext = mb_substr($decoded, $hexSize, null, '8bit');
                    
                        $decrypted = Sodium::crypto_secretbox_open(
                            $ciphertext,
                            $nonce,
                            $key
                        );
                        if (empty($decrypted)) {
                            return array();
                        }
                    
                        return json_decode($decrypted, true);
                    }
                    

                    對于沒有libsodium庫的開發人員,我們的一個博客讀者,提供了一個安全cookie實現的例子,其使用了defuse/php-encryption(我們推薦的PHP庫)。

                    0x06 使用關聯數據的認證加密


                    在我們前面的示例中,我們集中精力于,同時使用加密和認證,使其作為必須小心使用的單獨組件,以避免加密的悲劇。具體而言,我們專注于密碼段鏈接模塊的AES加密。

                    然而,密碼學家已經開發出更新,更具有彈性的加密模型,其加密和認證信息在同一操作。這些模型被稱為AEAD模型(Authenticated Encryption with Associated Data)。關聯數據意味著,無論你的應用程序需要什么進行認證,都不加密。

                    AEAD模型通常用于有狀態的目的,如網絡通信中,其中一個隨機數可以很容易地管理。

                    AEAD兩個可靠的實現是AES-GCM和ChaCha20-Poly1305。

                    總結一下,你該記住的

                    將兩者混為一談你就得自擔風險

                    為了完成CIA triad,你需要單獨解決可用性。這通常不是一個加密問題。

                    更重要的是:在密碼學專家的監督下,使用具有韌性被證實記錄的庫,而不是自己在那里閉門造車,你會好得多。

                    原文:https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频