游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

SpringBoot如何保证接口安全?老鸟们都是这么玩的!

  对于互联网来说,只要你系统的接口暴露在外网,就避免不了接口安全问题。如果你的接口在外网裸奔,只要让黑客知道接口的地址和参数就可以调用,那简直就是灾难。
  举个例子:你的网站用户注册的时候,需要填写手机号,发送手机验证码,如果这个发送验证码的接口没有经过特殊安全处理,那这个短信接口早就被人盗刷不知道浪费多少钱了。
  那如何保证接口安全呢?
  一般来说,暴露在外网的api接口需要做到防篡改和防重放才能称之为安全的接口。防篡改
  我们知道http是一种无状态的协议,服务端并不知道客户端发送的请求是否合法,也并不知道请求中的参数是否正确。
  举个例子,现在有个充值的接口,调用后可以给用户增加对应的余额。http:localhostapiuserrecharge?userid1001amount10
  如果非法用户通过抓包获取到接口参数后,修改userid或amount的值就可以实现给任意账户添加余额的目的。如何解决
  采用https协议可以将传输的明文进行加密,但是黑客仍然可以截获传输的数据包,进一步伪造请求进行重放攻击。如果黑客使用特殊手段让请求方设备使用了伪造的证书进行通信,那么https加密的内容也会被解密。
  一般的做法有2种:采用https方式把接口的数据进行加密传输,即便是被黑客破解,黑客也花费大量的时间和精力去破解。接口后台对接口的请求参数进行验证,防止被黑客篡改;
  步骤1:客户端使用约定好的秘钥对传输的参数进行加密,得到签名值sign1,并且将签名值也放入请求的参数中,发送请求给服务端步骤2:服务端接收到客户端的请求,然后使用约定好的秘钥对请求的参数再次进行签名,得到签名值sign2。步骤3:服务端比对sign1和sign2的值,如果不一致,就认定为被篡改,非法请求。防重放
  防重放也叫防复用。简单来说就是我获取到这个请求的信息之后什么也不改,,直接拿着接口的参数重复请求这个充值的接口。此时我的请求是合法的,因为所有参数都是跟合法请求一模一样的。
  重放攻击会造成两种后果:针对插入数据库接口:重放攻击,会出现大量重复数据,甚至垃圾数据会把数据库撑爆。针对查询的接口:黑客一般是重点攻击慢查询接口,例如一个慢查询接口1s,只要黑客发起重放攻击,就必然造成系统被拖垮,数据库查询被阻塞死。
  对于重放攻击一般有两种做法:基于timestamp的方案
  每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数一起进行数字签名。因为一次正常的HTTP请求,从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间比较,是否超过了60s,如果超过了则认为是非法请求。
  一般情况下,黑客从抓包重放请求耗时远远超过了60s,所以此时请求中的timestamp参数已经失效了。如果黑客修改timestamp参数为当前的时间戳,则sign1参数对应的数字签名就会失效,因为黑客不知道签名秘钥,没有办法生成新的数字签名。
  但是这种方式的漏洞也是显而易见,如果在60s之内进行重放攻击,那就没办法了,所以这种方式不能保证请求仅一次有效。
  老鸟们一般会采取下面这种方案,既可以解决接口重放问题,又可以解决接口一次请求有效的问题。基于noncetimestamp的方案
  nonce的意思是仅一次有效的随机字符串,要求每次请求时该参数要保证不同。实际使用用户信息时间戳随机数等信息做个哈希之后,作为nonce参数。
  此时服务端的处理流程如下:去redis中查找是否有key为nonce:{nonce}的string如果没有,则创建这个key,把这个key失效的时间和验证timestamp失效的时间一致,比如是60s。如果有,说明这个key在60s内已经被使用了,那么这个请求就可以判断为重放请求。
  这种方案nonce和timestamp参数都作为签名的一部分传到后端,基于timestamp方案可以让黑客只能在60s内进行重放攻击,加上nonce随机数以后可以保证接口只能被调用一次,可以很好的解决重放攻击问题。代码实现
  接下来通过实际代码来看看如何实现接口的防篡改和防重放。1、构建请求头对象DataBuilderpublicclassRequestHeader{privateStringsign;privateLongtimestamp;privateStringnonce;}2、工具类从HttpServletRequest获取请求参数Slf4jUtilityClasspublicclassHttpDataUtil{post请求处理:获取Body参数,转换为SortedMapparamrequestpublicSortedMapString,StringgetBodyParams(finalHttpServletRequestrequest)throwsIOException{byte〔〕requestBodyStreamUtils。copyToByteArray(request。getInputStream());StringbodynewString(requestBody);returnJsonUtil。json2Object(body,SortedMap。class);}get请求处理:将URL请求参数转换成SortedMappublicstaticSortedMapString,StringgetUrlParams(HttpServletRequestrequest){Stringparam;SortedMapString,StringresultnewTreeMap();if(StringUtils。isEmpty(request。getQueryString())){returnresult;}try{paramURLDecoder。decode(request。getQueryString(),utf8);}catch(UnsupportedEncodingExceptione){e。printStackTrace();}String〔〕paramsparam。split();for(Strings:params){String〔〕arrays。split();result。put(array〔0〕,array〔1〕);}returnresult;}}
  这里的参数放入SortedMap中对其进行字典排序,前端构建签名时同样需要对参数进行字典排序。3、签名验证工具类Slf4jUtilityClasspublicclassSignUtil{验证签名验证算法:把timestampJsonUtil。object2Json(SortedMap)合成字符串,然后MD5SneakyThrowspublicbooleanverifySign(SortedMapString,Stringmap,RequestHeaderrequestHeader){StringparamsrequestHeader。getNonce()requestHeader。getTimestamp()JsonUtil。object2Json(map);returnverifySign(params,requestHeader);}验证签名publicbooleanverifySign(Stringparams,RequestHeaderrequestHeader){log。debug(客户端签名:{},requestHeader。getSign());if(StringUtils。isEmpty(params)){returnfalse;}log。info(客户端上传内容:{},params);StringparamsSignDigestUtils。md5DigestAsHex(params。getBytes())。toUpperCase();log。info(客户端上传内容加密后的签名结果:{},paramsSign);returnrequestHeader。getSign()。equals(paramsSign);}}4、HttpServletRequest包装类publicclassSignRequestWrapperextendsHttpServletRequestWrapper{用于将流保存下来privatebyte〔〕requestBodynull;publicSignRequestWrapper(HttpServletRequestrequest)throwsIOException{super(request);requestBodyStreamUtils。copyToByteArray(request。getInputStream());}OverridepublicServletInputStreamgetInputStream()throwsIOException{finalByteArrayInputStreambaisnewByteArrayInputStream(requestBody);returnnewServletInputStream(){OverridepublicbooleanisFinished(){returnfalse;}OverridepublicbooleanisReady(){returnfalse;}OverridepublicvoidsetReadListener(ReadListenerreadListener){}Overridepublicintread()throwsIOException{returnbais。read();}};}OverridepublicBufferedReadergetReader()throwsIOException{returnnewBufferedReader(newInputStreamReader(getInputStream()));}}
  防篡改和防重放我们会通过SpringBootFilter来实现,而编写的filter过滤器需要读取request数据流,但是request数据流只能读取一次,需要自己实现HttpServletRequestWrapper对数据流包装,目的是将request流保存下来。5、创建过滤器实现安全校验ConfigurationpublicclassSignFilterConfiguration{Value({sign。maxTime})privateStringsignMaxTime;filter中的初始化参数privateMapString,StringinitParametersMapnewHashMap();BeanpublicFilterRegistrationBeancontextFilterRegistrationBean(){initParametersMap。put(signMaxTime,signMaxTime);FilterRegistrationBeanregistrationnewFilterRegistrationBean();registration。setFilter(signFilter());registration。setInitParameters(initParametersMap);registration。addUrlPatterns(sign);registration。setName(SignFilter);设置过滤器被调用的顺序registration。setOrder(1);returnregistration;}BeanpublicFiltersignFilter(){returnnewSignFilter();}}Slf4jpublicclassSignFilterimplementsFilter{ResourceprivateRedisUtilredisUtil;从fitler配置中获取sign过期时间privateLongsignMaxTime;privatestaticfinalStringNONCEKEYxnonce;OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{HttpServletRequesthttpRequest(HttpServletRequest)servletRequest;HttpServletResponsehttpResponse(HttpServletResponse)servletResponse;log。info(过滤URL:{},httpRequest。getRequestURI());HttpServletRequestWrapperrequestWrappernewSignRequestWrapper(httpRequest);构建请求头RequestHeaderrequestHeaderRequestHeader。builder()。nonce(httpRequest。getHeader(xNonce))。timestamp(Long。parseLong(httpRequest。getHeader(XTime)))。sign(httpRequest。getHeader(XSign))。build();验证请求头是否存在if(StringUtils。isEmpty(requestHeader。getSign())ObjectUtils。isEmpty(requestHeader。getTimestamp())StringUtils。isEmpty(requestHeader。getNonce())){responseFail(httpResponse,ReturnCode。ILLEGALHEADER);return;}1。重放验证判断timestamp时间戳与当前时间是否操过60s(过期时间根据业务情况设置),如果超过了就提示签名过期。longnowSystem。currentTimeMillis()1000;if(nowrequestHeader。getTimestamp()signMaxTime){responseFail(httpResponse,ReturnCode。REPLAYERROR);return;}2。判断noncebooleannonceExistsredisUtil。hasKey(NONCEKEYrequestHeader。getNonce());if(nonceExists){请求重复responseFail(httpResponse,ReturnCode。REPLAYERROR);return;}else{redisUtil。set(NONCEKEYrequestHeader。getNonce(),requestHeader。getNonce(),signMaxTime);}booleanaccept;SortedMapString,StringparamMap;switch(httpRequest。getMethod()){caseGET:paramMapHttpDataUtil。getUrlParams(requestWrapper);acceptSignUtil。verifySign(paramMap,requestHeader);break;casePOST:paramMapHttpDataUtil。getBodyParams(requestWrapper);acceptSignUtil。verifySign(paramMap,requestHeader);break;default:accepttrue;break;}if(accept){filterChain。doFilter(requestWrapper,servletResponse);}else{responseFail(httpResponse,ReturnCode。ARGUMENTERROR);return;}}privatevoidresponseFail(HttpServletResponsehttpResponse,ReturnCodereturnCode){ResultDataObjectresultDataResultData。fail(returnCode。getCode(),returnCode。getMessage());WebUtils。writeJson(httpResponse,resultData);}Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{StringsignTimefilterConfig。getInitParameter(signMaxTime);signMaxTimeLong。parseLong(signTime);}}6、Redis工具类ComponentpublicclassRedisUtil{ResourceprivateRedisTemplateString,ObjectredisTemplate;判断key是否存在paramkey键returntrue存在false不存在publicbooleanhasKey(Stringkey){try{returnBoolean。TRUE。equals(redisTemplate。hasKey(key));}catch(Exceptione){e。printStackTrace();returnfalse;}}普通缓存放入并设置时间paramkey键paramvalue值paramtime时间(秒)time要大于0如果time小于等于0将设置无限期returntrue成功false失败publicbooleanset(Stringkey,Objectvalue,longtime){try{if(time0){redisTemplate。opsForValue()。set(key,value,time,TimeUnit。SECONDS);}else{set(key,value);}returntrue;}catch(Exceptione){e。printStackTrace();returnfalse;}}普通缓存放入paramkey键paramvalue值returntrue成功false失败publicbooleanset(Stringkey,Objectvalue){try{redisTemplate。opsForValue()。set(key,value);returntrue;}catch(Exceptione){e。printStackTrace();returnfalse;}}}

10年前他靠一首我的滑板鞋火爆全国,如今却被嘲笑上热搜摩擦摩擦!是魔鬼的步伐,是魔鬼的步伐。。。。。。不知道各位在听到这段歌词的时候,脑海里是不是又响起了那魔性的歌喉,别的不说,光听这两句摩擦都能让大家的DNA动起来了。……全新一代骁龙7发布会定档3月17日见Redmi全球首发3月10日消息,今天早上高通中国官方微博正式官宣了骁龙新品发布会的时间。新的骁龙新品发布会定在了3月17日下周五,从目前网络上曝光的情况来看,该芯片无疑将是骁龙7Gen1……对标苹果!透明后盖LED灯带,NothingPhone价格被不得不说,随着人们的物质生活水平的不断提高,审美也在不断发生的改变。比如这几年流行的抽象艺术、太阳花、奈良美智、Supreme,还有元宇宙中的数字藏品,这些产物放在10年前,可……只想防超巨,詹姆斯也不怕!打服球队老板,是勇士让我变得贪婪前言近日NBA官方公布了2223赛季的完整赛程,其中全美直播场次最多的球队为勇士队,之后是湖人、凯尔特人和太阳以及76人,之所以勇士能够高居第一,力压詹姆斯所在的湖人队,……深度揭秘儿童U型和普通电动牙刷哪个好?很多家长为了孩子的牙齿健康简直是操碎了心,想要孩子自主清洁干净牙齿真不是一件简单的事情,所以儿童U型电动牙刷的出现也让很对家长心动,它在网上宣传的卖点是u型刷特殊的设计更加贴合……北方最宜居的3座海滨城市,比青岛性价比高,空气好养老绝佳说起北方最宜居的城市,很多人都会说是青岛,青岛的确很好,拥有媲美海南的优质沙滩,而且文化底蕴深厚,是难得的宜居之城。但青岛也有缺点,比如夏天比较潮湿,7、8月份比较热,关……夺韩国首金,黄大宪赢2亿韩元奖励!获终身保障,每月可领100北京时间2月11日消息,黄大宪在帮助韩国拿到北京冬奥会首金后,各种奖励来了,截至目前,黄大宪已经赢得了2亿韩元的奖金,约合人民币110万!因为对韩国体育的贡献,黄大宪如今获得了……亚的斯亚贝巴,见识全世界发现的第一个直立行走的人类祖先露西头号周刊东非大裂谷旅行故事之二埃塞俄比亚首都亚的斯亚贝巴背靠海拔3300米的恩托托山,阿瓦什河从这里蜿蜒流淌,气候湿润,鲜花盛开。与万里之遥的北京动辄30多度的炎热……三国志战略版2200区段龙军2272VS2205最新大事记大家好!我是2272龙军史官龙钺丨纳兰,首先恭喜兄弟盟:百战丨小鬼于2022年7月26日晚9点开关成功。26日可能注定不顺,龙军这边龙耀一开城失败,与霸业奖励擦将而过,……春天多给孩子吃蔬菜,分享6道快手菜,好做好吃,孩子爱吃长得快春天是万物生长的季节,也是孩子长高的黄金时期。家长们都希望抓住这个时期,让自己的孩子长得更高,身体更健康,在这个时候,除了给孩子吃一些高蛋白的肉类食物补充以外,还要多给孩子吃一……蓝眼泪奇妙夜4月7日,阳江海陵岛东岛龟石,璀璨星空,绝美银河,蓝色荧光海海浪起伏。南都拍客刘学林摄3月12日晚上8点,深圳西涌海滩,海岸线发出盈盈蓝光。南都拍客曾柏源摄3月13……郑薇请辞内蒙古,专注中国女篮!山东敲定新外援,超新星投奔青岛头条创作挑战赛据内蒙古媒体透露,为了专注于执教中国女篮,避免分心,再创佳绩,郑薇指导决定辞去内蒙古女篮主教练一职,改由国家队助理教练木拉提接任。这下压力可全都来到杜锋指导……
十万左右的国产suv,长城荣威比亚迪长安吉利和奇瑞哪个质量比首先要肯定一点,上面列举的这些品牌造车经验都是相当丰富的。尤其在造SUV上,除了荣威差一点起步晚之外,其他几个车企造SUV都是信手拈来,旗下的SUV总体质量都差不多。毕竟……阿里华为争相进入,AI制药能否探索生命禁区人类创造了AI,AI能否反过来拯救人类呢?除了问答聊天画画,ChatGPT们正在加速向细分领域渗透,而AI制药正成为当下AI应用落地的先行者。科技巨头跨界进入医疗赛道……怎么才能熟练倒车?倒车主要还是要通过查看后视镜,以及在最佳的时机快速调整方向盘角度,以保证车身在不同的阶段有正确的角度。倒车一般发生在进入停车位时,很多人经常犯一个错误,在开始倒车时角度就是错误……电动三轮车为什么允许生产销售,有的地方却不给上牌,不让上路?一些进入工信部目录的产品是允许生产销售的。这样的电动三轮车都是合规车辆,可以合法销售、合法上牌,依法上路。我们看一下进入工信部目录的部分电动三轮车品牌与型号:只要进入工信……排量越大越费油吗?很多人在买车的时候都有一个误区,认为车子排量越大越费油,其实这是一个非常错误的认知,今天我就来说说关于发动机排量和油耗之间的关系。先说一个我身边的真实故事十几年前,……想自驾游去一趟西藏,哪个时间段去最佳?五千元人民币够吗?这个是我们的行程和话费,供参考。行程:我是焦作的,我、我老婆和朋友夫妻在2019年8月2日下午5点出发的。第一天通宵开车直接杀向成都(焦作成都1150km),住在成……为什么老司机建议买车尽量买便宜的?首先,维修成本低廉,技术过硬,你见过电动窗坏的,中控锁失灵的,你见过手摇玻璃坏的吗?,多半是用力过猛摇把碎了,手动变速箱已经不能在老了,技术成精了,那些什么cvt,双离合,干湿……城市中电动自行车如果被彻底禁止了,会怎样?如果电动自行车被彻底禁止,那么自行车和摩托车就会增加。其实,电动自行车不适合城市使用,因为重量大、速度快、没有声音,容易撞人伤人,而且锂电池容易爆炸起火,铅电池污染严重。……一辆汽车的寿命有多久,15年以上的车真的就不能开吗?一辆汽车的寿命有多久,15年以上的车真的就不能开吗?一辆汽车的寿命有多久?那可长了,以今时今日车子的制造工艺来看,跑个百万公里都不是什么太难的事(出租车都能做到),而以咱……打坐调息时呼吸之间的停顿,是在呼完停顿,还是在吸满气后停顿?顺其自然,呼短息长下丹田,周气全身在息间。初学腹动,有功了气动。我是呼完停顿。吸满后停顿时,会感觉到气血从背部呼呼地往颈部涌,而且一直往上涌,这时候特别害怕头……为什么很多人都在戒糖呢?戒糖会给身体带来什么好处?从早餐的豆浆到下午的冷饮,再到晚上的巧克力,含糖食物全天陪伴着许多人。但是糖到底有多不健康?你怎么能戒掉它呢?糖并没有最好的声誉,但许多人不能不管它。糖是碳水化合物之一。……从喀什开车到拉萨,走219国道可以开小排量轿车吗?谢谢邀请。小排量轿车正走219一定要保证车况良好,并且要做好抗高反的物质和心理准备。从叶城219零公里起点算起,行驶100公里左右,将要翻越库地达坂,这里的弯道能把……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网