1024搬砖之IG密码加密方案分析

10.24本来是普通的日子,但却有机会让你很容易的区分的两种人:程序猿与其他。

正好周六,于是把之前 side project 中的一个临时方案修改一下。其中一个关键问题点是:用 go 生成 Instagram 登录时需要用到的加密密码。

C# 版本代码如下

扫了一下整体结构,发现IG的这段加密设计还是很好的体现了大厂典范:

  1. 密码加密使用到了 aes-256-gcm, 不是野生程序员上来就是base64或者来一个自欺欺人的哈希函数(MD5, SHA1等)。这两者本身不应该一起提,因为本身是用途完全不一样的东西,只是国内看过很多方案是后者,有时候还觉得自己加了salt更安全。AES结合GCM在解决数据加密问题的同时,也解决是数据完整性校验的问题。此外,加密操作中引入time作为附加数据,因此也可以校验数据的时效性,防止重放攻击。
  2. AES是一种对称加密,因此涉及的密钥分发的问题。上述方案中,使用了SealedPublicKeyBox 这种常用且规范的源于。即通过接收者的公钥来解密AES的对称密钥,得到密钥的密文。而这个密钥密文只有接收者使用自己的私钥才能解密。
  3. 从私钥密钥去中心化以及管理维护成本出发,应该是同时启用了多对公私钥对(可通过keyId识别)。
  4. 密文bytes构造上采用经典简洁的length.content设计。
  5. 最终构造的 enc_password 格式中包含了平台、版本、时间戳、密文。如果你也设计过密码加密的方案,你应该能看到这几个要素没有一点废话,基本就是教科书的标准格式示范。调研了一圈,发现的唯一业务上的槽点是版本为某个特定值时,其实是允许传输明文密码的。这从语义上来说是矛盾的,推测是从前向兼容的一种妥协。
  6. golang中可以通过 NewGCM 实现 aes-256-gcm, 但是认证标签(authentication tag) 没有单独输出,是append在密文之后的。因此可以通过 cipherText[len(cipherText)-16:] 获取。
  7. golang中没有 SealedPublicKeyBox 原语。可以用 package golang.org/x/crypto/nacl/box 中的 SealAnonymous 代替。

其实密码加密方案有很多基本的概念和原则,国外大厂也有很多规范的设计。只要不是一开始就想当然,其实是能找到或者设计出一个符合业务需求且安全高效的加密方案的。

特殊的一天,在老家楼上分析了一段有意思的代码,完整了方案的重构,还开着遥控车在农村撒欢越野。 What a beautiful day!

九月总结及阶段思考

9月最后一天,开完最后一个会议,早早的从公司溜了,顺便突然出现在妞儿单位的停车场给她个惊喜,同时实现一下接女儿放学的小小心愿,这应该是9月份最开心的事了(还真是枯燥无味,朴实无华…)。

9.30意味着S1财年结束了。转瞬间,两年过去了,很多事情无论是经历的业务还是心路,过去的半年比过去的一年似乎更多更长,有着别样的滋味。

合作关系上一直比较幸运,少有的低谷也在不知不觉间得到了扭转。感恩这种幸运,同时也感谢自己一直坚持的信用价值。否则我相信纵使有更多人从身旁路过,也只不过是一个过客。

过去两年的主题一直是在找寻成长。但讽刺的是,从blog看,技术输出明显变少了。如今对于这一点已经非常坦然了,我相信技术出生的同学依然会介意这一点,因为技术上的学习和成长很容易从对比中去量化。人们对于可预期,强反馈的事物总是非常有执念。

然而,个人的成长远不止技术成长。其他层面的成长反而是非常难以标定和量化的。因此,过去一年,我一直在尝试通从别人眼中照镜子的方式来衡量自己的成长。这种照镜子一方面是你能够成就自己的同时,也能成就他人,并且这种成就有时候可能对你短期来说是有损的。比如,你闪光的idea、plan中关键的环节,这些你是否愿意交个他人,同时在一定程度上退身,兜底的是你,上台领奖交给他。坦率讲,我说的这些在过去的一年之于我不是“比如”,而是事实,我也并不是慈善家。但是,我出奇的发现,你在意的人其实是能够看清这背后的逻辑关系的,你的退身反而是价值和口碑的积累。

其次是要在你的关系网络中找到关键点。很多人谈中年危机,其实本质上都是因为他在他赖以生存的网络中出了问题,而这一切跟年龄无关,如果一定要说有什么关系的话,只是年轻的时候输了一局你还有下一局。从这点看,无论你是要在技术领域深入成为不可替代,还是在业务层面八面玲珑,四处延伸,本质上都是提高你在生存网络上的附着力。

最后是要充分理解精致利己主义者,这其中包括你自己。我一直认为个人的成长是内环境熵减的过程,如果你成长的速度高于平均,那么周围环境之于你就是一个熵增的过程。因此,但凡是在平均线以上,无论你主观如何认知和解释,本质上你都是在利己的同时在损人。而对于成长速度不在一个层次的人来说,彼此就是彼此的熵增和熵减。从这点看,个人成长跟不上公司发展速度的、夫妻二人成长速度差异太大的,最终只能分道扬镳。而我们可以做的就是不断的迭代中,无论是熵减还是被熵增,保持平和的心态,以及持续对抗的态度。

岁月无静好,希望至美!

谈谈这两年在业务中做技术的思考

一个闷热的中午,照常与几位同事在连廊吃午饭。跟我当初一起入职的同事提起说,已经两年了。他的感受一如他往常的云淡风轻:生了个娃,家庭上忙了很多,工作上留下的印象不多。而我告诉他,我觉得这两年挺漫长,当前的状态也是“很忙”的状态。这种长和忙其实也代表了过去两年的表象,而背后的一些事情值得细细思考和沉淀。

这个两年离技术更远了一些。很多技术出身的人是抵制甚至是有些许恐惧这种距离的。我也一样。技术同学的成长路径大概分两种:按照底层核心/中间件/业务系统由下至上或者自顶而下发展。每个环节根据个体差异,平均停留3~5年,而最后一个层级可能会停留多年。我属于前者。过程曲折,但是也没有什么可纠结的。而这种离技术的远不是完全放弃技术的积累,而是技术不再是唯一的首要位置。另一方面,在技术成长上需要更加体系的方式构建自己的技术框架。

比如,这两年追过Flutter, 了解了它在哪些场景下适合解决什么样的问题,以及解决效果及局限性是怎样。在很多前端同学还在犹豫是否要学习的时候,我已经基于Flutter上线了一个Demo. 但是继续深入的事情那就需要等待合适的土壤了。

这两年离业务近了很多。做业务的技术同学有个普遍的困惑:业务结果是前提,并且以业务结果评估技术结果,在不公平,但是也没办法。因此很容易掉入业务说啥就做啥的陷阱,最后长出来的系统千疮百孔,岌岌可危。这里有一个明显的误区,业务!=业务owner. 很多时候,技术同学只是解决了业务owner的问题,并没有从更高的层次不断抽象,去发现和解决真正的业务问题。

如何避免成为 CRUD boy? 这其实是个伪命题。正确的提问姿势是:如何避免成为只是个 CRUD boy? 两个做法可参考,一是使用已有的轮子或者自己造轮子让这种层次的开发大部分自动化,二是把剩下没法自动化的部分交给团队的人员梯队去消化。

业务系统没有技术含量?这个应该是很多职场初期同学都会问的问题。本着先问是不是,再说为什么的原则:业务系统并不是没有技术含量,而是技术价值输出的对象以及兑现的方式发生了变化。底层核心/中间件层面的轮子很容易在输出给上层系统使用的时候体现其价值。这也是很多技术同学非常熟悉和认可的技术产品生产方式. Talk is cheap, show me the code可以认为也是这种价值转换的诠释。这种价值转换最大的参考案例就是github。然而,对于业务系统而言,Talk is valuable, write the code: 理解和抽象业务非常重要,直接决定了代码的价值。更大层面上,你要理解其背后的用户模型和商业模型。

业务系统技术同学的价值体现在:1. 业务域80%通用问题的技术抽象识别;2. 根据抽象识别选择合适的底座或必要时候能打造适合业务状态的轮子;3. 支撑业务是基线,加速业务达成,扩大业务基本面价值是生命线。对于技术同学来说,要时刻思考:抽离掉技术底座和业务后,你的价值是否归零。

但是,并不是所有的业务都能持续下去。小到一个按钮功能,大到整个公司战略。签字画押前,多跟业务同学沟通,以及业务的历史合作方了解。下定决定了,那就接受那些无法改变的事情。但是,有一点很重要,靠谱的同学无论做什么业务会抢手受欢迎。

一直愉快的合作是非常罕见的。大部分合作都是信用积累和消耗的往复过程。对于个人品牌亦如此。所以,我鼓励大家对人对事上都较真一点,该点出的问题就说出来,不想接的招直接打回去。如果你连内心真实的不认可都无法输出,那么你的赞许也毫无意义。

坦率讲,过去两年虽然发生了很多事情,但是还是觉得自己挺幸运的。遗憾留给过去,平和的心态走向未来。