話說(shuō)月初的時(shí)候曾想玩玩移動(dòng)app開發(fā),目前app開發(fā)比較流行c/s架構(gòu),不,用時(shí)髦點(diǎn)的話說(shuō)是云端架構(gòu)。對(duì)于網(wǎng)絡(luò)應(yīng)用來(lái)說(shuō),第一個(gè)遇到的問(wèn)題就是用戶身份驗(yàn)證。之前基本上就沒(méi)做過(guò)c/s架構(gòu)的東西(和b/s對(duì)應(yīng)的c/s),所以在這方面算是空白。后來(lái)面試過(guò)兩個(gè)Android開發(fā)者,把這個(gè)問(wèn)題當(dāng)做一個(gè)系統(tǒng)設(shè)計(jì)的題目來(lái)問(wèn),也沒(méi)有得到更多的想法。
當(dāng)年做b/s時(shí),用戶身份驗(yàn)證這種事靠的是cookie&session,即瀏覽器發(fā)送請(qǐng)求時(shí)攜帶寫入cookie的session_id,服務(wù)端通過(guò)session_id可以得到用戶的一些信息。但session的局限性在于服務(wù)器必須維持這個(gè)狀態(tài)。除此之外還有純cookie,就是把需要維持key-value對(duì)寫入瀏覽器的cookie里,為了安全還可以加個(gè)密。
在研究了新浪微博api的驗(yàn)證方式后,發(fā)現(xiàn)除了oauth外還有http basic auth這種方式。前者不多說(shuō),基本上用開放api開發(fā)應(yīng)用都會(huì)用到。后者是通過(guò)將用戶名和base64后的密碼通過(guò)http headers發(fā)送給服務(wù)器進(jìn)行驗(yàn)證的一種方式,缺點(diǎn)很明顯,每次都得發(fā)送密碼,盡管有加密,但還是有密碼泄露的風(fēng)險(xiǎn)。
面試一個(gè)做過(guò)android上c/s app開發(fā)的同學(xué)時(shí),他說(shuō)他們app用的方法類似于以前open api的認(rèn)證方式,就是每次請(qǐng)求中攜帶一個(gè)用作身份標(biāo)識(shí)的token,服務(wù)器根據(jù)這個(gè)token來(lái)判斷是誰(shuí)發(fā)來(lái)的消息。這種認(rèn)證方式的好處是不需要每次都發(fā)密碼,但缺點(diǎn)同樣明顯,就是一旦token被截獲,那么就可以隨意向服務(wù)器發(fā)送請(qǐng)求了。
根據(jù)oauth的原理,以及腦海中僅存的上過(guò)幾節(jié)的《信息安全》基礎(chǔ)知識(shí)(這時(shí)候真恨大學(xué)時(shí)沒(méi)怎么上過(guò)信息安全這門課),大概研究出了一種方案。實(shí)際上就是利用hmac這種加密算法,客戶端用密鑰對(duì)請(qǐng)求消息就行簽名,然后將簽名和請(qǐng)求消息一起發(fā)送給服務(wù)器,服務(wù)器繼續(xù)利用密鑰對(duì)請(qǐng)求消息簽名,同時(shí)判斷是否和客戶端發(fā)送的簽名結(jié)果一致。由于密鑰并不隨著網(wǎng)絡(luò)交互進(jìn)行發(fā)送,因此可以認(rèn)為這種驗(yàn)證機(jī)制是安全的。
以微博客戶端為例,用戶在發(fā)微博時(shí),服務(wù)器必須確認(rèn)該客戶端是這個(gè)用戶,才能給這個(gè)用戶發(fā)微博。不局限于http協(xié)議通信,假設(shè)客戶端服務(wù)器通過(guò)普通tcp socket通信,消息為json。
當(dāng)用戶注冊(cè)時(shí),生成一對(duì)(user_token, user_secret),其中user_token用于標(biāo)識(shí)用戶,而user_secret為密鑰之一,隨著密碼的改變而改變。當(dāng)用戶登陸時(shí),生成一對(duì)(login_token, login_secret),這對(duì)的生命周期和登陸狀態(tài)保存時(shí)間等同。比如客戶端向服務(wù)器發(fā)送請(qǐng)求為{“user_token”:”xxxx”,”login_token”:”yyyy”,”action”:”send”,”message”:”tweet a twitter”},因?yàn)閷?duì)象的屬性可以認(rèn)為有無(wú)序性,因此需要將key按字典序排列,得到一個(gè)字符串進(jìn)行簽名,即對(duì)字符串a(chǎn)ction=send&login_token=yyyy&message=tweet a twitter&user_token=xxxx進(jìn)行簽名,oauth中還需要對(duì)其進(jìn)行urlencode,使用的密鑰為user_secret&login_secret,假設(shè)簽名為abcdefg,同時(shí)客戶端需要將token發(fā)送給服務(wù)器,以便服務(wù)器確定用哪個(gè)密鑰進(jìn)行簽名,即最終發(fā)送的json消息為{“user_token”:”xxxx”,”login_token”:”yyyy”,”action”:”send”,”message”:”tweet a twitter”,”signature”:”abcdefg”}。服務(wù)器收到請(qǐng)求消息后,即可以通過(guò)token拿到密鑰,并對(duì)除signature以外的部分進(jìn)行簽名驗(yàn)證是否和signature相同,從而確認(rèn)這個(gè)消息是否是由合法的用戶發(fā)出的。
當(dāng)然,這只是自己根據(jù)oauth衍生出來(lái)的想法,不知道真正的移動(dòng)應(yīng)用c/s驗(yàn)證是怎么搞的。以前在淘寶實(shí)習(xí)時(shí),曾經(jīng)聽過(guò)一堂web安全方面的分享,也提到過(guò)所謂的cookie雙token驗(yàn)證,不知道原理和這個(gè)是不是類似。還有幾個(gè)問(wèn)題沒(méi)有想明白:
1. 從安全的角度來(lái)說(shuō),雖然發(fā)送正常請(qǐng)求時(shí),光有明文和密文沒(méi)辦法得到密鑰,但登陸的時(shí)候總是要由服務(wù)器將密鑰發(fā)送給客戶端的,這個(gè)時(shí)候還是容易泄密。不過(guò)最終hmac簽名的密鑰可以再加上一段服務(wù)器和客戶端約定好的字符串。但如果客戶端被反編譯,這段字符串仍然可以被找到。那么這段字符串就應(yīng)該也是生成的,比如客戶端的請(qǐng)求消息里加上timestamp,服務(wù)端用timestamp+user_token再簽出一段字符串用作簽名消息體的密鑰的一部分。不過(guò)問(wèn)題就是這個(gè)哈希算法應(yīng)該也可以破解出來(lái)。不太明白o(hù)auth中的timestamp意義在哪?
2. 第二個(gè)就是雙token雙secret到底有沒(méi)有用,能否簡(jiǎn)化成只有l(wèi)ogin_token, login_secret, user_token。通過(guò)user_token和timestamp在客戶端構(gòu)造出一個(gè)臨時(shí)的secret作為密鑰的一部分,然后服務(wù)器利用相同的hash算法生成這個(gè)臨時(shí)secret做簽名,似乎也能保證安全。
3. 還有就是雖然沒(méi)有辦法偽造消息,但如果截獲這個(gè)消息,就可以無(wú)數(shù)次發(fā)這個(gè)包給服務(wù)器,這是一條有效消息。莫非timestamp的作用就是有個(gè)過(guò)期限制?
聯(lián)系客服