本文转载至 http://www.cnblogs.com/Lifehacker/p/mobile_game_protocol_encrypt_and_authentication.html
这一块之前一直感兴趣,终于在2月份争取到机会去做这一块的工作。前辈给我留下了一个鉴权的框架:
- 客户端连接服务器
- 服务器将随机数发给客户端
- 客户端用客户端私钥加密,发回到服务器
- 服务器端用客户端公钥解开密文,比对解开的随机数是否与原来的一致
- 如果一致,则客户端发送随机数到服务器,服务器用服务器端私钥加密,将密文发送到客户端;同时,产生新的随机数,用于稍后对会话进行rc4加密,并将这个随机数以客户端公钥加密,发送到客户端。
- 客户端用服务器端公钥解开密钥,比对随机数和自己发的是否相同,相同的话则用客户端私钥解开下一个包,取出用于rc4加密的key密文
- 至此,双方身份验证完成,会话先进行压缩,再通过rc4算法进行加密
在这里,私钥充当了一个身份的象征,只要拥有私钥,就认为对方是授信客户端。可能有朋友会问,如果客户端被破解怎么办?我觉得安全专家道哥有个观点很好,“安全的本质是信任的问题。设计任何安全方案,最终都必须要有一个东西是「假设可以信任的」,只是看这个「可信任」的东西被攻击成功的概率大小。如果不这么做,则做不出任何的安全方案。”所以,考虑协议安全的时候,我们只能选择相信客户端密钥被安全的保管着。
回头再看看这个方案,这里用到了私钥进行加密。熟悉ssh的同学应该会联想到其挑战过程,ssh服务器是用客户端公钥对随机数进行加密,再发送到客户端的。公钥加密和私钥加密的区别是,在明文相同的情况下,公钥加密出来的密文每次都不一样,而私钥加密出来的密文是每次都相同的。示例代码可以参见: https://github.com/spin6lock/rsa_encrypt_and_decrypt_in_c 密文和明文总是一一映射,容易被碰撞攻击,进而绕过加密过程。因此,私钥加密多用于身份验证,比如电子邮件的数字签名,首先用md5对邮件明文进行信息摘要,然后用私钥进行加密,公钥是公开的,保证任何看到这封邮件的人都可以进行解密,获取md5信息进行验证,确保邮件没有被纂改。
于是,我花了一周左右的时间修改了验证流程。新的验证流程如下:
- 客户端连接服务器
- 服务器用客户端公钥加密随机数,发给客户端
- 客户端用客户端私钥解密,发回服务器
- 服务器对比随机数,不一样的话就断开连接
- 客户端用服务器端公钥加密随机数,发送到服务器
- 服务器用私钥解密,发送回客户端
- 客户端验证通过
- 服务器用客户端公钥加密rc4会话所用密钥,发送到客户端
- 客户端用公钥解开,接下来在rc4加密下上传