Swift Python 互通 Json 數據簽名

最近很流行自簽證書進行 HTTPS 解密,然後就有不少人通過修改蘋果的內購回執實現對 App 的破解。實際上驗證購買應該是 App 連接服務器,服務器來和蘋果的服務器進行通信,然後將結果發送給 App 的——但不少開發者(包括個人開發者以及企業開發者)懶得去專門維護服務器,所以直接用 App 和蘋果的服務器進行通信,這就給中間人攻擊提供了機會。

蘋果官方強調:“不要直接在 App 中驗證收據”

蘋果官方強調:“不要直接在 App 中驗證收據”

中間人攻擊,就是說當 A 和 B 進行通信時,C 對 A 假裝自己是 B,對 B 假裝自己是 A,這樣通信過程就從 A <—> B 變成了 A <–> C <–> 乙, 此時 A 和 B 都還以為對方是可信的,可通信的內容早不知道被 C 改了多少了。

通常來說我們使用 HTTPS 加密傳輸就已經能夠很好的對抗中間人攻擊了,但對於這種特殊情況,用戶主動去信任一個“不安全”(自己簽名)的證書進行 HTTPS 解密,那 HTTPS 加密在客戶端就成了不可信的。

這種情況下,我們就需要自己實現對數據的保護。

安全性和完整性

對數據進行保護,主要是兩點,“安全性”和“完整性”,前者保護數據不被第三方窺探,後者則保證你的數據在通信的過程當中不會被篡改,當然,通常來講加密也一定程度保證了數據的完整性,畢竟如果被篡改了,可能也就無法解密了。

但只依靠加密,就給中間人攻擊提供了機會。所以,我們要在 HTTPS 的安全性前提下,給自身代碼添加完整性驗證。

簽名

所謂“簽名”,和現實中的簽名不同,這裡的簽名是指通過一些特殊的算法,將數據的特徵提取出來,算法保證了一旦數據被改變,哪怕是一個符號,那麼提取的特徵就完全不同了,這樣,我們只要在發送數據時包含這個特徵,在收到後重新驗證它,就能確保數據在傳輸過程中沒有被篡改。

重簽名

有一個問題就是如果中間人在改了數據之後重新簽名,我們假定選擇的特徵提取算法被洩露了,中間人在更改了數據之後使用相同的算法重新簽名(也就是提取特徵),那客戶端依然會認為數據是完整的——所以我們要在客戶端和服務端約定一個“鹽”值,你也可以理解為密碼。

它不能讓你把數據從特徵值裡恢復出來(都說了是提取特徵,並不是加密,這個過程是不可逆的),但雙方約定了密碼之後在簽名時將這個“密碼”追加或者前置在數據中,這樣一旦中間人更改了數據,他即使可以使用相同的算法重新簽名,由於不知道我們預先設置的密碼,他簽出來的結果還是不同,這樣客戶端就知道這個數據是被篡改過的了。

重放攻擊

既然無法對數據進行修改,那麼駭客還可以抓取原本生效的數據報,重新再來發送,這樣服務器或者客戶端驗證了簽名和加密,數據完全正確,但實際上卻是來自另一個版本客戶端的傳輸數據——要應對這個情況,就要在之前數據結構的基礎上,再增加一個概念——“時間戳”,通常我們使用 utc 的時間戳,其實就是從格林威治時間1970年01月01日到現在的總計秒數——當然你也可以用其他的能精確到秒(甚至毫秒)的時間格式——把時間戳也追加在數據裡一起進行簽名,避免時間戳被篡改,然後客戶端和服務端進行通信時,檢查時間戳是否在允許範圍內,比如1秒內,或者30秒內等等,如果間隔太久,即時簽名驗證通過,也不能信任這個數據了,這樣,就避免了重放攻擊。

代碼

簽名的算法有很多,比如常見的 MD5、SHA1 等等等等,這些算法都可以直接拿來簽名使用,這裡我使用了 RSA 證書籤名,實際上就是用更長更複雜的密碼。

我們把要傳輸的數據和時間戳放在一起生成一個字符串,然後對字符串進行 SHA256 提取特徵,然後將特徵用 RSA 證書私鑰簽名;

等到客戶端收到數據,就將數據和時間戳用相同的方式生成字符串,進行 SHA256 提取特徵,然後用公鑰進行簽名驗證。

這樣公鑰私鑰的配對,好處在於,不像約定密碼那樣容易洩露——畢竟密碼就寫在程序中,很容易被找到——公鑰可以隨意傳播,它的作用僅僅是驗證簽名而不能對數據進行簽名,無需擔心洩露問題。

生成密鑰

打開任意你喜歡的終端,輸入命令 的openssl ,然後再輸入命令 genrsa -私人的.ESTAB 1024 來生成私鑰,後邊的數字越大就越安全,但你也要權衡簽名的時間成本,通常來說,1024 足夠了。

最後輸入命令 RSA - 私人的.ESTAB -出版 -上市.ESTAB 生成公鑰,這個公鑰就是你要放在客戶端中分發到最終用戶手中的密鑰了。(使用命令 出口 來退出 openssl)

實際上,生成的密鑰文件其實就是一個純文本文檔,密鑰本質上是二進制的,但它們都被 base64 編碼成文本保存。

使用命令 cat 私人的.ESTAB 來查看你的私鑰:

使用命令 cat 上市.ESTAB 來查看公鑰:

蟒蛇

 

為了方便使用,我們直接把上面私鑰的代碼複製,用一個變量來保存這個私鑰:

然後是簽名代碼:

這裡 標誌() 直接傳入字符串即可,它會將你傳入的字符串轉換成 UTF-8 編碼的二進制數據進行 SHA256 摘要,然後將摘要進行簽名,最終將簽名結果轉換為 base64 編碼的字符串輸出。

Swift

這裡我們同樣,將公鑰保存到變量中,注意只複製 base64 編碼部分,不要開頭和結尾的 -----開始 上市 ----------結束 上市 -----

上文中輸出的密鑰都是一行一行的,這裡我們將它們無縫拼接在一起,形成一個長串。

記得引用框架 進口 通用加密

然後我們寫一個函數來生成二進制公鑰:

最終來對數據進行簽名驗證:

只要傳入被簽名的字符串,再傳入簽名的 base64 編碼,函數就會自動對字符串進行 SHA256 摘要,然後簽名恢復成二進制數據,最後通過系統內置算法,使用你的公鑰,對摘要和簽名進行驗證,驗證通過,返回 true

後記

使用不同的代碼在不同的平台進行互通是一件很困難的事情,簡單的加密算法和方式往往會在不同的平台得出不一樣的結果,同一個語言,在同一個平台,是最容易的,但不同的語言就很複雜,具體實現時一定要注意這個問題。在嘗試了無數種方式後,最終我還是使用 RSA 簽名實現了跨語言平台互通,希望這篇文章對你有用。

參考文獻

本文由 落格博客 原創撰寫:落格博客 » Swift Python 互通 Json 數據簽名

轉載請保留出處和原文鏈接:https://www.logcg.com/archives/3318.html

關於作者

R0uter

如非聲明,本人所著文章均為原創手打,轉載請註明本頁面鏈接和我的名字。

發表評論

您的電子郵件地址不會被公開. 必填字段標 *