最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 防止短信驗(yàn)證碼接口被盜刷問題解決

 更新時(shí)間:2026年02月07日 10:12:46   作者:uup  
本文主要介紹了Java 防止短信驗(yàn)證碼接口被盜刷問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、Bug 場景

在一個(gè)基于 Java 的 Web 應(yīng)用中,用戶注冊或找回密碼等功能依賴短信驗(yàn)證碼進(jìn)行身份驗(yàn)證。然而,近期發(fā)現(xiàn)短信驗(yàn)證碼接口被惡意用戶頻繁調(diào)用,導(dǎo)致大量短信被發(fā)送,不僅增加了運(yùn)營成本,還影響了正常用戶的使用體驗(yàn),甚至可能因觸發(fā)運(yùn)營商短信發(fā)送限制而導(dǎo)致服務(wù)不可用。

二、代碼示例

短信發(fā)送服務(wù)類(有缺陷)

import java.util.Random;

public class SmsService {
    public void sendSms(String phoneNumber) {
        // 生成 6 位隨機(jī)驗(yàn)證碼
        int code = new Random().nextInt(900000) + 100000;
        System.out.println("向 " + phoneNumber + " 發(fā)送短信驗(yàn)證碼: " + code);
        // 實(shí)際應(yīng)用中應(yīng)調(diào)用短信發(fā)送 API 發(fā)送驗(yàn)證碼
    }
}

短信驗(yàn)證碼接口控制器(有缺陷)

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SmsVerificationCodeController {
    private SmsService smsService = new SmsService();

    public void sendVerificationCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String phoneNumber = request.getParameter("phoneNumber");
        if (phoneNumber != null) {
            smsService.sendSms(phoneNumber);
            response.getWriter().println("短信驗(yàn)證碼已發(fā)送");
        } else {
            response.getWriter().println("手機(jī)號不能為空");
        }
    }
}

三、問題描述

  1. 預(yù)期行為:正常用戶在需要時(shí)能夠獲取短信驗(yàn)證碼,且惡意用戶無法通過頻繁調(diào)用接口來盜刷短信驗(yàn)證碼,確保短信發(fā)送資源合理使用,服務(wù)穩(wěn)定運(yùn)行。
  2. 實(shí)際行為:惡意用戶可以通過編寫自動(dòng)化腳本,不斷調(diào)用短信驗(yàn)證碼接口,導(dǎo)致大量不必要的短信被發(fā)送。這是因?yàn)楫?dāng)前接口沒有任何限制機(jī)制,無論是正常用戶還是惡意用戶,只要提供了手機(jī)號,就可以無限制地獲取短信驗(yàn)證碼。

四、解決方案

  1. 增加頻率限制:通過記錄用戶請求頻率,限制同一手機(jī)號在一定時(shí)間內(nèi)的短信發(fā)送次數(shù)。可以使用 Redis 來存儲手機(jī)號的發(fā)送記錄和時(shí)間戳。
import redis.clients.jedis.Jedis;
import java.util.Random;

public class SmsService {
    private static final int MAX_SENDS_PER_MINUTE = 3; // 每分鐘最多發(fā)送 3 次
    private Jedis jedis;

    public SmsService(Jedis jedis) {
        this.jedis = jedis;
    }

    public boolean canSendSms(String phoneNumber) {
        String key = "sms:limit:" + phoneNumber;
        Long count = jedis.incr(key);
        if (count == 1) {
            jedis.expire(key, 60); // 設(shè)置過期時(shí)間為 1 分鐘
        }
        return count <= MAX_SENDS_PER_MINUTE;
    }

    public void sendSms(String phoneNumber) {
        if (canSendSms(phoneNumber)) {
            int code = new Random().nextInt(900000) + 100000;
            System.out.println("向 " + phoneNumber + " 發(fā)送短信驗(yàn)證碼: " + code);
            // 實(shí)際應(yīng)用中應(yīng)調(diào)用短信發(fā)送 API 發(fā)送驗(yàn)證碼
        } else {
            System.out.println("發(fā)送頻率過高,請稍后再試");
        }
    }
}

修改后的短信驗(yàn)證碼接口控制器

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import redis.clients.jedis.Jedis;
import java.io.IOException;

public class SmsVerificationCodeController {
    private SmsService smsService;

    public SmsVerificationCodeController(Jedis jedis) {
        this.smsService = new SmsService(jedis);
    }

    public void sendVerificationCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String phoneNumber = request.getParameter("phoneNumber");
        if (phoneNumber != null) {
            smsService.sendSms(phoneNumber);
            response.getWriter().println("短信驗(yàn)證碼已發(fā)送");
        } else {
            response.getWriter().println("手機(jī)號不能為空");
        }
    }
}
  1. 使用圖形驗(yàn)證碼:在發(fā)送短信驗(yàn)證碼之前,要求用戶先輸入圖形驗(yàn)證碼。用戶只有正確輸入圖形驗(yàn)證碼后,才能請求短信驗(yàn)證碼,增加惡意調(diào)用的難度。
// 圖形驗(yàn)證碼生成和驗(yàn)證邏輯(示例代碼,實(shí)際需更完善實(shí)現(xiàn))
public class CaptchaService {
    public String generateCaptcha() {
        // 生成圖形驗(yàn)證碼的邏輯,返回驗(yàn)證碼字符串
        return "1234";
    }

    public boolean verifyCaptcha(String inputCaptcha, String storedCaptcha) {
        return inputCaptcha.equals(storedCaptcha);
    }
}

再次修改后的短信驗(yàn)證碼接口控制器

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import redis.clients.jedis.Jedis;
import java.io.IOException;

public class SmsVerificationCodeController {
    private SmsService smsService;
    private CaptchaService captchaService;

    public SmsVerificationCodeController(Jedis jedis) {
        this.smsService = new SmsService(jedis);
        this.captchaService = new CaptchaService();
    }

    public void sendVerificationCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String phoneNumber = request.getParameter("phoneNumber");
        String inputCaptcha = request.getParameter("captcha");
        if (phoneNumber != null) {
            String storedCaptcha = "1234"; // 實(shí)際應(yīng)用中應(yīng)從 session 或其他存儲中獲取
            if (captchaService.verifyCaptcha(inputCaptcha, storedCaptcha)) {
                smsService.sendSms(phoneNumber);
                response.getWriter().println("短信驗(yàn)證碼已發(fā)送");
            } else {
                response.getWriter().println("圖形驗(yàn)證碼錯(cuò)誤");
            }
        } else {
            response.getWriter().println("手機(jī)號不能為空");
        }
    }
}
  1. IP 訪問限制:記錄請求的 IP 地址,限制同一 IP 在一定時(shí)間內(nèi)對短信驗(yàn)證碼接口的訪問次數(shù)。同樣可以使用 Redis 來實(shí)現(xiàn)。
import redis.clients.jedis.Jedis;
import java.util.Random;

public class SmsService {
    private static final int MAX_REQUESTS_PER_IP_PER_MINUTE = 10; // 每分鐘每個(gè) IP 最多請求 10 次
    private Jedis jedis;

    public SmsService(Jedis jedis) {
        this.jedis = jedis;
    }

    public boolean canSendSmsFromIp(String ip) {
        String key = "sms:ip:limit:" + ip;
        Long count = jedis.incr(key);
        if (count == 1) {
            jedis.expire(key, 60); // 設(shè)置過期時(shí)間為 1 分鐘
        }
        return count <= MAX_REQUESTS_PER_IP_PER_MINUTE;
    }

    // 其他方法不變
}

最終修改后的短信驗(yàn)證碼接口控制器

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import redis.clients.jedis.Jedis;
import java.io.IOException;

public class SmsVerificationCodeController {
    private SmsService smsService;
    private CaptchaService captchaService;

    public SmsVerificationCodeController(Jedis jedis) {
        this.smsService = new SmsService(jedis);
        this.captchaService = new CaptchaService();
    }

    public void sendVerificationCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String phoneNumber = request.getParameter("phoneNumber");
        String inputCaptcha = request.getParameter("captcha");
        String clientIp = request.getRemoteAddr();

        if (phoneNumber != null) {
            String storedCaptcha = "1234"; // 實(shí)際應(yīng)用中應(yīng)從 session 或其他存儲中獲取
            if (captchaService.verifyCaptcha(inputCaptcha, storedCaptcha) && smsService.canSendSmsFromIp(clientIp)) {
                smsService.sendSms(phoneNumber);
                response.getWriter().println("短信驗(yàn)證碼已發(fā)送");
            } else if (!captchaService.verifyCaptcha(inputCaptcha, storedCaptcha)) {
                response.getWriter().println("圖形驗(yàn)證碼錯(cuò)誤");
            } else {
                response.getWriter().println("請求頻率過高,請稍后再試");
            }
        } else {
            response.getWriter().println("手機(jī)號不能為空");
        }
    }
}

到此這篇關(guān)于Java 防止短信驗(yàn)證碼接口被盜刷問題解決的文章就介紹到這了,更多相關(guān)Java 防止短信驗(yàn)證碼接口被盜刷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud注冊中心部署Eureka流程詳解

    SpringCloud注冊中心部署Eureka流程詳解

    Eureka是Netflix開發(fā)的服務(wù)發(fā)現(xiàn)框架,本身是一個(gè)基于REST的服務(wù),主要用于定位運(yùn)行在AWS域中的中間層服務(wù),以達(dá)到負(fù)載均衡和中間層服務(wù)故障轉(zhuǎn)移的目的
    2022-11-11
  • Eclipse代碼格式化設(shè)置簡單介紹

    Eclipse代碼格式化設(shè)置簡單介紹

    這篇文章主要介紹了Eclipse代碼格式化設(shè)置簡單介紹,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • ArrayList的自動(dòng)擴(kuò)充機(jī)制實(shí)例解析

    ArrayList的自動(dòng)擴(kuò)充機(jī)制實(shí)例解析

    本文主要介紹了ArrayList的自動(dòng)擴(kuò)充機(jī)制,由一個(gè)題目切入主題,逐步向大家展示了ArrayList的相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • Java如何獲取客戶端mac地址

    Java如何獲取客戶端mac地址

    在用戶登錄時(shí),通過獲取IP地址來識別計(jì)算機(jī)的MAC地址,然后將用戶賬號與該MAC地址進(jìn)行綁定,確保每個(gè)賬號只能在一臺特定的計(jì)算機(jī)上登錄,增強(qiáng)系統(tǒng)安全性,這種方法適用于需要嚴(yán)格賬戶安全管理的場景
    2024-09-09
  • 詳解SpringBoot接收參數(shù)的五種形式

    詳解SpringBoot接收參數(shù)的五種形式

    在Spring Boot中,接收參數(shù)可以通過多種方式實(shí)現(xiàn),本文給大家介紹了SpringBoot接收參數(shù)的五種形式,并通過代碼和圖文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • Java可重入鎖reentrantLock解析

    Java可重入鎖reentrantLock解析

    這篇文章主要介紹了Java可重入鎖reentrantLock解析,reentrantLock跟synchronized代碼結(jié)構(gòu)差不多,只是多了一個(gè)lock和unlock的過程,需要的朋友可以參考下
    2023-12-12
  • 一文詳解Java中的監(jiān)聽器(Listener)

    一文詳解Java中的監(jiān)聽器(Listener)

    這篇文章主要介紹了Java中監(jiān)聽器(Listener)的相關(guān)資料,監(jiān)聽器模式是一種設(shè)計(jì)模式,用于處理異步事件和通知,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • Java調(diào)用MySQL數(shù)據(jù)庫的存儲過程和自定義函數(shù)及區(qū)別解析

    Java調(diào)用MySQL數(shù)據(jù)庫的存儲過程和自定義函數(shù)及區(qū)別解析

    本文介紹了存儲過程和自定義函數(shù)的概念、特性和構(gòu)建方法,并通過Java代碼展示了如何調(diào)用存儲過程和自定義函數(shù),最后,對比了存儲過程和自定義函數(shù)的區(qū)別,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • 在Java中Scanner的用法總結(jié)

    在Java中Scanner的用法總結(jié)

    這篇文章主要介紹了在Java中Scanner的用法總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java中拷貝list數(shù)組幾種常見的方法

    Java中拷貝list數(shù)組幾種常見的方法

    這篇文章主要給大家介紹了關(guān)于Java中拷貝list數(shù)組幾種常見的方法,在Java中,List是一個(gè)接口,它有多個(gè)實(shí)現(xiàn)類,如ArrayList、LinkedList等,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08

最新評論

宝清县| 宁南县| 翁源县| 天气| 南川市| 蓬安县| 读书| 曲麻莱县| 社旗县| 池州市| 抚松县| 冀州市| 红原县| 准格尔旗| 乾安县| 长阳| 宜章县| 大连市| 绥江县| 洪雅县| 锡林浩特市| 甘南县| 福贡县| 武义县| 锦屏县| 禹州市| 延庆县| 安阳市| 嘉黎县| 满洲里市| 洞口县| 肥乡县| 如皋市| 儋州市| 广西| 萝北县| 青岛市| 九寨沟县| 皋兰县| 绥棱县| 寿光市|