一、引子
今天我看项目上同事转给我的一份接口说明文档。看到如下的一个接口定义:
在这个接口里,有两部分数据,一个是放在 http头里的信息,一部分是放在 body里的数据。根据参数名称和简单的说明,我猜第一部分应该是用户认证信息,第二部分是接口要发送的数据。就是说调用这个接口需要用户认证。
这听上去没有问题,对一个商业系统来讲,对外暴露的api必须要经过用户认证,认证通过后,才会执行调用。
但是仔细看下去,有点不对味了。
二、背景调查
我们看他的http头信息,也就是用户认证信息:
1、bi-access-toen-user 接口用户,固定值
2、bi-access-token-code 接口秘钥,固定值(注:其实是密码,不是秘钥)
3、bi-access-token-timestamp 时间戳,取当前时间
4、bi-access-token-signature 加密穿,是 user + code + timestamp 字符串 的md5编码。
我问了给我文档的同事(同事甲),
我:既然 第四个参数 是由 前三个参数用公开的算法(md5)运算出出来的,为什么还要传?因为根据接口参数的设计规范,如果某个参数可以由其他的参数运算出来而且这个运算关系是幂等的,那么这个参数就是多余的。
同事甲:这是传数据的时候进行的MD5加密,MD5一般是不能反向找到密码的,因此推导不出来。 (这个回答答非所问)
同事没有回答我的问题,过了会又补充说:咱们的接口现在都是通用的,你们(的系统)也是这样的接口(设计)。
我又找到这个接口的设计者同事乙
我:我在前天转给你的▒▒▒▒系统的接口文档里看到的,每次调用接口都带着明文密码?
同事乙:带着,没那么严格,现在都是带着密钥。(他没有意识到问题)
我:你都md5了,完全不用密码了
同事乙:......(没有再回复。)
三、问题分析
下面我来分析下这个接口的问题。
1、接口里有密码明文。
这个在正式的系统里是不可接受的,想10年前,csdn报出来的丑闻,数据库中用户的密码都是明文,这个也就没啥可说的了。
在接口里传输认证信息是不可避免的,我谈谈避免明文密码的做法都有哪几种
(1)用https协议。这不用说,这个协议自己就会对数据进行加密,足够安全,但是需要在服务器配置证书。
(2)对密码进行md5加密。客户端传送 user id 和 md5之后的密码。服务端验证时,对密码采用同样的算法,只要md5后的密文和客户端传过来的一致,表示密码验证通过。
2、用户和密码是固定的
我不知道在调用接口的时候,是不是真的会硬编码使用这个用户和密码,至少接口文档中是这么写的。我相信不是,这说明文档写的不严谨,给用户传递了不准确的信息。
3、密码是多余的
因为第四个参数 是前三个参数运算出来的,只要传 user ,timestamp 和 signature就可以了。服务器可以从数据库中查到密码 按照接口的算法运算出 所谓的singnature,比较一下就ok,如果一直,就说明验证通过,否则失败。
4、在具体的接口调用中,存放认证信息,而且是明文,加大了密码泄露的风险。
这个问题,我想说的是什么,正确的接口设计应该是这样的,除了做具体业务的接口外,应该还有登录的接口,在调用业务接口之前,首先先调用登陆接口,获得token,调用业务接口时,只传送token就ok,知道token失效。这样密码明文传送的次数大大减少,暴露的风险也就降低了。
四、正确的做法
规范的接口调用流程,应该是这样的:
(1)调用认证接口得到token
认证接口,通过将userid,password等认证信息发送到服务,服务器形成token,返给客户端。
形成token的算法有很多,常用的是jwt。token有有效期。jwt的优点是 服务器端不需要保存session,token存在客户端。
(2)发起业务调用
在发起业务调用的额时候,传过去步骤(1)中得到的 token。
如果token服务器验证通过,调用成功。
使用token而不是用户和密码,减少了账号和密码在网路上暴露的次数,降低了风险,增强了安全性。
否则(比如token过期了)在重新执行步骤 (1)重新获得token
(3)退出
这是可选的,根据业务场景选用。退出后,服务器点将token作废。注意标准的jwt token认证协议中,token是无法作废的,除非服务器增加额外的处理逻辑。
五、结束语
从上看,这个接口的设计问题还是挺多的,严重违背了系统安全的设计规范,当然也通不过系统安全扫描。