我們?cè)陂_發(fā)過程中,肯定會(huì)有和第三方或者app端的接口調(diào)用。在調(diào)用的時(shí)候,下面的方法可以來防止非法鏈接或者惡意攻擊。
劍河網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),劍河網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為劍河成百上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的劍河做網(wǎng)站的公司定做!
一、簽名
根據(jù)用戶名或者用戶id,結(jié)合用戶的ip或者設(shè)備號(hào),生成一個(gè)token。在請(qǐng)求后臺(tái),后臺(tái)獲取http的head中的token,校驗(yàn)是否合法(和數(shù)據(jù)庫或者Redis中記錄的是否一致,在登錄或者初始化的時(shí)候,存入數(shù)據(jù)庫/redis)
在使用Base64方式的編碼后,Token字符串還是有20多位,有的時(shí)候還是嫌它長(zhǎng)了。由于GUID本身就有128bit,在要求有良好的可讀性的前提下,很難進(jìn)一步改進(jìn)了。那我們?nèi)绾萎a(chǎn)生更短的字符串呢?還有一種方式就是較少Token的長(zhǎng)度,不用GUID,而采用一定長(zhǎng)度的隨機(jī)數(shù),例如64bit,再用Base64編碼表示:
var?rnd =?new?Random();
var?tokenData =?userIp+userId;
rnd.NextBytes(tokenData);
var?token =?Convert.ToBase64String(tokenData).TrimEnd('=');
由于這里只用了64bit,此時(shí)得到的字符串為Onh0h95n7nw的形式,長(zhǎng)度要短一半。這樣就方便攜帶多了。但是這種方式是沒有唯一性保證的。不過用來作為身份認(rèn)證的方式還是可以的(如網(wǎng)盤的提取碼)。
二、加密
客戶端和服務(wù)器都保存一個(gè)秘鑰,每次傳輸都加密,服務(wù)端根據(jù)秘鑰解密。
客戶端:
1、設(shè)置一個(gè)key(和服務(wù)器端相同)
2、根據(jù)上述key對(duì)請(qǐng)求進(jìn)行某種加密(加密必須是可逆的,以便服務(wù)器端解密)
3、發(fā)送請(qǐng)求給服務(wù)器
服務(wù)器端:
1、設(shè)置一個(gè)key
2、根據(jù)上述的key對(duì)請(qǐng)求進(jìn)行解密(校驗(yàn)成功就是「信任」的客戶端發(fā)來的數(shù)據(jù),否則拒絕響應(yīng))
3、處理業(yè)務(wù)邏輯并產(chǎn)生結(jié)果
4、將結(jié)果反饋給客戶端
三、第三方支持
比如spring?security-oauth
一般有五種方式:
1、Token授權(quán)認(rèn)證,防止未授權(quán)用戶獲取數(shù)據(jù);
2、時(shí)間戳超時(shí)機(jī)制;
3、URL簽名,防止請(qǐng)求參數(shù)被篡改;
4、防重放,防止接口被第二次請(qǐng)求,防采集;
5、采用HTTPS通信協(xié)議,防止數(shù)據(jù)明文傳輸;
所有的安全措施都用上的話有時(shí)候難免太過復(fù)雜,在實(shí)際項(xiàng)目中需要根據(jù)自身情況作出取舍,比如可以只使用簽名機(jī)制就可以保證信息不會(huì)被篡改,或者定向提供服務(wù)的時(shí)候只用Token機(jī)制就可以了,如何取舍,全看項(xiàng)目實(shí)際情況和對(duì)接口安全性的要求。
HTTP協(xié)議是無狀態(tài)的,一次請(qǐng)求結(jié)束,連接斷開,下次服務(wù)器再收到請(qǐng)求,它就不知道這個(gè)請(qǐng)求是哪個(gè)用戶發(fā)過來的,但是對(duì)我們有權(quán)限訪問限制的模塊而言,它是需要有狀態(tài)管理的,以便服務(wù)端能夠準(zhǔn)確的知道HTTP請(qǐng)求是哪個(gè)用戶發(fā)起的,從而判斷他是否有權(quán)限繼續(xù)這個(gè)請(qǐng)求。
Token的設(shè)計(jì)方案是用戶在客戶端使用用戶名和密碼登錄后,服務(wù)器會(huì)給客戶端返回一個(gè)Token,并將Token以鍵值對(duì)的形式存放在緩存(一般是Redis)中,后續(xù)客戶端對(duì)需要授權(quán)模塊的所有操作都要帶上這個(gè)Token,服務(wù)器端接收到請(qǐng)求后進(jìn)行Token驗(yàn)證,如果Token存在,說明是授權(quán)的請(qǐng)求。
Token生成的設(shè)計(jì)要求:
1、應(yīng)用內(nèi)一定要唯一,否則會(huì)出現(xiàn)授權(quán)混亂,A用戶看到了B用戶的數(shù)據(jù);
2、每次生成的Token一定要不一樣,防止被記錄,授權(quán)永久有效;
3、一般Token對(duì)應(yīng)的是Redis的key,value存放的是這個(gè)用戶相關(guān)緩存信息,比如:用戶的id;
4、要設(shè)置Token的過期時(shí)間,過期后需要客戶端重新登錄,獲取新的Token,如果Token有效期設(shè)置較短,會(huì)反復(fù)需要用戶登錄,體驗(yàn)比較差,我們一般采用Token過期后,客戶端靜默登錄的方式,當(dāng)客戶端收到Token過期后,客戶端用本地保存的用戶名和密碼在后臺(tái)靜默登錄來獲取新的Token,還有一種是單獨(dú)出一個(gè)刷新Token的接口,但是一定要注意刷新機(jī)制和安全問題;
根據(jù)上面的設(shè)計(jì)方案要求,我們很容易得到Token=md5(用戶ID+登錄的時(shí)間戳+服務(wù)器端秘鑰)這種方式來獲得Token,因?yàn)橛脩鬒D是應(yīng)用內(nèi)唯一的,登錄的時(shí)間戳保證每次登錄的時(shí)候都不一樣,服務(wù)器端秘鑰是配置在服務(wù)器端參與加密的字符串(即:鹽),目的是提高Token加密的破解難度,注意一定不要泄漏;
客戶端每次請(qǐng)求接口都帶上當(dāng)前時(shí)間的時(shí)間戳timestamp,服務(wù)端接收到timestamp后跟當(dāng)前時(shí)間進(jìn)行比對(duì),如果時(shí)間差大于一定時(shí)間(比如:1分鐘),則認(rèn)為該請(qǐng)求失效。時(shí)間戳超時(shí)機(jī)制是防御DOS攻擊的有效手段。
寫過支付寶或微信支付對(duì)接的同學(xué)肯定對(duì)URL簽名不陌生,我們只需要將原本發(fā)送給server端的明文參數(shù)做一下簽名,然后在server端用相同的算法再做一次簽名,對(duì)比兩次簽名就可以確保對(duì)應(yīng)明文的參數(shù)有沒有被中間人篡改過。
簽名算法:
1、首先對(duì)通信的參數(shù)按key進(jìn)行字母排序放入數(shù)組中(一般請(qǐng)求的接口地址也要參與排序和簽名,那么需要額外添加url= 這個(gè)參數(shù));
2、對(duì)排序完的數(shù)組鍵值對(duì)用進(jìn)行連接,形成用于加密的參數(shù)字符串;
3、在加密的參數(shù)字符串前面或者后面加上私鑰,然后用md5進(jìn)行加密,得到sign,然后隨著請(qǐng)求接口一起傳給服務(wù)器。
注意: 對(duì)于客戶端的私鑰一定要妥善處理好,不能被非法者拿到,如果針對(duì)于H5的項(xiàng)目,H5保存私鑰是個(gè)問題,目前沒有更好的方法,也是一致困擾我的問題,如果大家有更好的方法可以留言一起探討。
客戶端第一次訪問時(shí),將簽名sign存放到服務(wù)器的Redis中,超時(shí)時(shí)間設(shè)定為跟時(shí)間戳的超時(shí)時(shí)間一致,二者時(shí)間一致可以保證無論在timestamp限定時(shí)間內(nèi)還是外 URL都只能訪問一次,如果被非法者截獲,使用同一個(gè)URL再次訪問,如果發(fā)現(xiàn)緩存服務(wù)器中已經(jīng)存在了本次簽名,則拒絕服務(wù)。如果在緩存中的簽名失效的情況下,有人使用同一個(gè)URL再次訪問,則會(huì)被時(shí)間戳超時(shí)機(jī)制攔截,這就是為什么要求sign的超時(shí)時(shí)間要設(shè)定為跟時(shí)間戳的超時(shí)時(shí)間一致。拒絕重復(fù)調(diào)用機(jī)制確保URL被別人截獲了也無法使用(如抓取數(shù)據(jù))。
方案流程:
1、客戶端通過用戶名密碼登錄服務(wù)器并獲取Token;
2、客戶端生成時(shí)間戳timestamp,并將timestamp作為其中一個(gè)參數(shù);
3、客戶端將所有的參數(shù),包括Token和timestamp按照自己的簽名算法進(jìn)行排序加密得到簽名sign
4、將token、timestamp和sign作為請(qǐng)求時(shí)必須攜帶的參數(shù)加在每個(gè)請(qǐng)求的URL后邊
5、服務(wù)端對(duì)token、timestamp和sign進(jìn)行驗(yàn)證,只有在token有效、timestamp未超時(shí)、緩存服務(wù)器中不存在sign三種情況同時(shí)滿足,本次請(qǐng)求才有效;
眾所周知HTTP協(xié)議是以明文方式發(fā)送內(nèi)容,不提供任何方式的數(shù)據(jù)加密,如果攻擊者截取了客戶端和服務(wù)器之間的傳輸報(bào)文,就可以直接讀懂其中的信息,因此HTTP協(xié)議不適合傳輸一些敏感信息,比如信用卡號(hào)、密碼等。
為了解決HTTP協(xié)議的這一缺陷,需要使用另一種協(xié)議:安全套接字層超文本傳輸協(xié)議HTTPS,為了數(shù)據(jù)傳輸?shù)陌踩?,HTTPS在HTTP的基礎(chǔ)上加入了SSL協(xié)議,SSL依靠證書來驗(yàn)證服務(wù)器的身份,并為客戶端和服務(wù)器之間的通信加密。
HTTPS也不是絕對(duì)安全的,如下圖所示為中間人劫持攻擊,中間人可以獲取到客戶端與服務(wù)器之間所有的通信內(nèi)容。
中間人截取客戶端發(fā)送給服務(wù)器的請(qǐng)求,然后偽裝成客戶端與服務(wù)器進(jìn)行通信;將服務(wù)器返回給客戶端的內(nèi)容發(fā)送給客戶端,偽裝成服務(wù)器與客戶端進(jìn)行通信。 通過這樣的手段,便可以獲取客戶端和服務(wù)器之間通信的所有內(nèi)容。 使用中間人攻擊手段,必須要讓客戶端信任中間人的證書,如果客戶端不信任,則這種攻擊手段也無法發(fā)揮作用。
針對(duì)安全性要求一般的app,可采用通過校驗(yàn)域名,證書有效性、證書關(guān)鍵信息及證書鏈的方式。
以上說的更多是設(shè)計(jì)階段的思路,如果API已經(jīng)在運(yùn)行的話,我們則需要通過其他方式,如API網(wǎng)關(guān)工具來保護(hù)我們的API,這里推薦的是Eolinker,對(duì)于上述的5個(gè)方面,都有對(duì)應(yīng)的功能做到保護(hù)API,可以自己部署開源版本試用一下:
accesstoken是一種方式,早期簡(jiǎn)單點(diǎn)的有appid,appkey方式,復(fù)雜一點(diǎn)的可以使用RSA加密。
服務(wù)器和APP直接大部分通過接口調(diào)用,比如用戶列表。/user/list/
post到/user/list/里面有加密的一個(gè)token這個(gè)是驗(yàn)證是不是一個(gè)合法的訪問者。而且現(xiàn)在很多開發(fā)平臺(tái)比如微信。
使用OAuth 認(rèn)證~ 或者你返回 token 如果要用session ,那就返回session id, 但是估計(jì)這樣的話 數(shù)據(jù)要存數(shù)據(jù)庫吧 查看原帖