从答题赚钱APP谈谈接口防抓包

从答题赚钱APP谈谈接口防抓包

这段时间,答题赚钱APP真的是红遍了神州大地:国民老公王思聪的冲顶大会、芝士超人、西瓜视频,甚至连老司机韩路也玩起了这个游戏?。有利益就有动力,毕竟每场奖金都在十万、百万,虽然官方可以在最终答对人数上面掺水稀释每人的奖金,但是的确可能拿到奖金。人类,对这种可预期、强反馈的东西跟吸毒一样……于是,市面上出现了很多所谓的自动AI答题工具。大概可以分为两个流派:

  1. 通过OCR识别题目,然后用搜索引擎搜索答案告诉用户选什么。答案选择策略各异。做得比较简单的就是选搜索结果最多的那个为正确答案。
  2. 直接抓包这些APP下发的题目,然后用搜索引擎搜索答案。

可以看出,主要区别就是如何获取题目的文本。顺便吐槽一句,其实这些工具跟AI有半毛钱关系呀。对于第一种方式,是比较难防的。第二种方式解决办法主要有两种:

  1. 设计之初,使用图片下发题目,而不是直接下发题目文本;
  2. 如果已经走上了文本下发题目这条不归路,那么至少要做到接口防抓包。

这里我们谈一下接口如何防抓包。

为何可以成功抓包?

  1. 接口走HTTP,那么直接是明文传输,也不存在传输层的认证和加密问题,所见即所得。随着大家安全意识的增强,直接这么裸奔的产品越来越少。但是会有人因为各种原因就是不迁移到HTTPS,然后自己实现一个民科版的加密。我们极其不推荐这种做法,主要有以下几个原因:
    1. 大部分工程师都没有密码学背景,设计的算法基本很难完备的考虑数据机密性、完整性和不可抵赖性。
    2. 将应用层与数据传输层进行耦合不仅限制了通用性,如无法进行透明的流量转发,而且会带来非常高的系统维护和迁移成本。
  2. 接口走HTTPS。嗯,数据加密了不是?但是,通过中间人攻击(MitM)也是可以成功抓包的。这背后的基本原理是:在手机上安装一个中间人CA证书(如Charles证书) --> APP信任手机上的证书 --> 中间人可以成功解密流量进行抓包

如何防止抓包?

对于HTTPS API接口,如何防止抓包呢?既然问题出在证书信任问题上,那么解决方法就是在我们的APP中预置证书。在TLS/SSL握手时,用预置在本地的证书中的公钥校验服务器的数字签名,只有签名通过才能成功握手。由于数字签名是使用私钥生成的,而私钥只掌握在我们手上,中间人无法伪造一个有效的签名,因此攻击失败,无法抓包。

同时,为了防止预置证书被替换,在证书存储上,可以将证书进行加密后进行「嵌入存储」,如嵌入在图片中或一段语音中。这涉及到信息隐写的领域,这个话题我们有空了详细说。

预置证书/公钥更新问题

这样做虽然解决了抓包问题,但是也带来了另外一个问题:我们购买的证书都是有有效期的,到期前需要对证书进行更新。主要有两种方式:

  1. 提供预置证书更新接口。在当前证书快过期时,APP请求获取新的预置证书,这过渡时期,两个证书同时有效,直到安全完成证书切换。这种方式有一定的维护成本,且不易测试。
  2. 在APP中只预埋公钥,这样只要私钥不变,即使证书更新也不用更新该公钥。但是,这样不太符合周期性更新私钥的安全审计需求。一个折中的方法是,一次性预置多个公钥,只要任意一个公钥验证通过即可。考虑到我们的证书一般购买周期是3~5年,那么3个公钥,可以使用9~15年,同时,我们在此期间还可以发布新版本废弃老公钥,添加新公钥,这样可以使公钥一直更新下去。

Golang多级内存池设计与实现

Golang多级内存池设计与实现

上个月,牙膏厂intel因为MeltdownSpectre两个bug需要给CPU固件和系统打了补丁。我们生产环境使用的是阿里云,打完补丁后,几台IO密集型的机器性能下降明显,从流量和cpu load估计,性能影响在50%左右,不是说好的最多下降30%麽?

在跑的业务是go写的,使用go pprof对程序profiling了一下,无意中发现,目前的系统gc和malloc偏高。其中ioutil.ReadAll占用了可观的CPU时间。

ioutil.ReadAll为什么慢?

这个函数的签名原型是func ReadAll(r io.Reader) ([]byte, error). 团队的小伙伴非常喜欢用这个函数,其中一个原因是这个函数可以将r中的数据一次性读完返回,不需要关心内存如何分配、如果分配的内存不够了,如何进行内存扩张等。作为一个util函数,这样设计是完全没问题的。但是,IO密集场景下,这个函数的开销就是你需要关心的了。这个函数实际调用realAll读取数据:

其中,capacity是常量值512. realAll函数在调用buf.ReadFrom进行数据读取:

看到这里,原因就非常清楚了:如果要读取的数据大小超过了初始buf大小(默认初始大小为512 bytes), 则会重新分配内存,并拷贝内容到新的buffer中。如果要读取的数据非常大,则会重复多次上述操作。那么优化的问题就转化为如何降低内存重分配和拷贝。

多级内存池的设计和实现

  1. 内存池被按照大小被分为多级。如上图所示,(0, 1024]使用level 0, (1024, 2048]使用level 1. 内存池分级有两个好处:
    1. 可以灵活的规划不同级别内存池的总大小和item数量,适应不同业务。
    2. 实现层面上,可以将一把内存池大锁拆分成多个小锁,减少锁争抢。
  2. 当已分配的内存池耗尽需要扩张时,一次性申请一大块内存,提高扩张效率。如level 0所示。
  3. 代码实现gmmpool,bench结果显示性能提高约19倍:

小结

对于频繁进行内存分配和释放的场景,使用内存池可以显著降低golang运行时的开销。同时也要注意,内存池的内存交给了用户管理,你需要小心检查是否存在内存泄露问题。如果你对性能要求没有这么苛刻,只是想复用一些小对象,那么我们推荐你使用标准库的sync.Pool.

另外,开头提到的阿里云性能问题,即使使用了内存池优化,结果还是非常悲剧。最后阿里云帮我们更换了没有打牙膏厂补丁的机器解决。是不是非常惊喜??

APP上传文件到云端的正确姿势:据说值三万美金

APP上传文件到云端的正确姿势

近几年云存储和CDN的普及给多媒体文件存储和分发带来了诸多便利。如今要上线一个基础功能视频、图片网站,使用CDN厂商提供的服务,转码、存储、分发,甚至简单的访问控制都一站式搞定。想想以前个人站长时代,需要自己加硬盘、买带宽,自己使用ImageMagick和ffmpeg转码?‍♀️,真是酸爽。

云储存带来便利的同时,有很多安全问题往往容易被忽视。前段无人机独角兽大疆创新DJI爆出SSL 密钥和AWS key泄露问题,这使得黑客可以直接访问用户的私有视频内容。更有意思的是,泄露的原因居然是因为大疆把key放在了github上的开源项目的固件firmware中,而且已经这么放了4年,四年……?。这件事有意思的是,发现该密钥的哥们是一名叫做KF的白客,并把这个问题报告给了大疆,准备领取$30000的奖励,还预定了Tesla Model 3, 结果大疆法务把这花小钱就能解决的大事给谈炸了,KF的特斯拉没有了,但是大疆损失的可就不止这点小钱了。喜欢看故事的同学可以移步大疆 VS “白帽子”,到底谁威胁了谁?

如今移动互联网的天下,几乎每个APP都会上传文件到云端。这里,我们谈一下上传文件到云端的错误姿势背后的原因,以及正确姿势是什么样的。

错误的姿势

将云端的key保存在APP,然后APP直接调用接口上传文件。

很惊讶?我们的独角兽公司大疆同学就是这么干的呀。其实,不需要嘲讽大疆,你可以问一下你身边的互联网公司工作的同学,结果会让你更惊讶。

就我了解的情况,走上这条不归路有这几类原因:

  1. 创业公司野蛮生长的技术债。
  2. 部门墙的原因,有些公司的云端账号可能掌握在客户端开发小组的手里,而客户端同学对于服务器端的安全问题相对欠缺知识背景和敏感度。
  3. 程序员偷懒,不走云端标准交互流程,并且有严重的侥幸心理。

正确的姿势

正确的姿势其实也是一句话:

密钥保存在服务器,客户端每次向服务器申请一个一次性的临时token或signature,然后上传文件。

据我们的使用情况看,国内的CDN厂商都支持这种授权三方上传方式。比如又拍云的认证授权,阿里云OSS的授权给第三方上传

当然,实际的系统不可能这么简单。下面以我们前端时间设计和实施的上传流程为例,介绍我们在设计文件上传时的考量因素:

名词解释:cds, content delivery service, 这是上述流程中唯一自己开发的服务,感谢CDN的普及?

  1. 根据我们以往的客户端文件上传监控,客户端上传文件第一次尝试的失败率约为4%(这其实是一个比较可怕的数字,同时你也可以感受一下4G网络的复杂性)。因此,客户端申请上传签名时,可以指定多种类型。在我们的系统中,我们实际使用了两个CDN厂商承载上传请求:阿里OSS和云拍云。默认通过阿里OSS上传,又拍云作为灾备上传。
  2. 为了能达到高于CDN厂商之上的可用性,我们使用了两家CDN厂商(又拍云和七牛)进行内容分发。访问每一个文件的完整url地址是可配置的,因此我们可以在任一CDN出现问题的时候,在后台切换CDN。
  3. 可能有同学发现了我们使用了不太主流的又拍云。没有什么特殊原因,只是因为给的价格折扣比其他两家要低。
  4. 所有的云端数据都保存在阿里OSS,主要是基于阿里OSS可用性是跨可用区的。另一方面,这也实现了云端储存与内容分发的剥离。这意味着我们可以无痛的更换又拍云或者七牛云。
  5. 客户端上传文件成功以后,cds会收到一个回调通知,这里我们做了文件内容的合规检查和内容审计。当然,你可以在这里做一些数据挖掘的事情。

小结

他山之石,可以攻玉。据说,大疆犯错的程序员已经被劝(开)退(除)了。如果你所在的公司还存在类似的问题,赶紧行动起来吧。