巴南网站制作,wordpress本地环境,郑州建网站的公司,app 设计网站建设开放平台资源的使用需要考虑防刷
短信验证码服务属于开放性服务#xff0c;由用户侧触发#xff0c;且因为是注册验证码所以不需要登录就可以使用,很容易被短信轰炸平台利用
GetMapping(wrong)
public void wrong() {sendSMSCaptcha(13600000000);…开放平台资源的使用需要考虑防刷
短信验证码服务属于开放性服务由用户侧触发且因为是注册验证码所以不需要登录就可以使用,很容易被短信轰炸平台利用
GetMapping(wrong)
public void wrong() {sendSMSCaptcha(13600000000);
}private void sendSMSCaptcha(String mobile) {//调用短信通道
}
对于短信验证码这种开放接口程序逻辑内需要有防刷逻辑。
1. 控制相同手机号的发送次数和发送频次:
限制同一手机号每天的最大请求次数, 频率
2. 增加前置图形验证码:
短信轰炸平台一般会收集很多免费短信接口一个接口只会给一个用户发一次短信所以控制相同手机号发送次数和间隔的方式不够有效, 即将弹出图形验证码作为前置 虚拟资产并不能凭空产生无限使用
虚拟资产虽然是平台方自己生产和控制但如果生产出来可以立即使用就有立即变现。比如因为平台 Bug 有大量用户领取高额优惠券并立即下单使用。
在商家看来这很可能只是一个用户支付的订单并不会感知到用户使用平台方优惠券的情况同时因为平台和商家是事后结算的所以会马上安排发货。而发货后基本就不可逆了一夜之间造成了大量资金损失。
我们从代码层面模拟一个优惠券被刷的例子。
假设有一个 CouponCenter 类负责优惠券的产生和发放。如下是错误做法只要调用方需要就可以凭空产生无限的优惠券
Slf4j
public class CouponCenter {//用于统计发了多少优惠券AtomicInteger totalSent new AtomicInteger(0);public void sendCoupon(Coupon coupon) {if (coupon ! null)totalSent.incrementAndGet();}public int getTotalSentCoupon() {return totalSent.get();}//没有任何限制来多少请求生成多少优惠券public Coupon generateCouponWrong(long userId, BigDecimal amount) {return new Coupon(userId, amount);}
}
这样一来使用 CouponCenter 的 generateCouponWrong 方法想发多少优惠券就可以发多少
GetMapping(wrong)
public int wrong() {CouponCenter couponCenter new CouponCenter();//发送10000个优惠券IntStream.rangeClosed(1, 10000).forEach(i - {Coupon coupon couponCenter.generateCouponWrong(1L, new BigDecimal(100));couponCenter.sendCoupon(coupon);});return couponCenter.getTotalSentCoupon();
}
更合适的做法是把优惠券看作一种资源其生产不是凭空的而是需要事先申请
接下来我们按照这个思路改进一下程序。
首先定义一个 CouponBatch 类要产生优惠券必须先向运营申请优惠券批次批次中包含了固定张数的优惠券、申请原因等信息
//优惠券批次
Data
public class CouponBatch {private long id;private AtomicInteger totalCount;private AtomicInteger remainCount;private BigDecimal amount;private String reason;
}
在业务需要发放优惠券的时候先申请批次然后再通过批次发放优惠券
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);//发放优惠券couponCenter.sendCoupon(coupon);});return couponCenter.getTotalSentCoupon();
}
可以看到generateCouponBatch 方法申请批次时设定了这个批次包含 100 张优惠券。在通过 generateCouponRight 方法发放优惠券时每发一次都会从批次中扣除一张优惠券发完了就没有了
public Coupon generateCouponRight(long userId, CouponBatch couponBatch) {if (couponBatch.getRemainCount().decrementAndGet() 0) {return new Coupon(userId, couponBatch.getAmount());} else {log.info(优惠券批次 {} 剩余优惠券不足, couponBatch.getId());return null;}
}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;
}
这样改进后的程序一个批次最多只能发放 100 张优惠券在通过 generateCouponRight 方法发放优惠券时每发一次都会从批次中扣除一张优惠券发完了就没有了 钱的进出一定要和订单挂钩并且实现幂等
涉及钱的进出需要做好以下两点。
第一任何资金操作都需要在平台侧生成业务属性的订单可以是优惠券发放订单可以是返现订单也可以是借款订单一定是先有订单再去做资金操作。
第二一定要做好防重也就是实现幂等处理并且幂等处理必须是全链路的。这里的全链路是指从前到后都需要有相同的业务订单号来贯穿实现最终的支付防重。
关于这两点你可以参考下面的代码示例
//错误每次使用UUID作为订单号
GetMapping(wrong)
public void wrong(RequestParam(orderId) String orderId) {PayChannel.pay(UUID.randomUUID().toString(), 123, new BigDecimal(100));
}//正确使用相同的业务订单号
GetMapping(right)
public void right(RequestParam(orderId) String orderId) {PayChannel.pay(orderId, 123, new BigDecimal(100));
}
//三方支付通道
public class PayChannel {public static void pay(String orderId, String account, BigDecimal amount) {...}
}
对于支付操作我们一定是调用三方支付公司的接口或银行接口进行处理的。一般而言这些接口都会有商户订单号的概念对于相同的商户订单号无法进行重复的资金处理所以三方公司的接口可以实现唯一订单号的幂等处理。
但是业务系统在实现资金操作时容易犯的错是没有自始至终地使用一个订单号作为商户订单号透传给三方支付接口。出现这个问题的原因是比较大的互联网公司一般会把支付独立一个部门。支付部门可能会针对支付做聚合操作内部会维护一个支付订单号然后使用支付订单号和三方支付接口交互。最终虽然商品订单是一个但支付订单是多个相同的商品订单因为产生多个支付订单导致多次支付。
如果说支付出现了重复扣款我们可以给用户进行退款操作但给用户付款的操作一旦出现重复付款就很难把钱追回来了所以更要小心。
这就是全链路的意义从一开始就需要先有业务订单产生然后使用相同的业务订单号一直贯穿到最后的资金通路才能真正避免重复资金操作。
重点回顾
第一使用开放的、面向用户的平台资源要考虑防刷主要包括正常使用流程识别、人机识别、单人限量和全局限量等手段。
第二虚拟资产不能凭空产生一定是先有发放计划、申请批次然后通过批次来生产资产。这样才能达到限量、有审计、能追溯的目的。
第三真实钱的进出操作要额外小心做好防重处理。不能凭空去操作用户的账户每次操作以真实的订单作为依据通过业务订单号实现全链路的幂等控制。如果程序逻辑涉及有价值的资源或是真实的钱我们必须有敬畏之心。程序上线后人是有休息时间的但程序是一直运行着的如果产生安全漏洞就很可能在一夜之间爆发被大量人利用导致大量的金钱损失。