Facebook 在對抗 BREACH Attack 的方法

在「Facebook Takes Tougher Stand Against BREACH Attack」這篇提到 Facebook 在 2012 年對抗 BREACH attack 的方法:

在文章最後面有提到當時一般建議的 migrate 方式 (關閉 TLS 的壓縮) 不適用於 Facebook:

Turning off compression is not an option for large dynamic sites such as Facebook because it would hinder performance dramatically.

而且就算關掉 TLS 的 compression,也還是有疑慮:

Even if TLS-level compression is disabled, it is very common to use gzip at the HTTP level. Furthermore, it is very common that secrets (such as CSRF tokens) and user input are included in the same HTTP response, and therefore (very likely) in the same compression context,

節錄幾段 migrate 的重點:

Facebook disclosed how it’s mitigating BREACH attacks by changing the frequency in which it rotates CSRF tokens from daily to each time a Facebook session is started.

本來 CSRF token 變更的頻率是好幾天一次,把頻率拉高...

After a new token is issued, the previous tokens still remain valid for a couple days, resulting in multiple tokens being permissible simultaneously.

然後舊的 token 還是會保持一段時間有效。

因為現實因素而沒辦法在 TLS 層關閉,後面在 application level 的 workaround 相當費功... (而且要多花不少資源?)

CloudFlare 停用 RC4 後的現象,以及後續...

今年一月的時候 CloudFlare 宣佈針對使用 TLS 1.1+ 的使用者停用 RC4:「Killing RC4 (softly)」。

而現在 (五月) 則直接從 cipher priority 上拔掉 RC4:「Killing RC4: The Long Goodbye」。

切換後的資料其實非常有趣:

可以看到本來用 RC4 的有兩塊,一塊是 ECDHE-RC4,一塊是 RSA-RC4。在 RC4 被拿掉後,就流竄到 ECDHE-AES-CBC 與 RSA-AES-CBC... (這兩個本來就可以預期)

但冒出 RSA-3DES 是怎樣 XDDD

Anyway,CloudFlare 在目前市場上算是很大的 provider,由他們出面率先拔掉 RC4 會對整個市場有正面的影響。接下來看看還有誰會動手?

使用 SSL 連上 Freenode IRC server

ijliao 長輩的 blog 上看到「weechat」這篇才想起來 Freenode 有提供 SSL 連線。

可以在「About freenode: IRC Servers」這頁看到 SSL port 的連線資訊:

All freenode servers listen on ports 6665, 6666, 6667, 6697 (SSL only), 7000 (SSL only), 7070 (SSL only), 8000, 8001 and 8002.

其中 port 6698/7000/7070 是 SSL only,所以就拿這幾個用。由於我是在 Ubuntu 上跑 ppa 版的 WeeChat,所以基本上只加上這三行就可以了:

/set irc.server.freenode.address chat.freenode.net/6697
/set irc.server.freenode.ssl on
/set irc.server.freenode.ssl_dhkey_size 1024

連上後應該會看到類似的訊息:

gnutls: connected using 1024-bit Diffie-Hellman shared secret exchange
gnutls: receiving 2 certificates
 - certificate[1] info:
   - subject `OU=Domain Control Validated,OU=Gandi Standard Wildcard SSL,CN=*.freenode.net', issuer `C=FR,O=GANDI SAS,CN=Gandi Standard SSL CA', RSA key 2048 bits, signed using RSA-SHA1, activated `2014-01-13 00:00:00 UTC', expires `2015-01-14 23:59:59 UTC', SHA-1 fingerprint `2df8bb8922e69f781ef5abcd234fffde0490be21'
 - certificate[2] info:
   - subject `C=FR,O=GANDI SAS,CN=Gandi Standard SSL CA', issuer `C=US,ST=UT,L=Salt Lake City,O=The USERTRUST Network,OU=http://www.usertrust.com,CN=UTN-USERFirst-Hardware', RSA key 2048 bits, signed using RSA-SHA1, activated `2008-10-23 00:00:00 UTC', expires `2020-05-30 10:48:38 UTC', SHA-1 fingerprint `a9f79883a075ce82d20d274d1368e876140d33b3'
gnutls: peer's certificate is trusted

然後在 status line 裡,server[freenode] 的部份變成綠色的。

OpenSSL 的 Heartbleed 漏洞不限於 Server,也包含 Client...

Heartbleed 是惡意的 client 可以利用 OpenSSLHeartbeat Extension 漏洞取得 server 的機敏資訊。

而在「Testing for "reverse" Heartbleed」這篇說明 (並且 PoC) 這組漏洞也適用於反向的操作,也就是惡意的 server 可以取得 client 的資訊。

exploit 相較起來比正向的難一些,但還是可行並且成功做出來了。文章裡有描述怎麼實做的...

換句話說,反正手上的 OpenSSL 都趕快升級...

OpenSSL 安全漏洞 (CVE-2014-0160)

CVE-2014-0160,又稱 Heartbleed Bug,是 OpenSSL 在 TLS 與 DTLS 協定裡的 Heartbeat Extension (RFC 6520) 的錯誤實作。

OpenSSL 官方的 security advisory 在這:「OpenSSL Security Advisory [07 Apr 2014]」,影響的範圍是:

Only 1.0.1 and 1.0.2-beta releases of OpenSSL are affected including 1.0.1f and 1.0.2-beta1.

實務上爆炸的程度則是:

A missing bounds check in the handling of the TLS heartbeat extension can be used to reveal up to 64k of memory to a connected client or server.

比較有描述性的說明可以參考「The Heartbleed Bug」這個站的敘述:

We have tested some of our own services from attacker's perspective. We attacked ourselves from outside, without leaving a trace. Without using any privileged information or credentials we were able steal from ourselves the secret keys used for our X.509 certificates, user names and passwords, instant messages, emails and business critical documents and communication.

由於 untraceable,這代表我們必須假設所有受影響機器上的 SSL private key 都已經被洩漏出去了,所有的 key 都必須 revoke 並且重新產生 (& 重新簽)。這兩天讓所有 SA 爆炸的超大新聞...

SSL/TLS 的 Perfect Forward Secrecy...


寫這篇順便測試 MathJax 的效果...

因為 NSA 的惡搞,這陣子 PFS (Perfect Forward Secrecy) 突然被拿出來討論:

在講 PFS 前,得先講 Diffie-Hellman key exchange (D-H)。

D-H 是利用這個等式:

$$(g^a)^b \equiv (g^b)^a \mod p$$

其中 \(p\) 是大質數,而 \(g\) 是 \(p\) 的 primitive root (即不存在任何 \(n < p\) 可以使得 \(g^n \equiv 1 \mod p\))。 而因為當 \(p\) 夠大時,要從 \(g^a \mod p\) 計算 \(a\) 就是離散對數問題,而離散對數問題是已知沒有有效率計算的問題,所以我們會假定當 \(p\) 夠大時,傳輸 \(g^a \mod p\) 是無法用合理資源計算得知 \(a\)。

因此,Alice 與 Bob 就可以產生自己的 private secret \(a\) (Alice) 與 \(b\) (Bob),計算出 \(g^a\) 與 \(g^b\) 後公開傳輸給對方,當 Bob 收到 Alice 提供的 \(g^a\) 時就計算 \((g^a)^b \equiv g^{ab} \mod n\),而 Alice 收到 Bob 提供的 \(g^b\) 後可以計算 \((g^b)^a \equiv g^{ba} \equiv g^{ab} \mod n\)。

而攻擊者只拿到公開的 \(g^a\) 與 \(g^b\) 以及 \(g\),無法計算出 \(g^{ab}\),於是就雙方就建立一組 shared secret 了。

回到 SSL/TLS 的問題上,由於 RSA 加解密的速度並不快,所以 SSL/TLS 是在 RSA 的保護下交換 RC4 或是 AES 所需要的金鑰 (key)。

交換 key 這件事情除了可以直接交換以外,還可以利用 D-H 交換。

D-H 交換可以確保當 RSA key 被破解時還要再破每個 session 的 D-H 所產生出來的 key,而直接交換的話,只要破一把 RSA key 就可以解出所有 traffic 了。

而 PFS 會被提出來,是因為目前消息指出 NSA 其實有在錄下 SSL/TLS 流量,等哪天有機會取得 RSA key 的時候 (無論是硬解,或是其他方式),就有機會能夠一次破一卡車資料... (因為目前大部分的 SSL/TLS 流量都沒有上 PFS)

雖然 PFS 會慢一些,不過已經確認 NSA 打算來搞了,所以還是乖乖加上去吧... @_@

Facebook 將全面支援 SPDY...

在「Facebook Adds SPDY Support!」看到 Facebook 將全面支援 SPDY 的消息。

Facebook 的 *.fbcdn.net 在二月先上 SPDY 了:

I managed to find this image uploaded by Varun Kumar on February 1 2013, showing that Facebook’s CDN hostname *.fbcdn.net was serving static resources like images and JavaScript via SPDY.

m.facebook.com (行動版) 也上 SPDY 了,不過要 Android 3+ 才支援。

目前 SPDY 主要支援的平台是 Firefox 13+ (11+ 支援,但預設沒開),Google Chrome 與 Android 3+,市占率大約 50%... 好像也不少?(參考:Can I use SPDY networking protocol?)

SSL/TLS 的問題...

這篇與「對稱式加密系統的爆炸歷史 (Authenticated encryption 的問題)」這篇相關,建議可以一起看一看。

TLS (Transport Layer Security),前身是 SSL (Secure Sockets Layer),是目前 HTTPS 所使用的加密協議。發展的順序上是 SSLv2、SSLv3、TLSv1、TLSv1.1、TLSv1.2。

然後有兩篇文章可以看:

第一篇文章講 Padding oracle attack,第二篇文章是酸 SSL/TLS 的修正愈修愈歪... XD

AES 這類的 block cipher 在加密或解密時會要求切齊 block size,以 AES 的要求就是 128bits (16 bytes)。

而對於不齊的資料要怎麼加密呢?其中一個方法是 PKCS#7:(圖片取自第二篇文章)

Padding

要想辦法補齊 128bits (16bytes),如果像上圖需要補 7bytes 進去,就都補上 \x07 (剛好就是補上長度),另外在最後面會補上 padding 的長度,而問題出就出在這個設計先天就有缺陷:在 SSL/TLS 所使用的 MAC-then-Encrypt 中,MAC 只計算原文的值,沒有保護到 padding 的部份,於是就可以針對 padding 的部份想辦法找到洞鑽。

pseudo code 可能是這樣:

// Decrypt to plaintext + mac + padding
$plaintext_mac_padding = decrypt($ciphertext);
if (NULL != $plaintext_mac_padding) {

    // Now decode padding part
    $plaintext_mac = decode_padding($plaintext_mac_padding, $padding_length);
    if (NULL != $plaintext_mac) {

        // Now check MAC part
        $plaintext = check_mac(plaintext_mac);
        if (NULL != $plaintext) {

            // Now it's okay
        }
    }
}

攻擊者亂改 $ciphertext 會導致解出來的 padding 也亂掉,但早期的 SSL 會回傳「padding error」這種對攻擊者有利的資訊,而導致攻擊者可以利用這個資訊想辦法得知更多內容。

而 TLS 並沒有從根本改善,而是試著加上機制補西牆:當遇到錯誤時就跳過,不要傳回錯誤資訊。

但因為攻擊者亂改封包造成 decode_padding() 會失敗,而沒有呼叫到 check_mac()。這導致了大量的計算時間差與能量差,而使得攻擊者可以藉由這些資訊而得知是否成功。而官方在 TLSv1.2 的建議是再補上機制來補洞:

In general, the best way to do this is to compute the MAC even if the padding is incorrect, and only then reject the packet. For instance, if the pad appears to be incorrect, the implementation might assume a zero-length pad and then compute the MAC.

而官方認為雖然這樣還是有 timing channel,但已經小到會被雜訊覆蓋,所以「應該」可以解決問題:

This leaves a small timing channel, since MAC performance depends to some extent on the size of the data fragment, but it is not believed to be large enough to be exploitable, due to the large block size of existing MACs and the small size of the timing signal.

於是,只要覺得「應該安全吧」,就會「應該會被破」:「Lucky Thirteen: Breaking the TLS and DTLS Record Protocols」:

The attacks apply to all TLS and DTLS implementations that are compliant with TLS 1.1 or 1.2, or with DTLS 1.0 or 1.2. They also apply to implementations of SSL 3.0 and TLS 1.0 that incorporate countermeasures to previous padding oracle attacks. Variant attacks may also apply to non-compliant implementations.

這 SSL/TLS 的設計讓人補到快起笑了... XD

資安的東西通常是愈複雜就愈容易被抓問題出來,在 SSL/TLS 的歷史包袱下,不知道什麼時候才想換 Encrypt-then-MAC 來改善底層問題...

加快 SSL 加解密速度...

看到 Ash Wu 貼的「5 easy tips to accelerate SSL」:

先列出原作者在文章裡給的結論:

ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:RC4+RSA:+HIGH:+MEDIUM

不過,現在考慮 SSL 效能以行動平台為主 (因為桌機用軟體計算也超快),而行動平台中 iOS 可以對 AES 與 SHA1 硬體加速 (iOS 4.3+),Android 一般的情況下看起來沒得用,所以就自己取捨啦...

對稱式加密系統的爆炸歷史 (Authenticated encryption 的問題)

在「Disasters」這邊列了不少對稱式加密系統 (secret-key cryptography) 爆炸的歷史,其中提到了很多 Encrypt 與 MAC 結合時的問題 (Authenticated encryption)。另外 Colin Percival 在 2009 年的時候有寫了一篇為什麼要用 Encrypt-then-MAC 的文章:「Encrypt-then-MAC」,當時 Colin Percival 寫的時候大家還是不能理解,但現在回頭看上面的爆炸歷史應該就清楚很多了 XDDD

SSH 協定是使用 Encrypt-and-MAC (傳輸「密文」與「明文的 MAC 值」)。在 2008 年時 SSH 使用 CBC 模式時會有安全問題:對 128bits CBC mode system (像是 aes128-cbc),任意位置的 32bits 有 2-18 的機會可以解出原文。(CVE-2008-5161,論文是「Plaintext Recovery Attacks Against SSH」)

TLS 1.0 (SSLv3) 使用 MAC-then-Encrypt (傳輸「明文與明文的 MAC 值」加密後的結果)。1999 年就知道這個方法不可靠,不過到了 2011 年時才被拿出來示範,也就是 BEAST attack。(CVE-2011-3389,在 ekoparty Security Conference 上的「表演」:「BEAST: Surprising crypto attack against HTTPS」,連結1連結2)

OpenSSLGnuTLS 所實作的 DTLS 在 2011 年也被炸到,其中 OpenSSL 是 100% plaintext recovery,GnuTLS 是 4%。(CVE-2012-0390,論文是「Plaintext-Recovery Attacks Against Datagram TLS」)

而 Encrypt-then-MAC (傳輸「密文」與「密文的 MAC」) 是三者裡面最不容易出包的作法,而且被證明 Provable security:Encrypt 與 MAC 所用的 crypto system 的安全強度不會因為 Encrypt-then-MAC 而減少。而這也是 IPSec 的作法。

附帶一提,其中 Provable security 這個詞,並非表示「可被證明是安全的」,在「In defense of Provable Security」這篇文章裡有比較完整的說明。通常是指安全強度不會因為這個系統而降低:以 Encrypt-then-MAC 的例子來說,如果 Encrypt 的部份用 DES,或是 MAC 用 CRC32,那麼 Encrypt-then-MAC 並不會提供更強的安全性...

總而言之,MAC-then-Encrypt 與 Encrypt-and-MAC 的方式要小心才能避免各種攻擊 (像是不能用 CBC mode),而 Encrypt-then-MAC 可以讓設計協定的人放鬆到「只要 Encrypt 與 MAC 都夠強」系統就沒問題。在 Authenticated encryption 裡提到的 ISO/IEC 19772:2009 支援六個模式,有些有專利問題,有些演算法看起來就很複雜 (於是就容易出包),其中 Encrypt-then-MAC 看起來是個還不錯的方案...