天天看點

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

前言

現在基本上各種手機

APP

注冊都會用到手機驗證碼,包括一些

PC

端網站也會使用手機号作為唯一辨別驗證!

恰巧,小明的老闆,讓其開發一個使用者注冊的功能,并且強制使用者注冊綁定手機,美其名曰為了提升安全性,呵呵哒,就是為了多撸一點使用者資訊。

案例

一般來說,發送手機驗證碼不能過于頻繁,前端發送按鈕點選後一般會有一個

60

秒倒計時的功能。也就是說,如果使用者點選發送一直沒有收到驗證碼,隻能60秒之後才可以進行重發。

那麼問題來了,如果使用者繞過前端,直接向背景

API

發送短信請求,然後寫個無限循環腳本,相信不久你的短信賬戶就會發來預警提示短信(一般來說大的短信商都有預警設定功能)。

其實很簡單,你隻需要

F12

,檢視發送請求就可以查找出背景請求位址,然後你可以在控制台輸入相關

JS

代碼,執行個十萬遍,是不是很爽?

這裡以七牛雲為測試案例,打開注冊頁面,F12進入調試模式,輸入手機号,手動點選發送,擷取其短信發送背景請求位址。下面是七牛雲的一個短信發送請求,撸主測試了一下,顯然沒有達到撸主的預期,畢竟是大廠,防禦措施還是做的很牛逼的。

以下是

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)
        }
    });
}           

控制台傳回以下資訊,前三次請求成功,後面的就出現了驗證碼校驗并進行了限流操作。

{"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"}           

撸主嘗試重新整理頁面,随便輸了一個手機号,再次點選發送,提示使用者輸入驗證碼,顯然是加強了防備,觸發了惡意請求認證攔截機制。

安全機制

對于開發者來說,他們不僅要考慮使用者正常擷取驗證碼的體驗還要考慮短信接口的安全性,撸主總結了以下幾點,希望對大家有所幫助。

  • 背景請求限流,對機關時間内發送頻率做限制。
  • 驗證碼機制,切記不要一開始就限制驗證碼,體驗及其不友好,觸發限流以後開啟驗證碼校驗。
  • 監控日發送短信數量,觸發一定的門檻值做相應的處理,根據實際業務需求。
  • 驗證碼存儲一定要保證

    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"));
    }
}           

小結

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

作者: 小柒

出處:

https://blog.52itstyle.vip

繼續閱讀