qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          蘋果 SSL/TLS Bug的細節

          字體:        | 上一篇 下一篇 | 打印  | 我要投稿  | 推薦標簽: Bug 蘋果 測試技術

            近日,蘋果向iOS用戶推送了一個安全更新,指出在iOS系統中SSL/TLS安全連接存在嚴重的bug,但并沒有給出更詳細的說明。對此問題的解答已經出現在Hacker News的頭條,我想大家都已經知道了這個漏洞,也不需要再胡亂猜測了。
            以下就是導致這個bug的一段代碼:
          static OSStatus
          SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
          uint8_t *signature, UInt16 signatureLen)
          {
          OSStatus        err;
          ...
          if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
          goto fail;
          if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
          goto fail;
          goto fail;
          if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
          goto fail;
          ...
          fail:
          SSLFreeBuffer(&signedHashes);
          SSLFreeBuffer(&hashCtx);
          return err;
          }
            注意其中有兩個連續的go to fail語句,第一個會正確地在if判斷為真時執行,但是第二個卻在任意情況下都會執行,盡管它有著看似標準的語句縮進。于是當代碼跳轉至fail時,由于認證使用的final方法還未執行,而update方法執行成功,因此err會包含一個校驗成功的信息,導致對簽名的認證永遠不會失敗。
            認證簽名時將會檢測ServerKeyExchange消息中的簽名,它用于DHE和ECDHE加密套件(多種加密算法聯合使用)在建立連接時獲取會話密鑰(ephemeral key,本次會話的臨時密鑰)。服務器告訴客戶端:“這是給你的會話密鑰和簽名,通過我的證書,你可以確定密鑰和簽名是來自于我的。”而現在會話密鑰和證書鏈之間的關聯已經斷裂,所有曾經安全的認證都不再有效。這意味著,服務器可以向客戶端發送正確的證書鏈,但在連接握手的過程中使用錯誤的私鑰進行簽名甚至干脆不簽名,因為我們無法確認這個服務器是否持有對應此證書的正確的私鑰。
            這個Bug出現在SecureTransport的代碼中,它將影響iOS的某個早期版本直到7.0.6(其中7.0.4我已經確認過),同時也會影響OS X系統(在10.9.1上已經得到確認)。所有使用了SecureTransport的地方都會被波及到,也就等于是絕大部分蘋果系統上的軟件。Chrome和Firefox在SSL/TLS連接中使用的NSS,因此得以幸免。然而如果你的軟件更新程序使用了SecureTransport,那么前面的討論都不能說明什么了。(譯注:更新程序可能連接到仿冒主機。)
            對此我構建了一個簡單的測試網站:https://www.imperialviolet.org:1266。注意端口號(1226是這個漏洞在CVE里的編號),443端口運行著一個正常的網站,而1226端口的網站將會發送使用錯誤私鑰簽名的證書。如果你使用https連接去訪問,就能夠重現這個bug。
            即使證書鏈是正確的,由于它和連接握手之間的關聯已經被破壞,我認為任何形式的證書鎖定都無法阻止這種錯誤的認證。同時,這個bug不僅僅影響使用DHE或者ECDHE加密套件的網站,因為攻擊者可以自行選擇合適的加密套件。
            在TLS 1.2的針對ServerKeyExchange消息的認證是使用的另一個方法,因此沒有受到影響。但仍然有上面提到的問題,攻擊者可以選擇任何客戶端能夠使用的版本。當然如果客戶端僅支持TLS 1.2,那就完全沒有問題了??蛻舳艘部梢灾皇褂妹魑?RSA加密套件,那么就不存在ServerKeyExchange消息,同樣起到了防范的效果。(當然在這兩種方法中,前一種更加可取。)
            根據我的測試發現,iOS 7.0.6已經修復了這個問題,但是在OS X 10.9.1中仍然存在。(補充:好像這個bug在OS X系統中是在10.9版引入的,但是iOS6的某些版本中就早已出現了。iOS 6.1.6昨天修復了此bug。)這樣潛伏在代碼深處的bug簡直就是一個噩夢。我相信這僅僅是個失誤,但無論是誰手滑(手賤)把這樣的代碼寫出來,我都為他感到深切的悲痛。
            下面是一段和這個bug有相同問題的代碼:
          extern int f();
          int g() {
          int ret = 1;
          goto out;
          ret = f();
          out:
          return ret;
          }
            如果我編譯時候加上參數-Wall(啟用所有警告),在Xcode中無論是GCC 4.8.2還是Clang 3.3都沒有對死代碼發出警告,對此我非常驚訝。更好的編譯警告本可以阻止這樣的悲劇,又或許在實際編碼中這類警告發生第一類錯誤(棄真錯誤)的概率太高?(感謝Peter Nelson指出在Clang可以使用-Wunreachable-code參數對這樣的問題發出警告,而不是-Wall。)
            看起來是允許if代碼塊不使用大括號才導致了這樣的代碼風格,但是有人在大括號里也可能使用錯誤的代碼縮進,因此我也沒覺得大括號帶來了多少便利。
            寫一個測試用例本可以發現這個問題,但是由于它深嵌在連接握手的過程中,所以非常復雜。這個用例需要寫一個完全獨立的TLS棧,并且包含大量發送無效握手請求的配置。在Chromium中我們有個修改過的TLSLite工具可以做類似的測試,但是我不太記得我們的用例是否完全適用于這個bug的情況。(如果不行的話,聽起來好像我已經知道周一早上要干嘛了)(譯注:當然是把用例改到可以完全適用)
            代碼審查對發現這類bug非常有效。不僅僅是瀏覽審閱,而是審查每句新寫的代碼。我不知道蘋果一般怎么做代碼審查,但是我充分相信我的同事,Wan-Teh和Ryan Sleevi。如果我意外手滑,他們一定會及時發現。可惜不是每個人都有幸和這樣的同事一起工作。
            最近,針對蘋果忽略對證書中主機的校驗這個事情,有一系列討論。的確在OS X中使用curl時,即使IP地址不在證書中,命令行也會接受和這個主機的連接。然而我沒找到更多問題了,Safari也沒有受到影響。

          posted on 2014-02-26 11:07 順其自然EVO 閱讀(313) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2014年2月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          2324252627281
          2345678

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 富源县| 玉山县| 五华县| 天峨县| 莫力| 万荣县| 明星| 萨迦县| 九寨沟县| 秦安县| 乐昌市| 玛曲县| 双城市| 洛浦县| 奇台县| 遵义市| 德庆县| 金秀| 红河县| 平潭县| 楚雄市| 平阳县| 读书| 德州市| 昆明市| 宜兰市| 武陟县| 华宁县| 墨脱县| 三河市| 甘南县| 太仓市| 朝阳县| 将乐县| 新民市| 朝阳区| 彝良县| 莱西市| 盘锦市| 靖远县| 安岳县|