猿哥的100條經驗|輕鬆解決用戶簡訊發送的各種問題
常見問題(FAQ)
1.簡訊轟炸
惡作劇者利用系統暴露的簡訊發送介面頻繁向不同的用戶手機號碼發送簡訊驗證碼。
2.單賬號多人登錄
同一賬號多人登錄的情況下在短時間內(例如2秒內)收到兩條不同的簡訊驗證碼。
3.同一賬號發簡訊頻率失控
同一個賬號,系統只進行了粗略的簡訊發送頻率控制,例如1天內最多允許發送100條。
4.同一賬號的觸發簡訊過期時間刷新
同一個賬號當用戶第2次觸發簡訊1分鐘只能發送一次簡訊的限制時,又要完整等一分鐘。
5.異常簡訊行為未記錄日誌
例如短時間內例如1秒內,在兩個完全不相關的模塊觸發了多次簡訊服務,而正常人的操作是不可能在一秒內做到的,當然咯,如果用戶是一個程序員那就不一定了。
6.活動期間簡訊服務膨脹
系統開放促銷活動,導致短時間內湧入大量新用戶,新用戶綁定手機號時觸發大量簡訊驗證碼發送,導致系統負載過高從而服務暫停。
解決方案
第1個問題
比較好解決,只要涉及到簡訊發送就需要填寫驗證碼,並且驗證碼的生成是通過用戶點擊「獲取圖形驗證碼」按鈕生成的,這裡使用了前端js與後端圖形驗證碼約定的加解密token驗證服務,可能會用到瀏覽器版本crypto.js來生成token,大幅度增加破解token生成演算法的門檻,並且時常更新key(類似公鑰)。
第2、3個問題
這兩個問題屬於共性問題,這樣的簡訊發送規則屬於「程序員粗略定的」而不是產品經理定的,所以才會出現此等亂象。
建議約定如下規則:
- 任一賬號30秒內發送1條簡訊,否則提示下次簡訊可發送時間(見下面Redis的ttl命令)。
- 用戶輸入簡訊驗證碼錯誤時提示用戶今日剩餘2次連續錯誤機會(共3次),輸入正確後錯誤次數恢復為3次,否則今日內鎖定。
第4個問題
使用redis的ttl來獲取redis的對應指定用戶簡訊發送key的剩餘expire(過期時間)並返回給用戶,避免用戶盲目等待,代碼示例:
<?phpn //$redis是從redis連接池裡面獲取的一個連接實例n if($redis->setnx($userSmsKey)){n $redis->expire(30);n SmsService::send($cellPhone,$code);n }n return $redis->ttl($userSmsKey);n
關於ttl命令見
TTL - Redis
第5個問題
如果有多個功能模塊都需要使用簡訊功能,則應該在簡訊發送的功能模塊Redis Key上體現區別,並使用統一的Redis Key來錄入簡訊發送信息。
例如:SNS(社交網路系統)--我們使用「{productName}:{versionNumber}:{moduleName}:{feature:sms}:{userId}:{date:20170909}」的key格式來約定的話,將moduleName換成sns即可。
類似,有UC(用戶中心),OC(訂單中心)等多個面向用戶的module劃分,應該有獨立的簡訊發送規則,同時也應該有統一的用戶簡訊key來約束,例如我們使用「{productName}:{versionNumber}:{feature:sms}:{userId}:{date:20170909}」。
第6個問題
活動期間使用容器技術開啟N個簡訊發送的服務示例,然後就可以round-robin(重複循環遍歷)簡訊服務,當然更多的微服務實踐你都可以用起來,只要能夠保證水平擴展以及彈性伸縮也就滿足要求了。
關於round-robin見
Round Robin_百度百科
Round-robin scheduling
本文代碼-稍後補上。
推薦閱讀:
※想深入學習php面向對象,推薦一些好書唄?
※PHPMailer又被發現嚴重漏洞 危b及數百萬網站
※虛驚一場?PHPMailer漏洞雞肋無比
※PHP 下載 url 遠程圖片
※(PHP、.net、JSP)哪一隻能實現花生殼的功能?
TAG:PHP |