以下內(nèi)容為自己的一些經(jīng)歷和一些查閱資料的總結(jié)厕诡,希望能幫助到需要的人
一 iOS上的加密思路
問題
這兩天一直在想公司app的安全問題亭病,因為發(fā)現(xiàn)很多app登錄的時候其實是裸奔的嫩实,帶著賬號和密碼幔戏,等塞進post 請求參數(shù)里,直接飛向了服務(wù)器旬渠。這本都是敏感信息,不應(yīng)該這樣輕易暴露在外邊端壳。以前所在公司告丢,也吃過這種虧。之前也一直看過加密的問題损谦,但是也沒有深入的理解岖免,這幾天查了一下資料,所以稍微記錄下使用的流程照捡。以后真的用到這個過程時候颅湘,掉坑了再回頭填。
過程
1栗精、客戶端將 username 和 pwd 做md5 處理闯参,然后再加上客戶端的AES key,將這部分內(nèi)容通過RSA加密悲立,傳給服務(wù)器鹿寨。
2、服務(wù)器會通過一個私匙薪夕,解開登錄傳過來的數(shù)據(jù)脚草,獲得 username、pwd原献,和 客戶端的AES key馏慨。
3、登錄成功后姑隅,服務(wù)器也回生成服務(wù)器端的AES key写隶,然后將登錄成功的狀態(tài) 和服務(wù)器端生成的AES key,通過客戶端的AES key進行加密粤策,回傳給客戶端樟澜,完成這次登錄的請求。
4、客戶端收到登錄回調(diào)的數(shù)據(jù)秩贰,通過客戶端自己的AES key 將數(shù)據(jù)解開霹俺,獲得登錄的狀態(tài)和服務(wù)器端的AES key。獲取了服務(wù)器端的AES key 之后毒费,自己本地生成的AES key丟棄丙唧,并保存服務(wù)器端的AES key。
5觅玻、以后需要加密的信息就直接通過服務(wù)器端的 AES key 加密想际,傳給服務(wù)器。
6溪厘、服務(wù)器可以動態(tài)控制AES key胡本,這樣偽造請求被發(fā)現(xiàn)后,也可以更換服務(wù)器的AES key畸悬。
流程圖
RSA、AES加密處理流程一些Tips
1蹋宦、RSA只在登錄的時候使用披粟。為什么只在登錄時候使用,因為RSA加密有一些限制冷冗,首先他的密文長度只有117個字節(jié)守屉,如果你需要加密的內(nèi)容過長,那么可定會超過117蒿辙,這樣就超出了限制拇泛,無法完成進一步的處理。其次须板,RAS加密是需要時間的啊碰镜,騷年!普通內(nèi)容习瑰,每次使用RAS加密绪颖,效率肯定不高啊。
2甜奄、在解編碼過程中柠横,涉及到了base64,記住base64 超過一定長度會自動換行课兄,拿到的base64 編碼牍氛,記得去掉換行符,不然是解不出來的烟阐。
3搬俊、用服務(wù)器的AES key原因就是可以動態(tài)的改變紊扬,如果一直使用客戶端的AES key,一旦泄露之后唉擂,如果要修改密匙就只能APP升級了餐屎。
二 iOS安全開發(fā)防護摘要
前段時間集中時間寫了一本《iOS應(yīng)用逆向工程—分析與實戰(zhàn)》,馬上就要上市玩祟。我想大概會有一部分iOS程序員覺得:你所說的這種越獄平臺的技術(shù)壓根上不了AppStore腹缩,與我何干?不過我相信另一部分人肯定會有相當(dāng)大的觸動的空扎。
寫作這本書的時候藏鹊,所有目標(biāo)都是集中在進攻方向上,而沒有太多考慮防守转锈。因為從逆向工程的角度盘寡,確實是非常不好守的:微信、QQ那樣的聊天工具黑忱,聊天記錄可以截妊绺А;支付寶甫煞、網(wǎng)銀那樣的支付工具,用戶信息和密碼可以截裙诰睢抚吠;至于其它更多app,放到逆向工程的面前感覺就是一個在裸奔的小孩弟胀,哦不楷力,一群裸奔的小孩。
雖然知識從來都是矛與盾的關(guān)系孵户,但對上了逆向工程萧朝,確實就易攻難守,不過夏哭,盡管是難守检柬,總還是可以守一守的。下面從筆者的經(jīng)驗上來分別羅列一下遇到的問題竖配,及某些app的實際對策何址。
1、本地數(shù)據(jù)
很多開發(fā)者喜歡用NSUserDefaults來存儲一些全局?jǐn)?shù)據(jù)进胯,但是這些信息可以直接在app目錄文件中讀到用爪,如果你也把username和password存在里面。胁镐。偎血。當(dāng)然诸衔,如果安全級別不高的程序,這么寫也沒什么問題颇玷;
很多app也會存一些簡單的數(shù)據(jù)到本地sqlite文件中笨农,但實際上,完全可以使用加密sqlite的亚隙,當(dāng)然磁餐,還是那句話,安全級別不高的程序阿弃,這么寫沒什么問題诊霹。
2、網(wǎng)絡(luò)接口保護
現(xiàn)在絕大部分的app都已經(jīng)是聯(lián)網(wǎng)程序了渣淳,經(jīng)典模式就是http+json脾还,客戶端一解析,再做的漂亮一點就齊活入愧。然而只要架上Charles或是tcpdump鄙漏,完整的url request+response就看的清清楚楚。有了這些url棺蛛,你的網(wǎng)絡(luò)數(shù)據(jù)就無密可保怔蚌,尤其是一些資源型的服務(wù),直接通過getList的模式就能把所有的數(shù)據(jù)抓回來旁赊。
這種情況下桦踊,即使是https也沒用,Charles輕松就能搞定终畅,可以看相關(guān)的文章籍胯。而且即使不用Charles或tcpdump,直接用代碼hook網(wǎng)絡(luò)接口离福,一樣能把數(shù)據(jù)拿到杖狼。
另外插播一句:json是個好東西,它的展現(xiàn)就是一個Dictionary妖爷,數(shù)據(jù)呈現(xiàn)的非常清晰蝶涩。但是它也絕對是最容易被盯上的點。設(shè)想一下赠涮,攻擊者hook了接口數(shù)據(jù)子寓,此時直接把json或Dictionary打印出來,信息是不是就一覽無余了笋除?在筆者的概念里斜友,把Dictionary/json轉(zhuǎn)成普通的業(yè)務(wù)對象再傳遞,即使被攔截垃它,起碼不會那么直觀地被看到鲜屏。當(dāng)然了烹看,這只能給逆向者增加一點麻煩,純屬細(xì)枝末節(jié)洛史。
筆者看過不少app惯殊,大概70%都是這種全裸奔的網(wǎng)絡(luò)請求,比如“網(wǎng)易新聞”也殖;剩下的會對url做一定的保護土思,比如加token和timestamp,如“36kr”忆嗜,這樣確實就把抓數(shù)據(jù)的難度陡然提升了己儒;最“變態(tài)”的是“我查查”,他們直接把url做了加密/編碼捆毫,這種情況下想要復(fù)制出來就需要大費周章闪湾,而且如果這種編碼方式不是通用的,就更難逆向解析了绩卤。
3途样、混淆
混淆有兩種模式,一種是對函數(shù)名做混淆濒憋,另一種是對代碼做混淆何暇,兩種都直接增加逆向的難度,但是擋是擋不住的凛驮,尤其是逆向者還有大把的時間赖晶。
4、程序結(jié)構(gòu)
在app這種小而美的領(lǐng)域中辐烂,如果代碼結(jié)構(gòu)也設(shè)計的非常簡潔漂亮,實在是一件令人賞心悅目的事情捂贿。不過對于逆向工程纠修,越是這種設(shè)計結(jié)構(gòu),越容易定位厂僧,有時甚至不用上什么大招扣草,直接從.h文件名和函數(shù)列表就能初步定位想要關(guān)心的核心代碼,如WhatsApp颜屠。
而一個反例是微信辰妙,微信的質(zhì)量水準(zhǔn)是有目共睹的,不過想要對它進行逆向工程就是一件比較痛苦的事情甫窟,因為最新的5.1有3000多個.h文件密浑,如此龐大的代碼量直接將逆向工作量提升一個數(shù)量級。在筆者的分析過程中粗井,經(jīng)常會被一堆的Mgr尔破、Event街图、Service給攪的心煩意亂。
這2個app只是兩個極端的比較懒构,畢竟WhatsApp全公司才50人餐济,一個iPhone版的開發(fā)者不過數(shù)人,結(jié)構(gòu)自然清晰胆剧;而微信早已是一個龐然大物絮姆,各部門之間相互合作,一層層的代碼庫抽象封裝好給其它組調(diào)用秩霍,即使是很簡單的調(diào)用可能也要串3篙悯、4個場,不過這樣也間接增加了逆向的復(fù)雜度前域。
5辕近、C或block函數(shù)
現(xiàn)在iOS方面的逆向工具都是針對OC來的,而一旦代碼以C函數(shù)或block函數(shù)來實現(xiàn)匿垄,相當(dāng)于就采用了匿名函數(shù)移宅,想要定位它就只能使用IDA,并且還很容易定位不準(zhǔn)椿疗。筆者曾經(jīng)在查看知乎日報的一段對token進行編碼的問題上繞了很大的圈子漏峰,依然沒有定準(zhǔn)位,最后干脆放棄了届榄,那段代碼就是拿block來完成的浅乔。而且,如果是C代碼铝条,在IDA中看起來就不是易讀的OC風(fēng)格偽代碼了靖苇,看起來也會比較累。
總的來說班缰,還是要看開發(fā)者比較在意哪方面的安全贤壁,才好考慮如何防護:
1、想要保證程序中的信息不被截取
幾乎是不可能的埠忘,因為即使再加密脾拆,密文也總要變成明文供業(yè)務(wù)邏輯來使用,攻擊者只要盯住這個點就能達到目標(biāo)莹妒;
2名船、想保護服務(wù)器的資源
客戶端在相當(dāng)程度上只是一個UI展現(xiàn),即使被破解也不是那么重要的旨怠,真正重要的是服務(wù)器端的資源渠驼,那么就要在網(wǎng)絡(luò)層進行防護了。現(xiàn)在大家都比較喜歡用http运吓,而且都集中喜歡使用AF渴邦、ASI等幾個開源庫疯趟,逆向者只要盯住這幾個口,就能把來往的request+response全部獲取谋梭,進而可以仿制一個客戶端信峻,此時服務(wù)器的資源也就全面開放了。同樣的瓮床,使用AsyncSocket也是一回事盹舞。
此時有3種防護措施:
1)服務(wù)器控制,不允許同一IP/客戶端頻繁抓取數(shù)據(jù)隘庄;
2)對url加上token踢步、timestamp,甚至url編碼丑掺,雖然碰上高手還是不能100%安全获印,但是破解者想要達到目的,就需要考慮付出的精力是不是值得了街州;
3)傳輸數(shù)據(jù)加密兼丰,并且將加解密的代碼層級加深,尤其是放到C或block函數(shù)中唆缴,這樣又將安全等級提高了一級鳍征。
3、想保護程序不被偽造或克隆
克隆/偽造其實是件非常容易的事面徽,甚至都不需要太多逆向工作艳丛,只要能把網(wǎng)絡(luò)請求搞定,剩下的就是代碼量趟紊、以及是否比被仿者做的更好的問題了氮双。
總的來說,客戶端沒太多可保護的空間霎匈,它應(yīng)該就是個業(yè)務(wù)展現(xiàn)和數(shù)據(jù)解析的工具眶蕉,與其花精力想防這個防那個,不如把精力放在網(wǎng)絡(luò)接口的保護上唧躲,尤其是加解密代碼提取到C或block中。
以上只是筆者個人的一些經(jīng)驗碱璃,希望大家能多多補充弄痹。
附:微信的安全防護措施,筆者認(rèn)為是比較值得學(xué)習(xí)的嵌器,他們的步驟是:
1肛真、不在業(yè)務(wù)表現(xiàn)上做太多無用功
除了代碼結(jié)構(gòu)比較龐大之外,微信沒有做特別的動作爽航;
2蚓让、服務(wù)器控制
所有的決斷性的動作由服務(wù)器控制乾忱,幾乎不可能靠通過篡改客戶端的代碼來獲取更大的權(quán)限。筆者曾經(jīng)針對每天20個漂流瓶的限制嘗試擴大權(quán)限历极,但是即使把本地代碼邏輯放開窄瘟,在超過20個瓶子之后,再撈回來的永遠是海星趟卸,顯然是服務(wù)器控制住了蹄葱。
當(dāng)然,本地LBS坐標(biāo)是無法被服務(wù)器控制的锄列,這也就是坐標(biāo)穿越插件能起作用的根本原因图云。
3、網(wǎng)絡(luò)數(shù)據(jù)加密
通過對網(wǎng)絡(luò)接口的攔截邻邮,雖然能得到socket收取的二進制數(shù)據(jù)竣况,首先是無法直接解密,其次是從那許多代碼中找解密代碼非常費勁筒严,縱然加解密都能搞定丹泉,想偽造也十分麻煩,packet中包羅了相當(dāng)多的信息萝风,我估計就是把他們的代碼開放給開發(fā)者嘀掸,想理清這一部分都不是一件輕松的事情。
4规惰、登錄唯一性
即使能夠偽造微信的請求睬塌,一旦登錄獲取數(shù)據(jù),原賬號就會被踢下線并且得到通知歇万,這本身就是一個安全警告揩晴,說起來也算是服務(wù)器控制。
如果開發(fā)者對于安全性的設(shè)計都能達到微信這一級別贪磺,安全級別就是比較值得信賴的了硫兰,但是這也不表示就解不出來,只要逆向者的水平達到熟練程度以上(自然是越高越好)寒锚,并且愿意投入大量精力在某個他們認(rèn)為值得的app上劫映,幾乎都能攻的下來。