網際網路安全性問題
談到網際網路安全,會想起中間人攻擊,DNS劫持,代理伺服器等,對于這麼多的危險,怎麼保證我們的系統真的足夠安全呢?
一個有效的方法:End to End Encryption(端對端加密)
怎麼去了解端對端加密呢?核心有如下兩點:
- 用戶端和服務端交換期間,資料是加密的
- 既然加密,就用到加密的key,每個用戶端使用到的加密key都應該不一樣
解決方法:
- 模拟Https的加密流程,生成一個sessionKey,用于加密互動時的資料
- 這種方式經過駭客的評估,确實有效地防止被攻擊
流程
- 前端請求後端拿到public key
- 前端生成一個16位的cKey(UUID),用public key加密,傳給後端
- 後端拿到加密内容後,用private key解密,拿到cKey
- 後端又生成一個16位的sKey(UUID),然後兩個key一起做異或,生成一個sessionKey
- 将cKey,sKey,sessionKey儲存到DB,而且資料要進行加密的,并且有一個sessionId(UUID)作為唯一辨別,sessionId不用加密
- 然後用cKey加密sKey和sessionId傳回給前端,前端用自己的cKey解密,拿到sKey
- 然後前端做一次異或,生成一個sessionKey儲存在App的runtime
- 每次請求的參數,以userId=1&name=AA這樣的一個字元串用sessionKey進行加密,然後sessionId放在請求的header中,
- 後端拿到資料後,先根據sessionId找到資料庫對應的sessionKey 和 IV,然後解密這兩個值,然後再用這另個值來解密encData。
問題一:End to End Encryption 過程中,需要拿到後端的公匙,可不可以再改進?
問題關鍵:
- 現在服務端的public key、private key是固定的,放在伺服器的一個安全機器上,能不能将其改成可變的?
解決思路:
- 每次使用者需要生成sessionKey的時候,先用deviceId作為key,在redis中查查,看有沒有對應吖pubic key、private key,如果有就拿出來用,如果沒有就重新生成一對。
- 因為deviceId每台機器都不一樣,是以生成的public key、private key是不一樣的。
問題二:即使做好了加密,如果被人攔截到請求的所有資料,怕不怕被用來重複送出
問題關鍵:
- 這種敏感的請求,應該有個逾時時間來記錄什麼時候無效
- 同時,不能重複使用
解決思路:
- 用戶端發起請求時,生成一個timeStemp,這是目前送出的時間。
- 服務端拿到請求後,首先檢查timeStemp,跟目前時間比較,看是否超過5分鐘,如果超過就是無效的,如果不超過就是有效的。
- 那在這5分鐘的時間内,怎麼保證不會被重複請求呢?
- 使用redis做分布式鎖,設定一個clientRef(16位UUID)作為key,在第一次請求時,看拿不拿得到redis的一個key。
- 如果拿得到,證明已經執行過了,可以直接抛異常。
- 如果拿不到,證明還沒有執行過,那就執行請求。
- key的逾時時間是5分鐘,5分鐘後自動删除,這樣就可以補充這5分鐘的空隙了。
問題三:如果跟第三方系統互動,要防止請求資料被中間人篡改了,怎麼辦?
關鍵問題:
- 怎麼檢查被篡改過?數字簽名
解決思路:
- 先跟第三方約定數字簽名的加密算法,如:SHA256
- 第三方請求過來時,生成timeStamp,clientRef,以及request json body一起組成一串字元串,用算法進行加密,名字叫signature(數字簽名)
- 第三方請求中,header中,放timeStamp,clientRef,signature
- 我們服務端收到請求後,将timeStemp,clientRef,request json body,以相同的規則,組成字元串,再用算法進行加密
- 加密後的值和signature比較,看是否相等
- 如果相等就沒問題,不相等就抛異常
如何改進:
- 可以從加密算法中改進,可以用Hash,對稱加密,非對稱加密(事先要把public key的證書給第三方)
- timeStamp,clientRef,signature,組成字元串的規則可以跟第三方約定好,保證不會那麼容易被猜到