需求分析
一、站在被攻擊者的角度而言,首先要保證的是:其手機號短時間內不收到多條短信(假定爲每分鐘最多收到1條),而若攻擊者以分鐘爲單位調用接口,對被攻擊者而言也難以接受,故同樣要保證的是:被攻擊者在同一天內不收到多條短信(假定爲5條)。
二、站在服務提供者的角度而言,平臺不希望發出大量無用短信,從而增加系統壓力與短信費用,但不能以簡單的限制每日發送短信總數量來做處理,因爲當攻擊者惡意調用多次接口導致系統不再提供服務後,將影響用戶的正常註冊。同時,在業務增長期,註冊人數難以用固定的數值來衡量,對於平臺而言,識別出可疑的異常調用者是最好的解決方案。
三、站在普通用戶的角度而言,在能夠保證正常註冊以外,註冊的體驗也較爲關鍵,比如:未收到短信時點擊重新發送的時間不宜過長、驗證碼不宜太過複雜等。
四、系統壓力與處理速度上,若這一套防刷機制過於複雜,在調用時要進行多種檢驗、判斷,會對系統造成壓力,同時用戶收到短信的速度也會減慢。
在各類場景如:
1.同一ip對同一手機號的大量發送
2.同一ip下對不同手機號的大量發送
3.更換ip對同一手機號大量發送
4.場景1、2、3下兩次請求之間間隔一段時間進行調用
5.不同ip短時間內對不同手機號的大量發送
優先級最高需要保證的是:
正常註冊功能不受影響
單一用戶不遭到“轟炸”式騷擾
其次要做到的是:
儘量少發出無用短信
正常用戶註冊體驗較好
擬用以下策略解決以下情況:
1.優化流程:如先讓用戶輸入要註冊的賬號密碼後再進入短信驗證環節,先驗證手機號是否合法後再 做其他判斷等。
2.保證某一用戶不遭到“轟炸”式騷擾:前端添加定時按鈕,如一分鐘後纔可以重新點擊發送
若該按鈕被繞過,則說明調用者並非正常用戶,策略3中會解決這一情況;
3.保證某一用戶同一天內不收到過多短信:爲每個號碼記錄其當日發送量,限制爲5條,若1中前端被 繞過,則也可以保證該用戶不會收到過多短信;
4.某一用戶不想再接到平臺短信:保留退訂功能,記錄所以退訂用戶爲禁止發送對象
5.同一ip對不同手機號大量發送:爲每個ip記錄其當日發送量,同樣有條數限制;
6.對於更換ip給不同手機號發送大量信息這一情況,在保證用戶能夠正常註冊的情況下,必然不能關閉發送服務,考慮的方案是噹噹日發送量到達一定量時,需要輸入驗證碼進行後續操作,另外可以再根據這一發送量,調整驗證碼難度,在不影響正常服務的情況下,逐漸增加攻擊者攻擊成本。
按照上述策略,擬完成的任務有:
1.完成對號碼、IP地址當日發送數量的限制
2.完成號碼退訂功能
3.完成對手機號是否合法的驗證
4.完成驗證碼功能及開啓驗證碼使用功能
5.全局異常處理、日誌、規範化接口等公共要求
6.集羣化處理
方案設計
對需求分析中給出的六點擬定完成任務的方案設想:
1.完成對號碼、IP地址當日發送數量的限制
2.完成號碼退訂功能
3.完成對手機號是否合法的驗證
4.完成驗證碼功能及開啓驗證碼使用功能
5.全局異常處理、日誌、規範化接口公共要求
6.集羣化處理
對號碼、IP地址發送數量限制
通過Redis的過期時間完成,存儲號碼/IP地址爲key,次數爲value的字符串,每次判斷是否到達限制,若未找到則寫入string,若達到限制則拒絕服務,若正常發送則令次數+1
號碼退訂功能
使用Redis的set集合完成,其查詢複雜度爲O(1),每次發送流程中優先判斷是否處於黑名單
手機號是否合法
使用正則表達式完成
驗證碼方案
當今日成功發送量大於給定值時,後續需要用戶輸入驗證碼才能服務
計數器方案:每日重置的線程安全的計數器,每次成功發送即+1,但考慮到服務器重啓後就會重新計數,所以還是需要持久化
實現:使用Kaptcha——一個google開源的驗證碼jar包生成驗證碼。具體流程爲:
1.前端請求後端
2.後端使用Kaptcha生成一個驗證碼captcha
3.後端爲這個驗證碼生成一個token,以token爲key,captcha爲value存在redis中
4.後端將token和驗證圖片一起傳給前端(圖片使用base64,與token打成一個map)
5.前端將這個token以及用戶所輸入的驗證碼傳入後端,後端根據token到redis中取值,驗證是否一致
可以提前生成一批驗證碼防止訪問高峯時驗證碼繪製佔用性能過高的情況
集羣化處理
設想將該業務實現爲一個短信發送服務,即服務提供者,在不同的場景下如用戶註冊、忘記密碼、綁定手機等需要發送短信時,由不同消費者調用該服務。使用Dubbo、ZooKeeper完成。
最終結構(provider):
代碼之後會上傳至github