胡律师:13306647218

数据接口如何保护安全《接口对接如何保证API接口安全》

时间:2021-07-23 18:49:02

一、摘要

在实际的业务开发过程中,我们经常需要与第三方互联网公司进行技术对接。 例如支付宝支付对接、微信支付对接、高德地图查询对接等服务。 如果你是创业型互联网的话,大部分可能都与其他公司的api接口对接。

当你的公司体量上涨的时候,这个时候,一些公司可能开始对你进行技术对接,变成了你提供api接口。 那时,我们应该如何设计和保证api接口的安全呢?

二、方案介绍

最常见的情况主要有两种。

token方案接口签名

2.1、token方案

中,token方案是web端使用最广泛的接口认证方案。 我想你以前写过《手把手教你,使用JWT实现单点登录》的报道,其中有详细介绍,有兴趣的人请读一下。 不认识的人没关系。 这里简单介绍一下token方案。

接口对接如何保证API接口安全

由上图可知,token方案的实现主要有以下步骤。

1 .用户登录成功后,服务端为用户生成唯一有效的证书。 这个有效值被称为token2,每次用户请求其他业务接口时,都需要在请求头上携带token3,当服务端接受客户端业务接口的请求时,验证token的合法性,如果不符合法律,则返回clarate 如果合法的话,就进入业务处理流程。 在实际使用中,用户登录成功后,生成的token保存在redis中时会有时效。 通常设定为2小时,经过2小时后自动无效。 此时,需要再次登录,再次获取有效的token。

token方案是目前业务类型项目中使用最广泛的方案,实用性非常高,可以有效防止黑客们抓包、获取数据。

但是token方案也有一些缺点! 最明显的是与第三方公司对接接口的时候。 当你的接口请求量非常大时,此时token突然失效,大量的接口请求失败。

这是非常实际的感受。 我记得很早的时候,和一家大型网络公司合作的时候,他们提供的接口对接方案是token方案。 当时,我们的流量高峰期,要求他们的接口报告大量错误,是因为token出了故障。 如果token发生故障,我们会调用他们更新token接口,在更新完成后,从token失效到重新更新token的期间,会大量产生请求失败的日志,因此在实际的API对接中采用了token方式。

2.2、接口签名

接口签名,顾名思义,是用几个签名规则对参数进行签名,将签名的信息放入请求标头,在服务端收到客户机的请求后,同样按照确定的规则生成对应的签名列和客户机的签名信息

接口对接如何保证API接口安全

接口签名方案主要有四个核心参数:

1、appID表示APP组id,其中匹配的是appsecret,表示APP组密钥,用于数据的签名加密,为不同的对接项目分配不同的appID和appsecret,保证数据的安全2、 请求的时间戳与服务器内的时间戳之差在5分钟以内,是有效的请求,不在此范围内的无效请求3、nonce表示临时的流号,用于防止重新提交验证。 4、签名表示签名字段,用于判断接口请求是否有效。 其中,签名的生成规则分为两个步骤。

步骤1 :对请求参数进行一次md5加密签名//步骤1

String参数1=请求方式请求URL相对地址请求Body字符串;

String参数1加密结果=md5(参数1 ) () ) ) ) ) ) ) ) ) ) )。

步骤2 :对步骤1的签名结果再次进行md5加密签名//步骤2

String参数2=appsecret timestamp nonce参数1加密结果;

String参数2加密结果=md5 (参数2 ) )

参数2加密的结果是我们要求的最终签名列。

接口签名方式仍然稳定,特别是在接口请求量较大的情况下。

也就是说,可以认为接口签名是对token方案的补充。

但是,如果想将接口签名案普及到前后对接,答案是“不适合”。

因为签名的计算非常复杂,其次,appsecret容易泄露!

说了这么多,下次一起用程序实践吧!

二、程序实践

2.1、token方案

如上所述,token方案的重点是用户登录成功后,只需要生成对应的token并返回前端,下次请求业务接口时需要自带token。

具体实践也可以分为以下两部分。

第一,使用uuid生成token,在redis中存储token,将有效期设定为2小时。 二是利用JWT工具生成token。 这个token可以跨平台,自然支持分布式,但本质上是使用时间戳密钥生成token。 接下来,介绍第二种实现方法。

首先,创建一个jwt工具。

publicclassJwtTokenUtil{

定义token回到头上

publicstaticfinalstringauth _ header _ key='授权';

//token前缀

publicstaticfinalstringtoken _ prefix=' bearer ';

//签名密钥

publicstaticfinalstringkey=' q3t6w9z $ cf (j @ ncqftjwnzr4u7x ';

//有效期限默认为2小时

publicstaticfinallongexpiration _ time=1000 l * 60 * 60 * 2;

//*

创建工具包

* * @ param内容

* * @返回

*/

公共建筑内容(字符串内容) {

返回令牌_前缀jwt.create (

.带主题(内容) )。

. withexpiresat (新日期(系统.当前时间米) )表达式)

. sign(algorithm.hmac512 )密钥);

}

//*

验证吨

* * @ param吨

*/

公共字符串验证密钥(字符串令牌)吞吐量执行{1}

特里

return jwt.require (algorithm.hmac 512 (关键点) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )。

. build () ) )

.验证(token .替换) Token_prefix,' '

获得主题(;

} catch (土耳其语) )

窄新表示法(' token无效。 请再次登录',e );

} catch (jwtverificationexceptione ) {

thrownewexception('token验证失败!' 、e;

}

}

}

然后,在登录时生成token并返回给客户端。

@请求映射(值=' /登录',方法=请求方法.后期,产品={ '应用程序/JSon; charset=UTF-8'} )

publicuservologin (requestbodyuserdtouserdto,HttpServletResponseresponse ) {

//.验证参数的合法性

//从数据库获取用户信息

userdb用户=用户服务. selectbyuserno (用户到用户否);

//…用户、密码认证

创建//Token,并将token置于响应头中

usertokenusertoken=新用户token (;

beanutils .复制属性(dbuser,用户令牌);

string token=jwttokenutil.create token (JSON对象. tojsonstring (用户token );

response.setheader (jwttokenutil.auth _ header _ key,token );

//定义返回结果

uservoresult=新用户VO (;

beanutils .复制属性(数据库,结果);

返回结果;

}

最后,创建一个集成中心,以验证客户端的token是否有效。

@Slf4j

publicclassauthenticationinterceptorimplementshandlerinterceptor {

@Override

公共外交事务处理(httpservletrequestrequest,HttpServletResponseresponse,对象处理程序)吞吐量

从http请求标头中取出token

finalstringtoken=request.get header (jwttokenutil.auth _ header _ key );

如果没有映射到//方法,则直接通过

if (! (handlerinstanceofHandlerMethod () ) ) ) )。

返回真;

}

//如果是方法探测的话,直接通过

if (http method.options.equals (请求方法() ) ) ) ) ) ) ) ) )。

响应. set状态(http servlet响应. sc _ ok );

返回真;

}

//方法中如果有JwtIgnore注释,则直接通过

处理程序方法=(处理程序方法)处理程序;

方法方法=处理程序方法.获取方法(;

if (method.isannotationpresent (jwt ignore.class ) )

jwtignorejwtignore=method.get annotation (jwt ignore.class );

if(jwtignore.value () ) ) ) )。

返回真;

}

}

local assert.isstringempty (Token,' token为空,认证失败!' );

//验证,获取token的内部信息

stringusertoken=jwttokenutil .验证token;

将token放入本地缓存

webcontext util.setuser令牌(用户令牌);

返回真;

}

@Override

公共集成(httpservletrequestrequest,HttpServletResponseresponse,对象处理程序,扩展请求) throwsee

//方法结束后,删除缓存的token

WebContextUtil.removeUserToken (;

}

}

生成token时,可以将用户ID、用户名等基本用户信息保存在token中。 这样,在token认证通过后,只需要解析内部信息就可以获取对应的用户ID,从而省去数据库查询基本信息的操作。

同时,在使用中,尽量不要保管机密信息。 因为容易被黑客解析!

按照与

2.2、接口签名

相同的思路,站在服务器端验证的立场上,可以首先创建签名拦截器,以验证客户端传递的参数是否合法。 只要有一个不正当的地方,就会提示错误。

具体的代码实践如下

publicclassigninterceptorimplementshandlerinterceptor {

@自动无线

私有应用程序服务应用程序服务;

@自动无线

privateRedisUtilredisUtil

@Override

公共房屋银行(httpservletrequestrequest,HttpServletResponseresponse,对象处理程序) )。

throws执行{2}

//appId验证

finalstringappid=request.get header (应用程序标识符);

if (字符串实用程序. isempty (应用程序) )

thrownewcommonexception('appid不能为空);

}

stringappsecret=appsecretservice.getappsecretbyappid (应用程序标识符;

if (字符串实用程序. isempty (应用程序集) )

thrownewcommonexception;

}

//时间戳验证

finalstringtimestamp=request.get header (' timestamp );

if (字符串实用程序. isempty (时间戳) )

thrownewcommonexception (' timestamp不能为空);

}

//5分钟以上,请不要作弊

long diff=系统.当前时间毫米(-long .透视长)时间戳记;

if (math.ABS (差异) 1000*60*5) {

thrownewcommonexception;

}

//临时流水号,防止重复提交

finalstringnonce=request.get header (' nonce );

if (string utils.isempty (无) )

thrownewcommonexception('nonce不能为空);

}

//验证签名

finalstringsignature=请求.获取标头(签名);

if (string utils.isempty (无) )

thrownewcommonexception (' signature不能为空);

}

finalstringmethod=request.get method (;

finalstringurl=request.getrequest uri (;

finalstringbody=stream utils.copy tostring (请求.获取输入),charset.forname('utf-8 ' ) )

stringsignresult=sign util.get signature (方法、网址、主体、时间戳、无、应用签名);

if (! 信号质量(信号结果) )

thrownewCommonException ('签名验证失败);

}

//检查请求是否重复

字符串键=应用程序时间戳' _ '无;

if (redis实用程序退出(密钥) )

thrownewCommonException;

}

//安装5分钟

redis util.save (密钥,签名结果,5*60 );

request.set属性(' Reid skey ',密钥);

}

@Override

公共集成(httpservletrequestrequest,HttpServletResponseresponse,对象处理程序,扩展请求) ) )。

throws执行{2}

//请求处理结束后,删除缓存

字符串值=请求.获取属性(红色天空);

if (! string utils.isempty (值) }{

redis util.remove (值;

}

}

}

签名工具类SignUtil :

公共类sssignutil {

//*

* *签名计算

* * @参数方法

* * @ param URL

* * @参数本体

* * @参数时间戳

* * @ param nonce

* * @ paramappsecret

* * @返回

*/

公共字符串获取器(字符串方法、字符串规则、字符串体、字符串时间戳、字符串无、字符串应用程序)

//第一层的信号

string requeststr1=methodurlbodyappsecret;

stringsignresult1=digest utils.m d5hex (requeststr1);

//第二段的签名

string requeststr2=appsecrettimestampnoncesignresult 1;

stringsignresult2=digest utils.m d5hex (requeststr2);

returnsignResult2;

}

}

签名计算可以替换为hamc方式进行计算,想法大致相同。

三、小结

上介绍的token和接口签名方案可以保护对外提供的接口,防止他人篡改请求和伪装请求。

但是,对数据本身缺乏安全性。 这意味着请求的参数和返回的数据可能会被其他人拦截和获取。 此外,由于这些数据是明文的,如果被拦截,则可以获取适当的商业数据。

在这种情况下,建议对请求参数和返回参数(如RSA、AES等加密工具)进行加密。

另外,在生产环境中,通过https方式进行传输,可以起到安全保护的作用! 这根据公司的业务需要很方便,一般公司都会有标准的对接方案。 在这里可以互相交流学习,以供参考