偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

涉及錢時,必須考慮防刷、限量和防重

開發(fā) 前端
對于短信驗證碼這種開放接口,程序邏輯內(nèi)需要有防刷邏輯。好的防刷邏輯是,對正常使用的用戶毫無影響,只有疑似異常使用的用戶才會感受到。對于短信驗證碼,有如下 4 種可行的方式來防刷。

任何涉及錢的代碼必須要考慮防刷、限量和防重,要做好安全兜底。涉及錢的代碼,主要有以下三類。

第一,代碼本身涉及有償使用的三方服務(wù)。如果因為代碼本身缺少授權(quán)、用量控制而被利用導(dǎo)致大量調(diào)用,勢必會消耗大量的錢,給公司造成損失。有些三方服務(wù)可能采用后付款方式的結(jié)算,出現(xiàn)問題后如果沒及時發(fā)現(xiàn),下個月結(jié)算時就會收到一筆數(shù)額巨大的賬單。

第二,代碼涉及虛擬資產(chǎn)的發(fā)放,比如積分、優(yōu)惠券等。雖然說虛擬資產(chǎn)不直接對應(yīng)貨幣,但一般可以在平臺兌換具有真實價值的資產(chǎn)。比如,優(yōu)惠券可以在下單時使用,積分可以兌換積分商城的商品。所以從某種意義上說,虛擬資產(chǎn)就是具有一定價值的錢,但因為不直接涉及錢和外部資金通道,所以容易產(chǎn)生隨意性發(fā)放而導(dǎo)致漏洞。

第三,代碼涉及真實錢的進(jìn)出。比如,對用戶扣款,如果出現(xiàn)非正常的多次重復(fù)扣款,小則用戶投訴、用戶流失,大則被相關(guān)管理機構(gòu)要求停業(yè)整改,影響業(yè)務(wù)。又比如,給用戶發(fā)放返現(xiàn)的付款功能,如果出現(xiàn)漏洞造成重復(fù)付款,涉及 B 端的可能還好,但涉及 C 端用戶的重復(fù)付款可能永遠(yuǎn)無法追回。

前段時間拼多多一夜之間被刷了大量 100 元無門檻優(yōu)惠券的事情,就是限量和防刷出了問題。

今天,我們就通過三個例子,和你說明如何在代碼層面做好安全兜底。

開放平臺資源的使用需要考慮防刷

我以真實遇到的短信服務(wù)被刷案例,和你說說防刷。

有次短信賬單月結(jié)時發(fā)現(xiàn),之前每個月是幾千元的短信費用,這個月突然變?yōu)榱藥兹f元。查數(shù)據(jù)庫記錄發(fā)現(xiàn),之前是每天發(fā)送幾千條短信驗證碼,從某天開始突然變?yōu)榱嗣刻鞄兹f條,但注冊用戶數(shù)并沒有激增。顯然,這是短信接口被刷了。

我們知道,短信驗證碼服務(wù)屬于開放性服務(wù),由用戶側(cè)觸發(fā),且因為是注冊驗證碼所以不需要登錄就可以使用。如果我們的發(fā)短信接口像這樣沒有任何防刷的防護(hù),直接調(diào)用三方短信通道,就相當(dāng)于“裸奔”,很容易被短信轟炸平臺利用:

@GetMapping("wrong")

publicvoid wrong() {

    sendSMSCaptcha("13600000000");

}

privatevoid sendSMSCaptcha(String mobile) {

//調(diào)用短信通道

}

對于短信驗證碼這種開放接口,程序邏輯內(nèi)需要有防刷邏輯。好的防刷邏輯是,對正常使用的用戶毫無影響,只有疑似異常使用的用戶才會感受到。對于短信驗證碼,有如下 4 種可行的方式來防刷。

第一種方式,只有固定的請求頭才能發(fā)送驗證碼。

也就是說,我們通過請求頭中網(wǎng)頁或 App 客戶端傳給服務(wù)端的一些額外參數(shù),來判斷請求是不是 App 發(fā)起的。其實,這種方式“防君子不防小人”。

比如,判斷是否存在瀏覽器或手機型號、設(shè)備分辨率請求頭。對于那些使用爬蟲來抓取短信接口地址的程序來說,往往只能抓取到 URL,而難以分析出請求發(fā)送短信還需要的額外請求頭,可以看作第一道基本防御。

第二種方式,只有先到過注冊頁面才能發(fā)送驗證碼。

對于普通用戶來說,不管是通過 App 注冊還是 H5 頁面注冊,一定是先進(jìn)入注冊頁面才能看到發(fā)送驗證碼按鈕,再點擊發(fā)送。我們可以在頁面或界面打開時請求固定的前置接口,為這個設(shè)備開啟允許發(fā)送驗證碼的窗口,之后的請求發(fā)送驗證碼才是有效請求。

這種方式可以防御直接繞開固定流程,通過接口直接調(diào)用的發(fā)送驗證碼請求,并不會干擾普通用戶。

第三種方式,控制相同手機號的發(fā)送次數(shù)和發(fā)送頻次。

除非是短信無法收到,否則用戶不太會請求了驗證碼后不完成注冊流程,再重新請求。因此,我們可以限制同一手機號每天的最大請求次數(shù)。驗證碼的到達(dá)需要時間,太短的發(fā)送間隔沒有意義,所以我們還可以控制發(fā)送的最短間隔。比如,我們可以控制相同手機號一天只能發(fā)送 10 次驗證碼,最短發(fā)送間隔 1 分鐘。

第四種方式,增加前置圖形驗證碼。

短信轟炸平臺一般會收集很多免費短信接口,一個接口只會給一個用戶發(fā)一次短信,所以控制相同手機號發(fā)送次數(shù)和間隔的方式不夠有效。這時,我們可以考慮對用戶體驗稍微有影響,但也是最有效的方式作為保底,即將彈出圖形驗證碼作為前置。

除了圖形驗證碼,我們還可以使用其他更友好的人機驗證手段(比如滑動、點擊驗證碼等),甚至是引入比較新潮的無感知驗證碼方案(比如,通過判斷用戶輸入手機號的打字節(jié)奏,來判斷是用戶還是機器),來改善用戶體驗。

此外,我們也可以考慮在監(jiān)測到異常的情況下再彈出人機檢測。比如,短時間內(nèi)大量相同遠(yuǎn)端 IP 發(fā)送驗證碼的時候,才會觸發(fā)人機檢測。

總之,我們要確保,只有正常用戶經(jīng)過正常的流程才能使用開放平臺資源,并且資源的用量在業(yè)務(wù)需求合理范圍內(nèi)。此外,還需要考慮做好短信發(fā)送量的實時監(jiān)控,遇到發(fā)送量激增要及時報警。

接下來,我們一起看看限量的問題。

虛擬資產(chǎn)并不能憑空產(chǎn)生無限使用

虛擬資產(chǎn)雖然是平臺方自己生產(chǎn)和控制,但如果生產(chǎn)出來可以立即使用就有立即變現(xiàn)的可能性。比如,因為平臺 Bug 有大量用戶領(lǐng)取高額優(yōu)惠券,并立即下單使用。

在商家看來,這很可能只是一個用戶支付的訂單,并不會感知到用戶使用平臺方優(yōu)惠券的情況;同時,因為平臺和商家是事后結(jié)算的,所以會馬上安排發(fā)貨。而發(fā)貨后基本就不可逆了,一夜之間造成了大量資金損失。

我們從代碼層面模擬一個優(yōu)惠券被刷的例子。

假設(shè)有一個 CouponCenter 類負(fù)責(zé)優(yōu)惠券的產(chǎn)生和發(fā)放。如下是錯誤做法,只要調(diào)用方需要,就可以憑空產(chǎn)生無限的優(yōu)惠券:

@Slf4j

publicclass CouponCenter {

    //用于統(tǒng)計發(fā)了多少優(yōu)惠券

    AtomicInteger totalSent = new AtomicInteger(0);

    public void sendCoupon(Coupon coupon) {

        if (coupon != null)

            totalSent.incrementAndGet();

    }

    public int getTotalSentCoupon() {

        return totalSent.get();

    }

    //沒有任何限制,來多少請求生成多少優(yōu)惠券

    public Coupon generateCouponWrong(long userId, BigDecimal amount)              {

        returnnew Coupon(userId, amount);

    }

}

這樣一來,使用 CouponCenter 的 generateCouponWrong 方法,想發(fā)多少優(yōu)惠券就可以發(fā)多少:

@GetMapping("wrong")

public int wrong() {

    CouponCenter couponCenter = new CouponCenter();

    //發(fā)送10000個優(yōu)惠券

    IntStream.rangeClosed(1, 10000).forEach(i -> {

        Coupon coupon = couponCenter.generateCouponWrong(1L, new BigDecimal("100"));

        couponCenter.sendCoupon(coupon);

    });

    return couponCenter.getTotalSentCoupon();

}

更合適的做法是,把優(yōu)惠券看作一種資源,其生產(chǎn)不是憑空的,而是需要事先申請,理由是:

虛擬資產(chǎn)如果最終可以對應(yīng)到真實金錢上的優(yōu)惠,那么,能發(fā)多少取決于運營和財務(wù)的核算,應(yīng)該是有計劃、有上限的。引言提到的無門檻優(yōu)惠券,需要特別小心。有門檻優(yōu)惠券的大量使用至少會帶來大量真實的消費,而使用無門檻優(yōu)惠券下的訂單,可能用戶一分錢都沒有支付。

即使虛擬資產(chǎn)不值錢,大量不合常規(guī)的虛擬資產(chǎn)流入市場,也會沖垮虛擬資產(chǎn)的經(jīng)濟(jì)體系,造成虛擬貨幣的極速貶值。有量的控制才有價值。

資產(chǎn)的申請需要理由,甚至需要走流程,這樣才可以追溯是什么活動需要、誰提出的申請,程序依據(jù)申請批次來發(fā)放。

接下來,我們按照這個思路改進(jìn)一下程序。

首先,定義一個 CouponBatch 類,要產(chǎn)生優(yōu)惠券必須先向運營申請優(yōu)惠券批次,批次中包含了固定張數(shù)的優(yōu)惠券、申請原因等信息:

//優(yōu)惠券批次

@Data

publicclass CouponBatch {

    privatelong id;

    private AtomicInteger totalCount;

    private AtomicInteger remainCount;

    private BigDecimal amount;

    private String reason;

}

在業(yè)務(wù)需要發(fā)放優(yōu)惠券的時候,先申請批次,然后再通過批次發(fā)放優(yōu)惠券:

@GetMapping("right")

public int right() {

    CouponCenter couponCenter = new CouponCenter();

    //申請批次    

    CouponBatch couponBatch = couponCenter.generateCouponBatch();

    IntStream.rangeClosed(1, 10000).forEach(i -> {

        Coupon coupon = couponCenter.generateCouponRight(1L, couponBatch);

        //發(fā)放優(yōu)惠券

        couponCenter.sendCoupon(coupon);

    });

    return couponCenter.getTotalSentCoupon();

}

可以看到,generateCouponBatch 方法申請批次時,設(shè)定了這個批次包含 100 張優(yōu)惠券。在通過 generateCouponRight 方法發(fā)放優(yōu)惠券時,每發(fā)一次都會從批次中扣除一張優(yōu)惠券,發(fā)完了就沒有了:

public Coupon generateCouponRight(long userId, CouponBatch couponBatch) {

    if (couponBatch.getRemainCount().decrementAndGet() >= 0) {

        returnnew Coupon(userId, couponBatch.getAmount());

    } else {

        log.info("優(yōu)惠券批次 {} 剩余優(yōu)惠券不足", couponBatch.getId());

        returnnull;

    }

}



public CouponBatch generateCouponBatch() {

    CouponBatch couponBatch = new CouponBatch();

    couponBatch.setAmount(new BigDecimal("100"));

    couponBatch.setId(1L);

    couponBatch.setTotalCount(new AtomicInteger(100));

    couponBatch.setRemainCount(couponBatch.getTotalCount());

    couponBatch.setReason("XXX活動");

    return couponBatch;

}

這樣改進(jìn)后的程序,一個批次最多只能發(fā)放 100 張優(yōu)惠券:


因為是 Demo,所以我們只是憑空 new 出來一個 Coupon。在真實的生產(chǎn)級代碼中,一定是根據(jù) CouponBatch 在數(shù)據(jù)庫中插入一定量的 Coupon 記錄,每一個優(yōu)惠券都有唯一的 ID,可跟蹤、可注銷。

最后,我們再看看防重。

錢的進(jìn)出一定要和訂單掛鉤并且實現(xiàn)冪等

涉及錢的進(jìn)出,需要做好以下兩點。

第一,任何資金操作都需要在平臺側(cè)生成業(yè)務(wù)屬性的訂單,可以是優(yōu)惠券發(fā)放訂單,可以是返現(xiàn)訂單,也可以是借款訂單,一定是先有訂單再去做資金操作。同時,訂單的產(chǎn)生需要有業(yè)務(wù)屬性。業(yè)務(wù)屬性是指,訂單不是憑空產(chǎn)生的,否則就沒有控制的意義。比如,返現(xiàn)發(fā)放訂單必須關(guān)聯(lián)到原先的商品訂單產(chǎn)生;再比如,借款訂單必須關(guān)聯(lián)到同一個借款合同產(chǎn)生。

第二,一定要做好防重,也就是實現(xiàn)冪等處理,并且冪等處理必須是全鏈路的。這里的全鏈路是指,從前到后都需要有相同的業(yè)務(wù)訂單號來貫穿,實現(xiàn)最終的支付防重。

關(guān)于這兩點,你可以參考下面的代碼示例:

//錯誤:每次使用UUID作為訂單號

@GetMapping("wrong")

publicvoid wrong(@RequestParam("orderId") String orderId) {

    PayChannel.pay(UUID.randomUUID().toString(), "123", new BigDecimal("100"));

}

//正確:使用相同的業(yè)務(wù)訂單號

@GetMapping("right")

publicvoid right(@RequestParam("orderId") String orderId) {

    PayChannel.pay(orderId, "123", new BigDecimal("100"));

}

//三方支付通道

publicclass PayChannel {

    publicstaticvoid pay(String orderId, String account, BigDecimal amount) {

        ...

    }

}

對于支付操作,我們一定是調(diào)用三方支付公司的接口或銀行接口進(jìn)行處理的。一般而言,這些接口都會有商戶訂單號的概念,對于相同的商戶訂單號,無法進(jìn)行重復(fù)的資金處理,所以三方公司的接口可以實現(xiàn)唯一訂單號的冪等處理。

但是,業(yè)務(wù)系統(tǒng)在實現(xiàn)資金操作時容易犯的錯是,沒有自始至終地使用一個訂單號作為商戶訂單號,透傳給三方支付接口。出現(xiàn)這個問題的原因是,比較大的互聯(lián)網(wǎng)公司一般會把支付獨立一個部門。支付部門可能會針對支付做聚合操作,內(nèi)部會維護(hù)一個支付訂單號,然后使用支付訂單號和三方支付接口交互。最終雖然商品訂單是一個,但支付訂單是多個,相同的商品訂單因為產(chǎn)生多個支付訂單導(dǎo)致多次支付。

如果說,支付出現(xiàn)了重復(fù)扣款,我們可以給用戶進(jìn)行退款操作,但給用戶付款的操作一旦出現(xiàn)重復(fù)付款,就很難把錢追回來了,所以更要小心。

這,就是全鏈路的意義,從一開始就需要先有業(yè)務(wù)訂單產(chǎn)生,然后使用相同的業(yè)務(wù)訂單號一直貫穿到最后的資金通路,才能真正避免重復(fù)資金操作。

重點回顧

今天,我從安全兜底聊起,和你分享了涉及錢的業(yè)務(wù)最需要做的三方面工作,防刷、限量和防重。

第一,使用開放的、面向用戶的平臺資源要考慮防刷,主要包括正常使用流程識別、人機識別、單人限量和全局限量等手段。

第二,虛擬資產(chǎn)不能憑空產(chǎn)生,一定是先有發(fā)放計劃、申請批次,然后通過批次來生產(chǎn)資產(chǎn)。這樣才能達(dá)到限量、有審計、能追溯的目的。

第三,真實錢的進(jìn)出操作要額外小心,做好防重處理。不能憑空去操作用戶的賬戶,每次操作以真實的訂單作為依據(jù),通過業(yè)務(wù)訂單號實現(xiàn)全鏈路的冪等控制。

如果程序邏輯涉及有價值的資源或是真實的錢,我們必須有敬畏之心。程序上線后,人是有休息時間的,但程序是一直運行著的,如果產(chǎn)生安全漏洞,就很可能在一夜之間爆發(fā),被大量人利用導(dǎo)致大量的金錢損失。

除了在流程上做好防刷、限量和防重控制之外,我們還需要做好三方平臺調(diào)用量、虛擬資產(chǎn)使用量、交易量、交易金額等重要數(shù)據(jù)的監(jiān)控報警,這樣即使出現(xiàn)問題也能第一時間發(fā)現(xiàn)。

責(zé)任編輯:武曉燕 來源: JAVA日知錄
相關(guān)推薦

2025-02-28 13:00:00

SpringBoot接口接口安全

2024-06-14 09:30:58

2025-06-12 08:21:22

2022-06-12 06:45:26

高并發(fā)防重

2025-10-29 01:21:00

2021-04-26 08:54:17

Spring BootSecurity防重登錄

2023-12-18 07:37:17

JavaScript防抖節(jié)流

2018-08-06 08:11:26

2025-06-09 01:22:00

2024-05-28 09:26:46

2012-11-19 10:02:01

cookie poiscookie防篡改cookie

2016-11-17 14:52:29

2012-10-19 09:22:54

2017-05-01 16:29:40

2023-07-24 08:00:56

客戶端訪問指定

2010-06-21 21:35:28

運維管理安防行業(yè)H3C

2010-09-14 19:50:55

2010-06-18 23:01:16

IT管理安防產(chǎn)業(yè)H3C

2012-02-13 17:02:44

內(nèi)網(wǎng)安全行為監(jiān)控CISA

2010-06-01 16:25:24

Zabbix報警
點贊
收藏

51CTO技術(shù)棧公眾號