iOS 7.0.6 / 6.1.6 修正了什麼安全問題?

iPhone 5s 升級7.0.6後在蜂窩數據下無法打開非 Https 網頁,大家有這種現象么?


我是來糾正前排同學的,雖然這位同學正確的指出了導致問題的代碼。

  1. 受影響的部分並不是安全連接中的證書驗證部分。也就是說如果你的證明書不是由被認可的機構簽發的、或者不匹配你的域名,在出問題的設備上仍舊是會彈出警告的。
  2. 水果系統下的成功執行`curl -s https://213.133.107.227/ --head`的事,被認為是curl自身的問題。可以拿wget或者Safari來試驗,都是會有警告的。

真正的問題其實更複雜一點。

簡單的說就是,
進行安全連接的時候,伺服器和客戶端會生成新的臨時鑰匙用來加密交換的信息。
這個過程中,伺服器需要發給客戶端自己的公開證書,以及用證書配對的私有鑰匙簽名後的臨時鑰匙。
而客戶端不僅需要驗證證書的合法性,還要驗證臨時鑰匙以證實伺服器端的確是擁有該證書對應的私有鑰匙的。這就是這次出問題的地方。多出的這一行`goto`導致了這個必須得驗證被跳過了。

所有受影響的系統下,使用DHE或者ECDHE協議進行的安全連接都有可能被劫持(不僅僅包括瀏覽器里的Https)。另外,Chrome和Firefox因為使用NSS協議,所以是安全的。

最後補上相關好文一篇
https://www.imperialviolet.org/2014/02/22/applebug.html


TL; DR: 修正了SSL鏈接時不驗證域名與證書中的域名匹配的問題[1]
===
之前的回答可能有點簡單了,這裡詳細地說一說。

眾所周知,在使用SSL連接的時候,會驗證域名與證書中的域名是否匹配。

什麼是證書呢?證書類似於伺服器的身份證。上面存儲的信息可以用來鑒別伺服器的身份,從而保證SSL加密的有效性。[4]

比如在訪問https://example.com 的時候,瀏覽器會檢查證書中的域名和example.com是否匹配。[2] 如果不做檢查的話,會出現什麼情況呢?任何一個攻擊者都可以用一個合法的證書來偽造自己的身份。

比如我是http://abc.com的站長,那麼我可以通過合法的渠道獲得http://abc.com的證書,在這之後,如果我劫持了http://def.com,那麼在SSL驗證的時候,瀏覽器會檢查這個證書。假如這個瀏覽器工作正確的話這個過程大概是這樣的:

Client: ClientHello(你好)
Server(def.com, 被http://abc.com劫持): ServerHello(你好,我是http://def.com)
Server(def.com, 被http://abc.com劫持): 這裡是我的證書,xxxxxxx (不信?給你看我的身份證)
Server(def.com, 被http://abc.com劫持): ServerHelloDone
Client: 檢查證書中的域名為 "http://abc.com", 實際應訪問的地址為"http://def.com"。卧槽,不匹配,肯定有人在幹壞事!!!Run fast, run far!!![3] 告訴用戶你訪問的這個地址給了我一個偽造的身份證,肯定不是什麼好人!!快跑!!

這時候用戶的瀏覽器上會提示:
The site"s security certificate is not trusted!

從而用戶就會意識到這次連接存在加密問題,可能會被人使用MITM[5](中間人攻擊)來監聽。

從而用戶就會意識到這次連接存在加密問題,可能會被人使用MITM[5](中間人攻擊)來監聽。
但是如果不做檢查的話,就會是這樣:

Client: ClientHello(你好)
Server(def.com, 被http://abc.com劫持): ServerHello(你好,我是http://def.com)
Server(def.com, 被http://abc.com劫持): 這裡是我的證書,xxxxxxx (不信?給你看我的身份證)
Server(def.com, 被http://abc.com劫持): ServerHelloDone
Client: 這個身份證是合法的,是政府發的唉,看來這次連接沒有問題,那麼,我的銀行卡密碼是xxxxx......

發現問題了嗎?這裡的證書是合法的,但是證書卻不是頒發給你要訪問的域名!這就好像有人拿著你的身份證並且說他就是你一樣!

===

"congrats to the Apple iOS team on adding SSL/TLS hostname checking in their latest update! very cool feature."

事實上,這個問題是由libsecurity_ssl這個庫引發的。所以他存在於所有使用了這個庫的軟體里。這裡包括了Mac OS X。 如果用curl訪問的話,就會是這樣:[6]

$curl -s https://213.133.107.227/ --head
HTTP/1.1 200 OK
Date: Thu, 28 Nov 2013 17:58:40 GMT
Server: Apache
X-Powered-By: PHP/5.3.27
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Pragma: no-cache
Set-Cookie: exp_last_visit=1070301520; expires=Fri, 28-Nov-2014 17:58:40 GMT; path=/
Set-Cookie: exp_last_activity=1385661520; expires=Fri, 28-Nov-2014 17:58:40 GMT; path=/
Set-Cookie: exp_tracker=a%3A1%3A%7Bi%3A0%3Bs%3A5%3A%22index%22%3B%7D; path=/
Last-Modified: Thu, 28 Nov 2013 17:58:40 GMT
Content-Type: text/html; charset=UTF-8

然而,同樣的命令在Ubuntu裡面卻有不同的表現:

# curl https://213.133.107.227/
curl: (51) SSL: certificate subject name "*.hetzner.de" does not match target host name "213.133.107.227"

注意最後一行,curl發現了證書的問題:證書是頒發給"*.hetzner.de",然而當前訪問的卻是"213.133.107.227"。

===
真的,你讀到這了?
那我們就來討論一點細節
為啥會這樣?
我們來看實現這一段檢查的代碼[7]:

static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
...
if ((err = SSLHashSHA1.update(hashCtx, signedParams)) != 0)
goto fail;
goto fail;
// 重點在這裡!!
if ((err = SSLHashSHA1.final(hashCtx, hashOut)) != 0)
goto fail;

err = sslRawVerify(ctx,
ctx-&>peerPubKey,
dataToSign, /* plaintext */
dataToSignLen, /* plaintext length */
signature,
signatureLen);
if(err) {
sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
"returned %d
", (int)err);
goto fail;
}

fail:
SSLFreeBuffer(signedHashes);
SSLFreeBuffer(hashCtx);
return err;

}

注意我在注釋里標註出來的代碼。那個goto看起來只是一個簡單的重複,但是學過c的各位應該明白,這個goto是不在前面if的scope裡面的!
也就是說,這裡的goto無論如何都會執行。導致的問題就是:從goto到fail:這段範圍內的代碼全部都永遠不可能被執行!


===

也許這只是偶然,也許這只是一次merge裡面的失誤。但是也可以有點陰謀論。還記得從前linux代碼中的這一段嗎?

if ((options == (__WCLONE|__WALL)) (current-&>uid = 0)) retval = -EINVAL;

Oops,應該是uid == 0 還是uid = 0?
這一行代碼被執行到的話,當前用戶就是root了。
世界真是太不美好了
===
References:
[1] Apple.com, About the security content of iOS 7.0.6
[2] Wikipedia, Transport Layer Security
[3] WordPress, http://bigbangtrans.wordpress.com/series-3-episode-22-the-staircase-implementation/
[4] Wikipedia, Public key certificate
[5] Wikipedia, Man-in-the-middle attack
[6] Github, https://gist.github.com/rmoriz/fb2b0a6a0ce10550ab73
[7] opensource.apple.com, sslKeyExchange.c


IOS7開始強制需要 https,是為了用戶安全考慮的


推薦閱讀:

微軟為何能單方面的終止對 Vista 和 XP 系統的支持?
Jony Ive 推動 iOS 採用扁平化設計(Flat Design),這會有什麼影響?

TAG:互聯網 | 信息安全 | SSL | HTTPS | iOS 7 |