飞道的博客

企业短信防火墙应用-小豆社保「社保代缴」

346人阅读  评论(0)

1 小豆社保业务及需求

半夜短信费用完, 怎么知道是否有问题?

小豆社保:是一家一站式人力资源SAAS服务云智慧平台,隶属于北京新琪科技有限公司, 说简单点就是解决工作变动无挂靠单位的人代缴社保的业务。

阿亮: 小豆社保CTO, 原安邦集团系统架构师 。

需求(半夜电话): 最近业务增长迅猛,我们公司预存的短信条数用完, 短信服务商半夜无法充值,怎么办?
上次充值短信条数不少, 好像比计划提早很多用完,是否有被盗刷的情况 ?

解决方案(回复): 下载短信防火墙,做对接,

  • 可以确保短信验证码不被盗刷,
  • 云控制台可以实时展现发送短信的详细数据

对接需要多久?产品经理反对出现谷歌验证码及类似的东东
1 对接需要投入多少人日,现在业务多,技术资源紧缺,
2 我们产品正在推广期,产品经理强烈反对增加像 12306 那样low 的验证方式, 人家是市场垄断地位,再多人吐槽也不改变, 我们不愿新来的客户一看注册流程太麻烦不再使用我们的产品,
如图:是我们的登录/注册页面,要求在页面上不能增加任何用户交互流程。

解决方案(回复):
1 一般熟悉的技术,半个人日就可以解决。
2 企业短信防火墙在任何时候,都不会出现类似谷歌验证码,如12306 那样的二次验证,完全符合需求。

2 企业短信防火墙接口对接

2.0 企业短信网关接入

首先解决多通道接入,以免单独单独通道出现问题导致整个业务受影响,
小豆社保目前用的是亿美软通短信接口, 采用企业短信网关后, 自动可以分配到其他短信通道, 目前配置中增加了助通科技的短信通道, 看配置文件 :sms_config.json
按50%的量配置

{
   
	"route": {
   
		"ztinfo":"50",
		"emay":"50"
	},	
	"emay": {
   
		"smsUrl": "http://www.btom.cn:8080",
		"appId": "",
		"secretKey": ""
	},	
	"ztinfo": {
   
		"smsUrl": "http://api.mix2.zthysms.com",
		"username": "",
		"password": "!"
	}	

}

发送短信接口 ,本次是调用客户端接口,访问服务的方式 (也可以本地调用)

/**
	 * 发送短信
	 */
	public JSONObject sendMsg(String phone, String msg) {
   
		Map<String, Object> paramsMap = new HashMap<>();
		paramsMap.put("phone", phone);
		paramsMap.put("msg", msg);
		logger.debug("msg=" + msg);
		String jsonResp = HttpClient.execClient("fireWareUrl", "SendSmsServlet", paramsMap, 1000);
		try {
   
			JSONObject jsonRet = jsonResp != null ? JSONObject.parseObject(jsonResp) : null;
			int ret = jsonRet != null ? jsonRet.getIntValue("ret") : -1;
			if (ret != 0) {
   
				logger.error("sendMsg() paramsMap=" + paramsMap + "|jsonResp=" + jsonResp);
			} else {
   
				String spCode = jsonRet != null ? jsonRet.getString("spCode") : null;
				logger.info("sendMsg() spCode=" + spCode + "|phone=" + phone + "|msg=" + msg);
			}
			return jsonRet;
		} catch (Exception e) {
   
			logger.error("sendMsg() paramsMap=" + paramsMap + "|jsonResp=" + jsonResp);
			return null;
		}
	}

	/**
	 * 发送模板短信
	 */

	public JSONObject sendTpMsg(String phone, String templateId, Map<String, String> templateMap) {
   
		Map<String, Object> paramsMap = new HashMap<>();
		String templateJson = templateMap != null ? JSONObject.toJSONString(templateMap) : null;
		paramsMap.put("phone", phone);
		paramsMap.put("templateId", templateId);
		paramsMap.put("templateJson", templateJson);
		String jsonResp = HttpClient.execClient("fireWareUrl", "SendSmsServlet", paramsMap, 1000);
		try {
   
			JSONObject jsonRet = (jsonResp != null) ? JSONObject.parseObject(jsonResp) : null;
			int ret = jsonRet != null ? jsonRet.getIntValue("ret") : -1;
			if (ret != 0) {
   
				logger.error("sendTpMsg() ret=" + ret + " paramsMap=" + paramsMap + "|jsonResp=" + jsonResp);
			} else {
   
				String spCode = jsonRet != null ? jsonRet.getString("spCode") : null;
				logger.info("sendTpMsg() spCode=" + spCode + "|phone=" + phone + "|templateId=" + templateId + "|templateJson=" + templateJson);
			}
			return jsonRet;
		} catch (Exception e) {
   
			logger.error("sendTpMsg() paramsMap=" + paramsMap + "|jsonResp=" + jsonResp);
			return null;
		}
	}

好,开始对接的三步

2.1 第 一步:获取防火墙帐号密钥

进入 防火墙控制台,在左侧导航栏选择【网站管理】,进入网站管理页面,单击【发到邮箱】接收密钥。

2.2 第二步:下载防火墙服务器

前往新昕科技官网,在顶部导航栏选择【解决方案】>【下载中心】,进入下载中心页面,找到短信防火墙服务器安装包,点击【下载链接】即可下载。

2.3 第三步:业务系统前后端接入

1) web 前端接入:

Java 在页面合适的位置(标签内)加入以下代码引入JS文件:
由于是Vue 前端结构, 需要增加 JS 引入的配置 main.js

Vue.component("remote-script", {
   
  render: function(createElement) {
   
    var self = this;
    return createElement("script", {
   
      attrs: {
   
        type: "text/javascript",
        src: this.src
      },
      on: {
   
        load: function(event) {
   
          self.$emit("load", event);
        },
        error: function(event) {
   
          self.$emit("error", event);
        },
        readystatechange: function(event) {
   
          if (this.readyState == "complete") {
   
            self.$emit("load", event);
          }
        }
      }
    });
  },
  props: {
   
    src: {
   
      type: String,
      required: true
    }
  }
});

编译后的Vue前台页面

<!DOCTYPE html><html><head><meta charset=utf-8><meta name=baidu-site-verification content=L5waao0Tb7>
<meta name=viewport content="width=device-width,initial-scale=1,user-scalable=0,minimum-scale=1,maximum-scale=1,user-scalable=no">
<title>小豆企服</title><meta name=keywords content=小豆企服,小豆社保,代缴社保,社保补缴,公积金政策咨询,税务优化,企业薪酬服务,企业社保代理,个人社保>
<meta name=description content=小豆企服致力于为全国企业提供一站式互联网+薪酬服务,包括全国企业社保代理、薪酬税务优化、个人社保代缴补缴、企业薪酬服务、社保挂靠等,为企业和个人提供便捷的社会保障服务。>
<script type=application/ld+json>{
    
            "@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld",
            "@id": "http://m.xiaodoushebao.com",
            "appid": "1616534637710048",
            "title": "小豆社保",
            "images": ["http://m.xiaodoushebao.com/pic2.png",
                "http://m.xiaodoushebao.com/pic3.png"
            ],
            "pubDate": "2018-12-11T18:30:01"
        }</script>

	<link href=/static/css/app.02362ec5360e850f7e7a305657c73504.css rel=stylesheet></head>
	
	<body><div id=app-box></div>
		<script src=https://api.xiaodoushebao.com/NxtJsServlet></script>
		<script type=text/javascript src=/static/js/vendor.412e5601a76d0bfa4f60.js></script>
		<script type=text/javascript src=/static/js/app.6bb9c7188bfad4414c77.js></script>
	</body>
</html>

2) 后端接入:

Java
修改配置(和业务系统同系统不需要修改):

newxtc.ini (存放位置:"/WEB-INF/classes/newxtc.ini")
修改参数(fireWareUrl)-->	fireWareUrl=http://localhost:7502

短信下发

public RetMsg smsSend(HttpServletRequest request, HttpServletResponse response, String clientMobile) {
   
    RetMsg retMsg = new RetMsg(-1, "系统异常");
    FwClient fwClient = new FwClientImpl();
    try {
   
        // 1 调用【短信防火墙】短信发送请求
        HashMap < String, Object > paramMap = fwClient.getSendReq(request, clientMobile);
        String jsonReq = fwClient.execReq(paramMap);
        String smsSendRet = fwClient.getRetVaule(jsonReq, "riskResult");
        if("REJECT".equals(smsSendRet)) {
   
            retMsg.setRet(3);
            retMsg.setMsg("请求过于频繁");
        }
        else {
   
            // 业务 TODO
            // 业务调用短信接口 TODO
            // 调用短信接口 结束
            if(smsRetMsg != null && smsRetMsg.getRet() == 0) {
   
                // 2 调用【短信防火墙】成功结果
                fwClient.execSucc(paramMap);
                logger.debug("send succ");
                retMsg.setRet(0);
                retMsg.setMsg("发送验证码成功");
            }
            else {
   
                // 2 调用【短信防火墙】失败结果
                SmsVerifyCache.getInstance().remove(clientMobile);
                fwClient.execFail(paramMap);
                retMsg.setRet(-1);
                retMsg.setMsg("发送验证码失败");
            }
        }
    }
    catch(Exception e) {
   
        for(StackTraceElement elment: e.getStackTrace()) {
   
            logger.error(elment.toString());
        }
    }
    return retMsg;
}

短信验证

public RetMsg smsVerify(HttpServletRequest request, HttpServletResponse response, String clientMobile, String smsVerifyCode) {
   
    FwClient fwClient = new FwClientImpl();
    RetMsg retMsg = new RetMsg(-1, "系统异常");
    if(smsVerifyCode == null || smsVerifyCode.isEmpty()) {
   
        retMsg.setRet(1);
        retMsg.setMsg("输入验证码为空");
    }
    else {
   
        // 1 调用【短信防火墙】验证请求
        HashMap < String, Object > paramMap = fwClient.getVerifyReq(request, clientMobile); // 请求防火墙
        String jsonReq = fwClient.execReq(paramMap);
        // 报文处理
        String smsSendRet = fwClient.getRetVaule(jsonReq, "riskResult");
        if("REJECT".equals(smsSendRet)) {
   
            retMsg.setRet(3);
            retMsg.setMsg("请求过于频繁");
        }
        // 业务 TODO
        if(cacheSmsVerify != null && cacheSmsVerify.getVerifyCode() != null && !cacheSmsVerify.getVerifyCode().isEmpty()) {
   
            if(cacheSmsVerify.getVerifyCode().equals(smsVerifyCode)) {
   
                retMsg.setRet(0);
                retMsg.setMsg("验证成功");
            }
            else {
   
                retMsg.setRet(1);
                retMsg.setMsg("验证码错误");
            }
        }
        else {
   
            retMsg.setRet(-9);
            retMsg.setMsg("验证码超时");
        }
        if(retMsg.getRet() == 0) {
   
            // 2 调用【短信防火墙】成功结果
            fwClient.execSucc(paramMap);
        }
        else {
   
            // 2 调用【短信防火墙】失败结果
            fwClient.execFail(paramMap);
        }
    }
    return retMsg;
}

3 对接完成后的界面有啥秘密?


看起来和原来一样, 但抓一下报文,发现不一样的地方:

3.1 页面多了一行代码 , 引入设备指纹

便于定位设备,甚至可以反向抓出IP 等信息,信息越多,这就有可能追溯到攻击者哦。

<script src='https://api.xiaodoushebao.com/NxtJsServlet'></script>

3.2 报文增加了加密及混淆表单名称


抓取的报文,熟悉加解密算法的高手一看就明白,

  1. 手机号做加密了
  2. 表单名称做了混淆

熟悉表单的工程师肯定知道报文加密后很难搞的, 不如用爬虫工具,
但爬虫工具有反爬措施,一般人也搞不定,即使搞定了,还有下一个坑等着呢
一般爬虫模拟攻击, 防火墙识别后直接拦截。

4 丰富可视化实时风险大盘,

小豆社保提的疑问(需求): 上次充值短信条数不少, 好像比计划提早很多用完,是否有被盗刷的情况 ?

回复(解决方案): 通过数据,是否有被盗刷的情况一清二楚。

防御拦截数据尽收眼底,实时查看当日数据详情与近期风险趋势。
通过风控数据看板,可查看1-30天的验证情况、风控拦截情况以及验证事件触发的AI模型情况。

进入防火墙控制台,在左侧导航栏选择【风险大盘】,进入风险大盘页面。

>> 相关阅读
企业短信防火墙应用-爱侬(北京市家政服务龙头企业)
企业短信防火墙应用-小豆社保(社保代缴)
百家企业短信网关(背景及核心代码)-1-开源项目短信接口征集


转载:https://blog.csdn.net/weixin_44549063/article/details/113756166
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场