后台接口开发与前端开发有不少不同,在并发、性能、容错、安全等方面都需要有一定的考虑......而且由于后台接口往往是直接或者间接的对数据库进行操作,所以在提供一个接口时,往往要考虑数据库数据是否有可能被人通过该接口恶意拷贝、修改甚至删除......
接口
我这里就最近碰到的一种现象来吐槽下:GetReportById(int reportId);看上去,这个接口很简单,功能也很明确,通过报告id查找报告,貌似没什么问题...
问题
但是,如果为该接口加上一些前提呢?首先该报告是与用户绑定的,其次该报告查看功能是不需登录的......此时,再来看看该接口:仅需一个报告id即可以获取到报告内容,一般情况下,这个报告id是主键,而且是自增的,那么,我导出数据库所有的报告只需要从1开始不断地改变入参reportId即可,显然,这是非常不安全的...(当然,可能有人觉得可以依托于其他方式来防止该问题,如IP调用限制、数据加密、入参id加密等)
解决
先来说说当我们没有使用数据加密时,有什么办法来防止数据通过接口循环导出?
1. 数据校验
想想,我们上面说的前提,报告是属于用户的,那么我们简单的修改下接口,改成GetReportById(int reportId, it userId),在通过报告id获取报告时校验下是否属于该用户,则可以防止数据被简单的循环导出了。
2. 入参加密
另外,更深一个层次,我们队入参id进行加密,使入参不再单纯的是自增id,而是一种无规律的字符串,那么,就对数据的保护是不是就更强了?
比如我们定一个id的加密方法(这里只是一个简单的示例):
原id为: reportId = 1;
定义一个随机值: code = new Random().nextInt(100);
加密后的id为: encryptId = (reportId + code) * 5;
解密获取原id: reportId = encryptId / 5 - code;
此时,我们的接口应该是GetReportById(encryptId, int code, it userId),当然,userId也可以进行加密,这里只是作为示例就不考虑这么多了...
3. 出参加密
即对数据出参进行加密,此时一般都会用到时间戳之类的作为加解密因子,所以接口可能会变为GetReportById(int encryptId, int code, long timestamp, it userId)
总结
相对于最初的GetReportById(int reportId)而言,后面的三个操作都带入了基础业务上不需要的参数,这些参数看上去确实是多余的。
因为我只需要报告,通过id查找报告,很简单的一个实现,而最后却加了一堆不解释看不懂的参数,可能会让人感觉莫名其妙。然而,这些参数却能解决数据安全问题,可谓“冗余并不一定是坏的”。
简书:ThinkinLiu 博客: IT老五
ps: 最近这段时间该webapi经常看到一些GetReportById(int reportId)类型的接口,所以就写了这篇文章,谈谈自己的看法,解除后台开发不久,如写得有问题,或者由于我知识面浅薄,有其他方式或在其他层面已经解决了该问题(不再需要考虑这种安全性问题),欢迎指教...