HASH算法在安全编程中的应用

密码学的安全,包含三个方面:

– 加密,数据在传输过程中加密,不被截获和窃听

– 完整性,数据传输到对端,防止被篡改

– 认证,对来源方和接收方都可以认证,防止冒充

本文主要描述Hash算法在安全编程中的认证应用场景。某个服务在对外部提供接口时候,为了对接口调用方做身份认证,保证调用方是合法授权过的而不是随意调用,一般都会要求在接口调用时,按照一定的规则对一些参数做hash签名,将签名和必要的参数一并发送到服务端,服务端收到请求后,按照同样的规则来重新生成hash签名和请求上行的签名做比对,以此来判断调用方的身份是否合法。本文主要对认证的常用做法及签名算法做简单剖析。

假设服务提供方提供的接口是基于http协议的形式,常用的具体做法:

– 服务提供方会预先分配给调用方一对key和secret,key一般用来标识调用方,而secret是调用方和服务提供方共享,并且不会在网络上直接传输;

– 调用方在调用某个http接口时,将部分请求参数比如param1=value1&param2=value2&param3=value3按照一定的规则排列,并加上secret,hash后生成签名sig;

– 发送请求时带上sig,则http请求字符串为 param1=value1&param2=value2&param3=value3&key=xxx&sig=xxx,服务端根据key值查询到对应的secret,按照同样的规则重新做hash生成sig,和请求的sig做比对,进而确定来源方的身份是否合法。

开发微信公众帐号时,微信服务器会推送公众号里产生的各种事件(自定义菜单点击事件、消息等)给到开发者注册的url上,开发者在收到这些事件时,需对来源方验证是否这些时间来自微信服务器而不是伪造的消息。

微信的验证方式如下:

4B17CCAB-3B58-4018-BD4E-C981CB8D5BD0
D83DB39C-C78E-4D50-AAF2-70A386C8BC6D
注意到,微信使用的hash算法为sha1,hash的内容包括了token(等同于上文提到的secret)、随机数、时间戳,三者按照字典顺序排列。

阿里云对象存储平台的API中也对开发者的请求做签名校验,具体请参考http://help.aliyun.com/document_detail/oss/api-reference/access-control/signature-header.html,但是采用的hash算法是hmac_sha1。

微信开放平台、阿里云API采用不同的hash算法,分别用sha1和hmac_sha1。微信开放平台签名生成方式,实际是MAC,key为微信公众平台的token,不在网络上传输,微信发送事件通知给开发者服务器上时,是知道开发者设置的token,开发者重新生成签名去验证时候,也是知道自己的token,timestamp、nonstr是明文传输的,根据三者来重新计算sha1,比对微信请求的signature即可。

MAC算法描述如下:

Message Authentication Code

MAC=hash(key+message)

作用:

– 校验数据完整性, 校验信息是否在传输过程中被恶意篡改或者被损坏

– 身份认证,确认信息来源方的身份

看起来没什么问题,既简单又能解决问题。可是为什么aliyun采用hmac_sha1算法做签名?是因为sha1、md5等hash算法能被扩展长度攻击,即使在不知道key的情况下,也能被攻破。

Wikipedia解释如下:

https://zh.wikipedia.org/wiki/%E9%95%BF%E5%BA%A6%E6%89%A9%E5%B1%95%E6%94%BB%E5%87%BB

在密码学和计算机安全中,长度扩展攻击(Length extension attacks)是指针对某些允许包含额外信息的加密散列函数的攻击手段。

该攻击适用于在消息与密钥的长度已知的情形下,所有采取了 H(密钥 ∥ 消息) 此类构造的散列函数[1]。MD5和SHA-1等基于Merkle–Damgård构造的算法均对此类攻击显示出脆弱性[2][3][4]。注意,由于散列信息验证码(HMAC)并未采取 H(密钥 ∥ 消息) 的构造方式,使用了脆弱算法的HMAC散列函数并不会受到此类攻击的影响[5]。SHA-3算法对此攻击免疫[6]。

可能觉得被长度扩展攻击的可能性到底有多大?有兴趣可以研究Flickr的api签名漏洞案例:

http://netifera.com/research/flickr_api_signature_forgery.pdf

HMAC

Hash-based Message Authentication Code

定义如下:
9D4FDED0-007F-48D2-AE2D-738581386FE4
解释:

H是hash函数,一般为sha、md5等

||字符串连接操作

⊕异或操作

opad,外填充常量,0x5c5c5c5c

ipad,内填充常量,0x36363636

伪码实现
BF89FA7C-2053-4EDB-8522-533B440B63BA785EE411-8416-401C-9D6C-F2E38315CE18
md5、sha1等hash的block size是64bytes,可以看伪码的注释部分:

– 如果key长度大于block size,则对key hash后重新赋值,截断其长度

– 如果key长度小于block size,则对key后补0,保证key长度等于block size

– 外填充key,用常量0x5c和key做block size次的异或运算

– 内填充key,用常量0x36和key做block size次的异或运算

– 对内填充key和message做hash,然后再用外填充和第一次hash结果再做hash

用以上的实现来避免长度扩展攻击。

php里内置的hmac实现,具体hash算法是可选择的,像aliyun采用hmac_sha1,就是用sha1的hash算法,

常用hash算法

DM5: MD5(RFC1321)是Rivest于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联(128bit),与MD4相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。已经被中国密码学专家王小云破解。

SHA1:由NISTNSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1设计时基于和MD4相同原理,并且模仿了该算法。SHA-1是由美国标准技术局(NIST)颁布的国家标准,是一种应用最为广泛的hash函数算法,也是目前最先进的加密技术,被政府部门和私营业主用来处理敏感的信息。而SHA-1基于MD5,MD5又基于MD4。已经被中国密码学专家王小云破解。比MD5强度大,输出是160bit,而MD5是128bit。

CRC:全称为CyclicRedundancyCheck,中文名称为循环冗余校验。它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制,比如TCP协议包头有CRC校验位。一般CRC计算结果都是32位的整数。

一将功成万骨枯

转眼之间在新的部门做新的业务已经超过一年的时间,中间经历了之前没有经历过的有趣的事儿。。

看到很多人陆续离职,或创业,或出走,有好有坏;

看到很多事儿,不是写代码那么单纯,人心是最复杂的东西;

技术好像长进不多,龌龊事经历不少;

公司大了,什么鸟儿都有,好多是你真没见过的,大开眼界;

结果最重要,真正的一将功成万骨枯;

唯KPI导向的产品注定是失败的产品。

本身写这点东西就是不成熟的表现。

移动应用中的IP就近接入方案

移动应用开发中,接入后台一般采用http协议,App客户端的表现就像网站的页面一样,和后台通信协议一般采用json或自定义。一般的web应用,在pc上浏览的比较多,用户访问的网络质量比较好,并且客户端是用户的浏览器,不会考虑也很难在接入速度上做优化。而移动应用中,有gprs、3g等移动网络环境,网络质量不会太乐观,为了iOS/Android客户端体验更流畅,会考虑在客户端和后台交互的过程中采用最优IP直连的方式,而非域名。

采用最优IP直连的优点

  1. 避免域名DNS解析
    域名解析还需要绕过吗?域名解析的耗时在移动网络中尤其慢,大概占整体耗时的1/3,有图有真相:
    image
  2. 防止域名被封
    三大运营商偶尔会封杀掉某个域名,或者直接劫持掉,不要怀疑运营商的奇葩之处。
  3. 地理位置访问最优、运营商访问最优
    计算距离用户地理位置最近的同一运营商的接入点。

实现方案

简化的架构如下:

image

 

方案的核心是IP库的解析,可以自建IP库,也可以使用现成的IP库(比较流行的纯真IP数据库),
image
客户端
1) 客户端首次访问使用域名访问后台
2) 后台收到客户端请求后,获取客户端接入的网关IP,根据网关IP在IP库中查询所对应的省份和运营商(依赖于IP库的准确度),
3) 将省份和运营商编码为一个AreaCode,并下发此AreaCode到客户端,
4) 后台根据AreaCode(表示接入的省份和运营商)选择同一省份同一运营商的接入点IP,

 

基于客户端上报的统计分析

无论移动客户端通过域名或者IP来访问,如何知道IP就近接入的策略是有效的?必须用数据说话。因此,客户端要建立完善的接入数据上报机制,给后台以坐接入数据分析和进一步优化调整的依据。涉及保密,只写出我认为有用的数据展现方式和上报项。上报可以有以下字段:

客户端接入时的网关IP(客户端自身可能无法获取,需要server协助获取)
server返回的就近码(包含运营商和地理位置信息)
本次访问的接入点IP
本次访问的接入点方式,域名、server返回的就近IP、内置默认IP
DNS解析时间(如果是域名访问)
DNS解析到的目的IP(如果是域名访问)
网络类型(需要综合判断,iOS和Android可能差别比较大),包括wifi、各运营商4g、各运营商3g、cmwap/cmnet、uniwap/uninet、ctwap/ctnet等
本次server请求的整体耗时
本次域名解析耗时(如果是域名访问)
客户端的基础信息,包括但吧

基于这些客户端的上报数据,可以得出很多不同类型的报表来分析接入情况:

使用域名和IP接入的速度对比
各省份和运营商的接入速度分析
接入速度区间分析
不同APN接入比例及速度对比

容错机制

 

接入点IP的更新和监控

 

干预策略

 

测速

我的读书之道

信息爆炸的时代,微博、微信、sns,几乎每天都会淹没在信息泥沼中,可是往往又茫茫然不知所谓。纷纷扰扰,何去何从?也来说说个人对读书的一些粗浅心得,很多借鉴自一些牛人总结的方法,也结合了自己的看法和经验。

渠道

看到一种绝妙的方法,顺藤摸瓜读好书。比如你喜欢某本书,就去找这本书作者看的书单,很可能里面有很多都是你会喜欢的书,文学类的尤其如此。这里推荐《暗时间》作者刘未鹏和《编程之美》作者邹欣创办的豆列,都是爱书之人。

http://book.douban.com/people/pongba/doulists

『只读经典』思考的技术与艺术(原“学会思考”)

数据挖掘与个性化推荐

http://www.douban.com/people/xinz/doulists/

有关创新的书

现代软件工程的教材和参考书

也可以关注业内比较有一定知名度、经常产出的大牛的blog,看看他们都看什么书,觉得感兴趣,就可以也看看。通过顺藤摸瓜的方式,能找到很多可读的书了,所谓站在巨人的肩膀上。

过滤

信息爆炸的时代,微博、sns都是泥沼。找到和你口味相近人、牛人、专家,这些人都起到很好的信息过滤作用,并且这些人都有一定嗅觉和灵敏度,你关注了这些人都能获得大部分的优质信息,就算有极少数消息不知道也无所谓。

工具

给你的kindle瘦身,不要让你的kindle成为藏书馆。kindle的阅读体验毋容置疑,kindle上保留10本以内的书就够了,随身携带,利用碎片化时间消磨在专注的阅读中,而不是陷入很快就失效的信息泥沼中,这样会绊住你的脚步。真爱生命,远离碎片。

能够让微博失色的东西,通常具有两个特质:纯粹和永恒。kindle是阅读器的不二之选,因为它专注阅读,连内置的浏览器都是残缺不全,唯独阅读做到了极致。相信你不会用kindle来刷豆瓣。纯粹的阅读。永恒的东西,就是经典。《TCP/IP协议》、《Unix网络编程》这些书,我相信在未来10年甚至更长一段时间内都是经典,都值得我们时时温习。当然,除了专业技术书,经典的文学作品,历史书,都可以放入kindle不时换换口味。在一个有阳光、恬静的午后,心思沉静,思路开阔,写起代码来思路都如尿崩。何况握着纯粹的阅读器,读着经典,瞬间,你会觉得彻底远离了泥沼,拥抱了永恒。

读和写

「知乎」诚可贵,「识之」价更高。

学到的只是,很大一部分会被忘却,而被忘记的只是的影子却保护着你避免陷入很多错觉。伊顿公学校长威廉•考利所言。因此,不用担心看过的内容记不住。

细节能否牢记不用太介意,特别是在同步Google的时代。读历史书籍,通感比细节更重要。这也是「知」和「识」的分野。

还有一种读叫「刍读」。反刍动物,比如像牛,未经充分咀嚼进入胃中半消化的食物都会返回嘴里再次咀嚼,并重新混合唾液进入胃中再次消化。书也一样,很多技术书读一遍可能就是囫囵吞枣,或者一知半解或者部分理解,过段时间重新温习,重新咀嚼理解消化,书中的营养才会完全吸收。

学而不思则罔。

看完一本觉得有意思的书,无论是读「通感」,还是「刍读」,都会有一点点的收获。blog是最好的方式,记下来,评论也好,总结也好,日积月累,再回头去看自己写的blog,还会有刍读的效果。写blog,贵在坚持,目标不用定的太大,比如我要一个星期写一遍,怎么怎么滴,完全不用。保持个一个月一篇就够了,一年下来起码10篇吧。写作、总结、书面表达能力、文字组织能力,2年下来就能有很明显的提高。

豆瓣读书是个好网站。

把自己想看的、正在看的、已经看过的书,在豆瓣读书上都记录下来吧,按照豆列分门别类。看完一本书了,不管是「通感」书还是「刍读」书,看完总会有个印象吧,写个书评,或者把kindle上的笔记导出来,导入豆瓣,或者Evernote尤其是「刍读」的书,笔记和心得也是一次次修改的,每「刍读」一次,更新一次笔记,我相信最终绝不会再有看完不记得细节或者没什么印象的感觉。

整理

有收集和积累,才有整理。

收集途径:

1)既然用到了kindle,那么评论和笔记,是优先收集和整理的对象。看完一本书,或者「刍读」后,肯定有不少产出了。某个晚上,思绪宁静,放着喜欢的音乐,正如我现在,敲打着键盘,一篇blog成形出炉,跟写代码一样惬意和成就。

2)看到一篇好文?马上在浏览器里用「剪藏」插件保存到Evernote里吧。随手打个标签,周期性的整理,每整理一次,都用自己的文字总结下来。周期建议为一个月。

3)事后阅读类的App或浏览器插件。可以在手机或者Kindle上事后阅读方法自行Google。不过,别让事后阅读没了以后。

后台服务部署拆分原则

之前的《后台服务优化原则》中提到后台service的一些拆分原则,也就是单个服务内对外接口拆分的一些原则。其实,在服务部署时,也会有一些不同的部署策略,来实现另一种意义上的拆分。最重要的作用在于「防火隔离」。

按请求来源渠道拆分

不同的请求来源,请求量必然不太一致。不同来源的请求被分发到各自的一组机器上,起到相互隔离的作用,服务出现问题时,只影响特定来源请求;某个来源渠道请求量上涨或者有问题时,所影响的范围也被限制。

按不同地区来拆分

思路同按请求来源渠道拆分。

按不同号段来拆分

微信的部署是按每千万的用户划分到一个set来承载。每个set是一套完整的服务(包括接入服务、逻辑服务、存储等),大概2、3百台机器(2012年的数据),不仅利于「防火隔离」,更利于扩容。

按不同运营商来拆分

按照不同的运营商来拆分部署时,不仅起到「防火隔离」的作用,也减少由于跨网络请求导致速度慢的情况,在天朝,都知道各运营商互联互通始终是个很现实的问题。

Kindle Paperwhite二代,我的新玩具

        日本亚马逊海淘,相当的给力,周三日亚下单,激活Prime账号,周四发货到转运公司,周五转运公司EMS发到国内,下一周的周二就收到货。简直神速!没被税!
中间被砍单10次以上,之前jshoppers一直被砍单,无奈改为不知名刚成立的华人开的转运公司jpgoodbuy,也是修改地址数次才下单成功,实在不容易。9980日元+1400日元ems+手续费共670左右人民币。
看书更专注不伤眼,每天在床上临睡前用New iPad看书时眼睛总会流泪,用了Kindle眼睛舒服多了。不到三天,利用上下班车上碎片时间,看了《你一定爱读的极简欧洲史》,体验非常棒!

IMAG0243_2745118

《你一定爱读的极简欧洲史》其实不简单

你一定爱读的极简欧洲史

       《一定爱读的极简欧洲史》,在拿到在日本亚马逊海淘的kindle paperwhite后,kpw上看完的第一本电子书,kindle阅读的体验非常好,很轻便对眼睛很好,之前用iPad看文字内容时间久了总会眼睛流泪,用kindle完全不会,同步功能也非常强大。
  极简欧洲史,跟我在上初高中时学习到的历史教科书完全不一样,并且也和我看过的其他国人写的史书也不一样。教科书上的历史,印象中只有死记硬背的一个个离散的发生在特定年份的历史事件和做出某某成就的历史人物。这本书,就像故事一样,没有那么多年份和事件,几乎都是写了作者对历史的理解,以及历史背后的特定时期的文化和出现这种文化的背景。当然,历史和地理也是分不开的。
  当然,既然是极简的欧洲史,读完这本书之后,脑袋里留的也是一个大概的欧洲史的轮廓。不过,对一个普通读者来说,足以。
  唯一的遗憾在于,读这本书时,都是在kindle上利于碎片时间读完,正如作者在书中提到的,最好手里拿着一张欧洲地图。

《淘宝技术这十年》书评

淘宝技术这十年

  还是在kindle上看完了这本书,因为没有kindle电子版,网上流传的pdf版本。至于原因,首先原谅个人版权意识不高,并且没太尊重作者的劳动,当然还是更重要的原因,定价确实高了,并且看完之后也就看完了,就当一本故事书了。非常适合看电子版(意味着没有实体书价值)。
  另一个让我困惑的原因是,写书评打标签时,完全不知道这本书能被我归类到哪一种,如果是技术类的,几乎每本都能有一个很清晰的分类,比如Java、架构、大数据、NoSQL等等。
  其实作者写的是在淘宝这10年中个人的经历,只不过好像是写的淘宝10年的技术演变,还会有一些产品和八卦人物之类,当然大牛向来都是被我等屌丝程序员所膜拜和敬仰的。
  嗯,就是一本跟技术有关的某个人的成长经历的,故事书。。
  不过,从书名来看,我还是把这本书的标签归为【历史】。

后台服务优化原则

目前在做一个Android应用分发的业务,涉及N多部门之间的利益纠葛和势力分配。后台服务在刚开始迭代非常快,很多业务逻辑集中在某个后台service中。

每个后台服务都是一个c++进程,提供rpc接口给调用方。所有请求都会通过网络接收后,在队列中被分发到多个业务处理线程中被统一处理,业务线程通常设置为8或16(cpu核数*1~2)。业务线程会统一处理每个接口的请求,而每个接口实现的复杂度、处理时间、调用量都会不同,并且在接口中如果需要调用其他rpc服务还会涉及网络调用会阻塞线程处理(如果不阻塞向后端的调用需要异步处理),这样每个请求在线程中被处理的时间都不尽相同,为了使线程处理更有高效,考虑如下拆分原则:

一、轻重分离

所谓轻重是指服务所提供对外rpc接口的实现逻辑轻重,分别把业务逻辑比较重的接口和比较轻的接口,拆分开来,逻辑轻的多数接口组成一个服务,逻辑重的少数接口组成一个服务。

二、快慢分离

服务的接口耗时有快有慢,可以把耗时大的接口单独拆分到新服务中,异步实现避免阻塞,不影响其他耗时非常短的接口。

三、多少分离

每个接口的调用量不同,可以把被调用次数比较少或者比较多的接口单独拆分,放在新服务中。

四、读写分离

读写分离其实以上几种拆分方式的综合,一般情况下,读写操作的耗时、调用量都会有不少差别,可以把读的接口和写的接口,拆分到不同的服务,让单个服务的处理更顺畅。

分久必合,合久必分。后台服务随着业务发展,根据需要势必会不停合并或拆分,可能是因为处理瓶颈,可能是优化内部实现,可能是使调用方更合理。拆分时需要按照上述原则来拆分,反之,有些接口需要合并时以上原则同样适用。

没有人能随随便便成功

7月1号的时候,一帮人浩浩荡荡去杭州出差为一个新的产品做封闭开发。杭州分公司是tx在2011年全资收购的一家公司,目前做pc版的Android手机软件助手类软件,类似豌豆荚、360手机助手等。

这个公司位置虽然比较偏远,几乎每人都开车上班,这个公司的人都好有钱的,应该被收购时分了不少钱。当时我们都这么揣测着。

昨天下午去跑步,恰逢这个分公司四位创始人之一也去跑步,虽然去杭州时见过1、2次,可对方对我们也没印象,毕竟是干活的程序员屌丝。

边慢跑边聊,聊了些技术问题,无意间提起些当年他们创业时的事儿和过程,有段时间最长有4个月没有钱发工资,几个人规模时每个月也要4、5w的开支,10个人左右时也9w左右了,每年近百万投入,人力成本还是占比最大。

4个月没有收入的最困难时期,都还坚持了下来,确实听不容易,所以才有了后来的投资以及收购,并且都是投资人主动找上门来的。当然当时豌豆荚也刚开始做,市场环境虽然以及明朗但还是蓝海,最重要的还是坚持信念和创业初期的各种艰辛啊。。