一次WAF的SNI時間排查

      網友投稿 872 2025-03-31

      0x00 背景

      近日華為云WAF團隊收到一個WAF旗艦版客戶反饋的問題,他們的APP在部分安卓機上無法正常使用,取消WAF后又正常。秉承著“以客戶價值為依歸”的理論,我們立馬對相關問題進行排查。首先客戶的站點是HTTPS的,然后出問題的終端是部分系統版本比較低的安卓手機,這里可以初步判斷是因為這部分終端不支持SNI造成的。

      SNI具體的內容在第三節中將會詳細介紹,請稍等。

      0x01 定位

      為了驗證我們的推斷,我在自己模擬器上面安裝了客戶的APP,針對手機瀏覽器和APP分別進行抓包,查看SNI的情況。

      這里我們模擬器使用的Genymotion,系統采用的安卓5.1.0,大概的截圖如下:

      TIPS:這個模擬器是基于X86架構,跑起來非常快,但是我們目標APP是ARM架構的,直接還不能運行,我們需要安裝額外的ARM-Translate的,這個就不在本文中介紹了,后面我會專門有文章來介紹,或者有需要的朋友可以直接聯系我。

      我們就在宿主機上面用Wireshark抓包即可,抓包過程也非常簡單,就是分別使用瀏覽器打開目標網址和用APP登錄,我直接給出抓包截圖,我們對比看一下吧。

      首先是瀏覽器的抓包:

      后面這個是APP的包

      兩者區別在于SSL握手時候Client的擴展字段有沒有SNI字段。

      0x01 SNI介紹

      SNI是Server Name Indication的縮寫,是為了解決一個服務器使用多個域名和證書的SSL/TLS擴展。它允許客戶端在發起SSL握手請求時(客戶端發出ClientHello消息中)提交請求的HostName信息,使得服務器能夠切換到正確的域并返回相應的證書。

      在SNI出現之前,HostName信息只存在于HTTP請求中,但SSL/TLS層無法獲知這一信息。通過將HostName的信息加入到SNI擴展中,SSL/TLS允許服務器使用一個IP為不同的域名提供不同的證書,從而能夠與使用同一個IP的多個“虛擬主機”更方便地建立安全連接。

      SSL握手

      HTTPS其實是將HTTP的請求使用TLS加密后使用TCP協議傳輸給目的方,幾者之間的關系如下:

      TLS加密需要需要在TCP連接建立之后,雙方進行SSL握手,協商隨機數和證書。大概的過程是這樣的:

      這里和我們這次文章比較相關的部分就是客戶端發送Hello后,服務端返回證書,客戶端校驗證書有效性。

      NGINX反向代理

      在現在互聯網時代,IP地址越來越緊張,因此我們經常會將多個域名或者網站使用同一臺服務器,同一個IP。NGINX通常就是這樣的網關。當一個HTTP請求到達時候,NGINX會通過HTTP請求中的Host頭來決定轉發目的服務器。

      NGINX要能夠正常的轉發,那么它必須能夠解析HTTP協議,從上面圖中,我們可以看到HTTPS請求中HTTP內容被TLS加密,NGINX在使用前必須進行解密,而解密需要雙方協商證書。好的,問題就來了,如果是多個HTTPS網站共享一個IP和端口,SSL握手時候,服務端如何正確選擇域名證書傳輸給客戶端呢?

      為了解決這個問題在RFC 6066中對TLS的擴展進行了定義,其中就提到了在握手階段一個server_name的擴展,它的內容就是域名的名字。服務端在接收到含有SNI的Client Hello后,根據其內容,去選擇該域名的證書返回給客戶端。

      記一次WAF的SNI時間排查

      因此從上面的解釋看出來,這個問題并不是只有WAF才會存在,而是綁定了同一個IP+端口的多個HTTPS網站都會遇到這樣的問題。

      0x02 APP分析

      在上面定位中,我們同一個系統,瀏覽器攜帶了SNI,但是客戶的APP沒有,因此我們決定對客戶的APP再進行一輪分析。這里需要使用到JEB工具對客戶的APK進行逆向分析。根據activity去查找登錄方法所使用HTTP包即可。我們最后定位到MobileHttpClientManager類,實現的代碼大致如下:

      從代碼里面看到,使用的SDK默認的DefaultHttpClient,從相關文章我們知道HttPClient默認是不使用SNI的。

      0x02 解決方案

      Android

      通常情況下,我們可以使用其他默認支持SNI的庫,比如URLConnection,OKHttp等

      try?{ ????URL?url?=?new?URL("https://www.huaweicloud.com"); ????URLConnection?urlConnection?=?url.openConnection(); ????HttpsURLConnection?connection?=?(HttpsURLConnection)?urlConnection; ????connection.setRequestProperty("Host",?"www.huaweicloud.com"); ????connection.setHostnameVerifier(new?HostnameVerifier()?{????????@Override ????????public?boolean?verify(String?hostname,?SSLSession?session)?{????????????return?HttpsURLConnection.getDefaultHostnameVerifier().verify("www.huaweicloud.com",?session); ????????} ????}); ????connection.connect(); }?catch?(Exception?e)?{ ????e.printStackTrace(); }?finally?{ }

      自 Android 2.3 開始,HttpsURLConnection 就支持 SNI。如果您需要支持 Android 2.2(及更舊的版本),一種解決辦法是在一個唯一端口上設置備用虛擬主機,以便了解要返回哪個服務器證書。

      比較極端的替代方法是不使用服務器默認情況下返回的驗證程序,而是將 HostnameVerifier 替換為不使用您的虛擬機主機名的驗證程序

      雖然HttpClient的4.3.2版本在Oracle JRE 1.7+已經支持SNI了,但是Android可不是使用的Oracle的JRE啦,這個涉及到版權等問題。

      我們最好是使用時,手動設置一下HostName。

      //?Android?specific?code?to?enable?SNIif?(Build.VERSION.SDK_INT?>=?Build.VERSION_CODES.JELLY_BEAN_MR1)?{????if?(Log.isLoggable(TAG,?Log.DEBUG))?{ ????????Log.d(TAG,?"Enabling?SNI?for?"?+?target); ????}????try?{ ????????Method?method?=?sslsock.getClass().getMethod("setHostname",?String.class); ????????method.invoke(sslsock,?target); ????}?catch?(Exception?ex)?{????????if?(Log.isLoggable(TAG,?Log.DEBUG))?{ ????????????Log.d(TAG,?"SNI?configuration?failed",?ex); ????????} ????} }

      從代碼也看到了,這個需要安卓4.2.2以后的版本才是支持的。

      iOS

      因為CFNetwork是支持SNI的,因此我們只需要判斷協議然后決定是用上層的網絡請求轉發還是用底層的cfnetwork來轉發。

      if?([self.request.URL.scheme?isEqualToString:@"https"]?)?{????????//使用CFnetwork ????????curRequest?=?req; ????????self.task?=?[[CustomCFNetworkRequestTask?alloc]?initWithURLRequest:originalRequest?swizzleRequest:curRequest?delegate:self];????????if?(self.task)?{ ????????????[self.task?startLoading]; ????????} ????}?else?{????????//使用普通網絡請求 ????????NSURLSessionConfiguration?*configuration?=?[NSURLSessionConfiguration?defaultSessionConfiguration]; ????????self.session?=?[NSURLSession?sessionWithConfiguration:configuration?delegate:self?delegateQueue:[NSOperationQueue?mainQueue]]; ????????NSURLSessionTask?*task?=?[self.session?dataTaskWithRequest:req]; ????????[task?resume]; ????}

      瀏覽器

      目前不管是PC還是移動端,主流的現代瀏覽器都是支持SNI的。

      0x03 參考鏈接

      [1]?SNI中文維基百科

      [2]?SSL握手介紹

      [3]?SSL/TLS協議介紹

      [4]?iOS的HTTP DNS方案

      waf

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何用單元格值保存Excel文件
      下一篇:Excel表格如何限制重復值輸入(excel表格怎么避免輸入重復數據)
      相關文章
      亚洲国产精品无码久久98| 亚洲精品99久久久久中文字幕| 亚洲一区精品中文字幕| 亚洲人配人种jizz| 国产AⅤ无码专区亚洲AV| 亚洲一卡2卡4卡5卡6卡残暴在线| 91麻豆国产自产在线观看亚洲| 成人伊人亚洲人综合网站222| 亚洲αv久久久噜噜噜噜噜| 亚洲成av人在线观看网站| 亚洲精品天堂在线观看| 亚洲日本一区二区| 中文字幕亚洲综合久久菠萝蜜 | 国产精品亚洲五月天高清| 亚洲精品国产情侣av在线| 亚洲一区无码中文字幕| 久久综合亚洲色hezyo| 亚洲国产综合精品| 亚洲伊人久久大香线蕉苏妲己| 亚洲AV福利天堂一区二区三| 在线日韩日本国产亚洲| 亚洲欧洲日产国码无码久久99 | 亚洲Av无码专区国产乱码DVD | 亚洲久热无码av中文字幕| 亚洲精品午夜久久久伊人| 亚洲精品偷拍无码不卡av| 亚洲av永久无码嘿嘿嘿 | 亚洲乱码一二三四区乱码| 亚洲午夜无码久久久久小说| 亚洲一区二区三区无码国产| 亚洲看片无码在线视频| 亚洲精品无码久久久久YW| 亚洲丰满熟女一区二区哦| 另类专区另类专区亚洲| 亚洲综合色成在线播放| mm1313亚洲精品无码又大又粗| 亚洲麻豆精品国偷自产在线91| 国产成人亚洲精品狼色在线| 亚洲Aⅴ无码专区在线观看q| 亚洲综合激情另类小说区| 在线综合亚洲欧洲综合网站|