臭名昭著的手機驗證碼功能是如何實現的

前言

如今基本上各類手機APP註冊都會用到手機驗證碼,包括一些PC端網站也會使用手機號做爲惟一標識驗證!前端

恰巧,小明的老闆,讓其開發一個用戶註冊的功能,而且強制用戶註冊綁定手機,美其名曰爲了提高安全性,呵呵噠,就是爲了多擼一點用戶信息。java

案例

通常來講,發送手機驗證碼不能過於頻繁,前端發送按鈕點擊後通常會有一個60秒倒計時的功能。也就是說,若是用戶點擊發送一直沒有收到驗證碼,只能60秒以後才能夠進行重發。ajax

那麼問題來了,若是用戶繞過前端,直接向後臺API發送短信請求,而後寫個無限循環腳本,相信不久你的短信帳戶就會發來預警提示短信(通常來講大的短信商都有預警設置功能)。json

其實很簡單,你只須要F12,查看發送請求就能夠查找出後臺請求地址,而後你能夠在控制檯輸入相關JS代碼,執行個十萬遍,是否是很爽?後端

這裏以七牛云爲測試案例,打開註冊頁面,F12進入調試模式,輸入手機號,手動點擊發送,獲取其短信發送後臺請求地址。下面是七牛雲的一個短信發送請求,擼主測試了一下,顯然沒有達到擼主的預期,畢竟是大廠,防護措施仍是作的很牛逼的。api

如下是JS腳本,複製粘貼到控制檯回車就能夠執行:安全

var data = {"operation":1,"is_voice":false,"mobile_number":"17762018888","captcha_type":2};for (var i = 0; i < 10; i++) {
    $.ajax({        type: 'POST',		contentType: 'application/json;charset=UTF-8',        data:JSON.stringify(data),        url: 'https://portal.qiniu.com/api/gaea/verification/sms/send',        success: function(data) {            console.log(data)
        }
    });
}

控制檯返回如下信息,前三次請求成功,後面的就出現了驗證碼校驗並進行了限流操做。session

{"code":200,"message":""}
{"code":200,"message":""}
{"code":200,"message":""}
{"code": 7209,"message":"captcha required"}
{"code": 7209,"message":"captcha required"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 429,"message":"too many requests"}
{"code": 7209,"message":"captcha required"}

擼主嘗試刷新頁面,隨便輸了一個手機號,再次點擊發送,提示用戶輸入驗證碼,顯然是增強了防備,觸發了惡意請求認證攔截機制。app

安全機制

對於開發者來講,他們不只要考慮用戶正常獲取驗證碼的體驗還要考慮短信接口的安全性,擼主總結了如下幾點,但願對你們有所幫助。dom

  • 後臺請求限流,對單位時間內發送頻率作限制。

  • 驗證碼機制,切記不要一開始就限制驗證碼,體驗及其不友好,觸發限流之後開啓驗證碼校驗。

  • 監控日發送短信數量,觸發必定的閾值作相應的處理,根據實際業務需求。

  • 驗證碼存儲必定要保證key爲手機號,切記不要以其它標識做爲key,好比sessionId

  • 必定要設置驗證碼失效時間,好比五分鐘,或者更短。

  • 驗證碼儘可能保證短小精悍,四到六位便可。

  • 若是後臺不作限制,切記前臺必定要作個倒計時的限制,至少過濾一部分小白用戶。

代碼案例

給小夥伴分享一個簡單的驗證碼生成、存儲、失效代碼案例:

import com.google.common.cache.CacheBuilder;import com.google.common.cache.CacheLoader;import com.google.common.cache.LoadingCache;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;public class Mobile {    /**
     * 測試方便,這裏設置了3秒失效
     */
    private static LoadingCache<String, String> caches = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(3, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {                @Override
                public String load(String mobile) {                    return "";
                }
            });    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Integer code = (int)((Math.random()*9+1)*100000);
        caches.put("17762018888",code.toString());
        System.out.println(caches.get("17762018888"));
        Thread.sleep(4000);
        System.out.println("是否是沒了:"+caches.get("17762018888"));
    }
}

小結

重要的功能必須進行先後端校驗,必要的時候必定要作好限流、黑名單等騷操做!!!

相關文章
相關標籤/搜索