以下內容為自己的一些經歷和一些查閱資料的總結,希望能幫助到需要的人
一 iOS上的加密思路
問題
這兩天一直在想公司app的安全問題,因為發現很多app登錄的時候其實是裸奔的,帶著賬號和密碼,等塞進post 請求參數里,直接飛向了服務器。這本都是敏感信息,不應該這樣輕易暴露在外邊。以前所在公司,也吃過這種虧。之前也一直看過加密的問題,但是也沒有深入的理解,這幾天查了一下資料,所以稍微記錄下使用的流程。以后真的用到這個過程時候,掉坑了再回頭填。
過程
1、客戶端將 username 和 pwd 做md5 處理,然后再加上客戶端的AES key,將這部分內容通過RSA加密,傳給服務器。
2、服務器會通過一個私匙,解開登錄傳過來的數據,獲得 username、pwd,和 客戶端的AES key。
3、登錄成功后,服務器也回生成服務器端的AES key,然后將登錄成功的狀態 和服務器端生成的AES key,通過客戶端的AES key進行加密,回傳給客戶端,完成這次登錄的請求。
4、客戶端收到登錄回調的數據,通過客戶端自己的AES key 將數據解開,獲得登錄的狀態和服務器端的AES key。獲取了服務器端的AES key 之后,自己本地生成的AES key丟棄,并保存服務器端的AES key。
5、以后需要加密的信息就直接通過服務器端的 AES key 加密,傳給服務器。
6、服務器可以動態控制AES key,這樣偽造請求被發現后,也可以更換服務器的AES key。
流程圖
RSA、AES加密處理流程一些Tips
1、RSA只在登錄的時候使用。為什么只在登錄時候使用,因為RSA加密有一些限制,首先他的密文長度只有117個字節,如果你需要加密的內容過長,那么可定會超過117,這樣就超出了限制,無法完成進一步的處理。其次,RAS加密是需要時間的啊,騷年!普通內容,每次使用RAS加密,效率肯定不高啊。
2、在解編碼過程中,涉及到了base64,記住base64 超過一定長度會自動換行,拿到的base64 編碼,記得去掉換行符,不然是解不出來的。
3、用服務器的AES key原因就是可以動態的改變,如果一直使用客戶端的AES key,一旦泄露之后,如果要修改密匙就只能APP升級了。
二 iOS安全開發防護摘要
前段時間集中時間寫了一本《iOS應用逆向工程—分析與實戰》,馬上就要上市。我想大概會有一部分iOS程序員覺得:你所說的這種越獄平臺的技術壓根上不了AppStore,與我何干?不過我相信另一部分人肯定會有相當大的觸動的。
寫作這本書的時候,所有目標都是集中在進攻方向上,而沒有太多考慮防守。因為從逆向工程的角度,確實是非常不好守的:微信、QQ那樣的聊天工具,聊天記錄可以截取;支付寶、網銀那樣的支付工具,用戶信息和密碼可以截取;至于其它更多app,放到逆向工程的面前感覺就是一個在裸奔的小孩,哦不,一群裸奔的小孩。
雖然知識從來都是矛與盾的關系,但對上了逆向工程,確實就易攻難守,不過,盡管是難守,總還是可以守一守的。下面從筆者的經驗上來分別羅列一下遇到的問題,及某些app的實際對策。
1、本地數據
很多開發者喜歡用NSUserDefaults來存儲一些全局數據,但是這些信息可以直接在app目錄文件中讀到,如果你也把username和password存在里面。。。當然,如果安全級別不高的程序,這么寫也沒什么問題;
很多app也會存一些簡單的數據到本地sqlite文件中,但實際上,完全可以使用加密sqlite的,當然,還是那句話,安全級別不高的程序,這么寫沒什么問題。
2、網絡接口保護
現在絕大部分的app都已經是聯網程序了,經典模式就是http+json,客戶端一解析,再做的漂亮一點就齊活。然而只要架上Charles或是tcpdump,完整的url request+response就看的清清楚楚。有了這些url,你的網絡數據就無密可保,尤其是一些資源型的服務,直接通過getList的模式就能把所有的數據抓回來。
這種情況下,即使是https也沒用,Charles輕松就能搞定,可以看相關的文章。而且即使不用Charles或tcpdump,直接用代碼hook網絡接口,一樣能把數據拿到。
另外插播一句:json是個好東西,它的展現就是一個Dictionary,數據呈現的非常清晰。但是它也絕對是最容易被盯上的點。設想一下,攻擊者hook了接口數據,此時直接把json或Dictionary打印出來,信息是不是就一覽無余了?在筆者的概念里,把Dictionary/json轉成普通的業務對象再傳遞,即使被攔截,起碼不會那么直觀地被看到。當然了,這只能給逆向者增加一點麻煩,純屬細枝末節。
筆者看過不少app,大概70%都是這種全裸奔的網絡請求,比如“網易新聞”;剩下的會對url做一定的保護,比如加token和timestamp,如“36kr”,這樣確實就把抓數據的難度陡然提升了;最“變態”的是“我查查”,他們直接把url做了加密/編碼,這種情況下想要復制出來就需要大費周章,而且如果這種編碼方式不是通用的,就更難逆向解析了。
3、混淆
混淆有兩種模式,一種是對函數名做混淆,另一種是對代碼做混淆,兩種都直接增加逆向的難度,但是擋是擋不住的,尤其是逆向者還有大把的時間。
4、程序結構
在app這種小而美的領域中,如果代碼結構也設計的非常簡潔漂亮,實在是一件令人賞心悅目的事情。不過對于逆向工程,越是這種設計結構,越容易定位,有時甚至不用上什么大招,直接從.h文件名和函數列表就能初步定位想要關心的核心代碼,如WhatsApp。
而一個反例是微信,微信的質量水準是有目共睹的,不過想要對它進行逆向工程就是一件比較痛苦的事情,因為最新的5.1有3000多個.h文件,如此龐大的代碼量直接將逆向工作量提升一個數量級。在筆者的分析過程中,經常會被一堆的Mgr、Event、Service給攪的心煩意亂。
這2個app只是兩個極端的比較,畢竟WhatsApp全公司才50人,一個iPhone版的開發者不過數人,結構自然清晰;而微信早已是一個龐然大物,各部門之間相互合作,一層層的代碼庫抽象封裝好給其它組調用,即使是很簡單的調用可能也要串3、4個場,不過這樣也間接增加了逆向的復雜度。
5、C或block函數
現在iOS方面的逆向工具都是針對OC來的,而一旦代碼以C函數或block函數來實現,相當于就采用了匿名函數,想要定位它就只能使用IDA,并且還很容易定位不準。筆者曾經在查看知乎日報的一段對token進行編碼的問題上繞了很大的圈子,依然沒有定準位,最后干脆放棄了,那段代碼就是拿block來完成的。而且,如果是C代碼,在IDA中看起來就不是易讀的OC風格偽代碼了,看起來也會比較累。
總的來說,還是要看開發者比較在意哪方面的安全,才好考慮如何防護:
1、想要保證程序中的信息不被截取
幾乎是不可能的,因為即使再加密,密文也總要變成明文供業務邏輯來使用,攻擊者只要盯住這個點就能達到目標;
2、想保護服務器的資源
客戶端在相當程度上只是一個UI展現,即使被破解也不是那么重要的,真正重要的是服務器端的資源,那么就要在網絡層進行防護了。現在大家都比較喜歡用http,而且都集中喜歡使用AF、ASI等幾個開源庫,逆向者只要盯住這幾個口,就能把來往的request+response全部獲取,進而可以仿制一個客戶端,此時服務器的資源也就全面開放了。同樣的,使用AsyncSocket也是一回事。
此時有3種防護措施:
1)服務器控制,不允許同一IP/客戶端頻繁抓取數據;
2)對url加上token、timestamp,甚至url編碼,雖然碰上高手還是不能100%安全,但是破解者想要達到目的,就需要考慮付出的精力是不是值得了;
3)傳輸數據加密,并且將加解密的代碼層級加深,尤其是放到C或block函數中,這樣又將安全等級提高了一級。
3、想保護程序不被偽造或克隆
克隆/偽造其實是件非常容易的事,甚至都不需要太多逆向工作,只要能把網絡請求搞定,剩下的就是代碼量、以及是否比被仿者做的更好的問題了。
總的來說,客戶端沒太多可保護的空間,它應該就是個業務展現和數據解析的工具,與其花精力想防這個防那個,不如把精力放在網絡接口的保護上,尤其是加解密代碼提取到C或block中。
以上只是筆者個人的一些經驗,希望大家能多多補充。
附:微信的安全防護措施,筆者認為是比較值得學習的,他們的步驟是:
1、不在業務表現上做太多無用功
除了代碼結構比較龐大之外,微信沒有做特別的動作;
2、服務器控制
所有的決斷性的動作由服務器控制,幾乎不可能靠通過篡改客戶端的代碼來獲取更大的權限。筆者曾經針對每天20個漂流瓶的限制嘗試擴大權限,但是即使把本地代碼邏輯放開,在超過20個瓶子之后,再撈回來的永遠是海星,顯然是服務器控制住了。
當然,本地LBS坐標是無法被服務器控制的,這也就是坐標穿越插件能起作用的根本原因。
3、網絡數據加密
通過對網絡接口的攔截,雖然能得到socket收取的二進制數據,首先是無法直接解密,其次是從那許多代碼中找解密代碼非常費勁,縱然加解密都能搞定,想偽造也十分麻煩,packet中包羅了相當多的信息,我估計就是把他們的代碼開放給開發者,想理清這一部分都不是一件輕松的事情。
4、登錄唯一性
即使能夠偽造微信的請求,一旦登錄獲取數據,原賬號就會被踢下線并且得到通知,這本身就是一個安全警告,說起來也算是服務器控制。
如果開發者對于安全性的設計都能達到微信這一級別,安全級別就是比較值得信賴的了,但是這也不表示就解不出來,只要逆向者的水平達到熟練程度以上(自然是越高越好),并且愿意投入大量精力在某個他們認為值得的app上,幾乎都能攻的下來。