短信驗證碼在 服務器 端的處理

轉載:http://blog.sina.com.cn/s/blog_80a6423d0102wm74.htmlhtml

目前,不少網站或app都要求用戶用手機註冊,好比滴滴打車的註冊界面是這樣的:redis

論短信驗證碼在 服務器 端的最佳處理姿式

 

流程大致分兩步:算法

  1. 用戶輸入手機號,點擊「獲取驗證碼」(滴滴界面上叫「驗證」),這時服務器會給用戶的手機發送一條短信數據庫

  2. 用戶查收短信後,輸入短信驗證碼,點「註冊」,服務器進行驗證,若是正確,執行註冊邏輯安全

     

常規的服務器端處理流程

  1. 第一步,服務器生成一個四位隨機碼做爲短信驗證碼,發短信出去,同時在數據庫或redis裏,記錄下該手機號對應的這個驗證碼以及超時時間ruby

  2. 第二步,用戶輸入驗證碼點「註冊」後,服務器端在數據庫或redis裏取到上步記錄的驗證碼,進行對比,若是相同,認證成功,繼續後續業務處理服務器

你們能夠看到,常規的服務器端處理,是須要操做數據庫或redis的,若是數據庫或redis掛掉,用戶註冊這個關鍵業務就無法進行了。 即便不掛掉,它們也可能成爲性能瓶頸架構

滴滴在《高可用架構》會場上分享了他們的實現方案:把方案作成無狀態的,即,不依賴數據庫或redis。 這是個很棒的思路,無狀態帶來的最好處多多(好比方便擴容、、)app

在會議現場提問環節,我提出了改進意見,因爲時間倉促,沒有與主持人深刻交流,會後也由於私事匆匆離開,也沒機會進一步交流性能

下面是個人改進方案,不涉及短信防刷這類「無關」問題(由於不管哪一種方案,都須要處理防刷)。 本質原理與滴滴的方案相同,全都是在非對稱摘要算法上作文章

第一步:用戶輸入手機號,點擊「獲取驗證碼」

這時,http request包含了用戶填寫的手機號:

phone= 18612345678

 


服務器端,生成一個隨機的四位碼做爲短信驗證碼(verify_code),發短信出去(這步略),爲了方便,我用ruby代碼表達,下同

verify_code = " #{rand( 10 )} #{rand( 10 )} #{rand( 10 )} #{rand( 10 )} "

 


算出過時時間exp(驗證碼5分鐘後過時):

exp = Time.now + 5.minutes

 


假設服務器端有一個全局的SECRET(注意別泄漏):

SECRET = "THIS_IS_A_SECRET"

 


咱們把這幾項拼成一個大的string,算一個摘要值(token)出來:

require ( 'digest' ) token = Digest::SHA256 .hexdigest(phone + verify_code + exp + SECRET )


摘要算法我這裏選了SHA256,能夠根據狀況調整


在本次請求的http response中,把exp和token傳回客戶端,相似:

{  " exp ": "2016-07-03 00:32:19 +0800" ,  " token ":"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
}

第二步:用戶輸入短信驗證碼,點「登陸」

這時,用戶提交的http request中包含以下信息(在服務器端,咱們用四個變量表示它們 ):

phone= 18612345678
verify_code_input= 用戶填的短信驗證碼
token= 上步傳回的值
exp= 上步傳回的值

 

服務器端先檢查一下短信驗證碼是否是超過5分鐘有效期了:

if Time .parse(exp) < Time .now  halt( "短信驗證碼已失效,請從新獲取" )
end

 

再檢查用戶輸入的短信驗證碼是否是正確,算法跟上步同樣:

require ( 'digest' ) token2 = Digest::SHA256 .hexdigest(phone + verify_code_input + exp + SECRET )
   
if token2 != token  halt( "短信驗證碼不正確,請從新獲取" )
end

# 下面是驗證經過後的代碼了...

 

這樣整個驗證過程就完成了

 

附個流程圖:

論短信驗證碼在 服務器 端的最佳處理姿式

後記:可行性和安全性

攻擊者由於手裏沒有SECRET,因此沒法僞造token。 這一點保證了整個方案的可行性

一樣由於有SECRET,因此攻擊者用rainbow table破解就不可行了,並且有exp定義超時時間,安全性有進一步提高。 實在不當心,SECRET泄漏了,攻擊者能夠實施的威脅就大的多了,不過這也是其它依賴SECRET的方案的一個通用問題(好比滴滴目前的方案)

 

服務器端換SECRET,形成的影響不過是最近幾分鐘內用戶獲取的短信驗證碼無效,須要用戶再獲取一次而已,能夠接受

相關文章
相關標籤/搜索