谈谈微信公众号开发中的信息加密(下)

上一篇说了微信消息的加密。但是微信公众号开发中需要密码学的地方并不止这些。

试想这样一个场景:用户通过 URL 查询所在位置附近的业余无线电中继台(或者饭店、旅馆、加油站),需要在 GET 报文中把自己的精确地理坐标(精确到10米吧)以 query string 的形式发送给服务器,例如这样:

http://repeater.applinzi.com/search/?lat=33.1234&lng=120.4321

精确的地理坐标属于较为敏感的用户信息,如果这样直接展示在 URL 里,那之前给消息加密不就成了掩耳盗铃?所以,需要加密(encryption)

我需要确保地理坐标在传输过程中没有被篡改,即完整性(integrity)

同时,我不希望用户把上面的 URL 地址改吧改吧自己编制一条 GET 报文来套取数据,所有合法的查询 URL 只能由我自己生成,这就需要认证(authentication)

某些场合,比如订单系统,还需要加密系统能抵御重放攻击(reply attack),然而我并不在乎用户点击同一条 URL 多次,所以这不在我的设计需求之内。

虽然 PyCrypto 分别提供了 Encryption 和 Authentication 算法,但是却并没有提供 Authenticated Encryption 的完整实现,需要用户自己把二者结合起来。结合方法有三种:

  • Encrypt-and-MAC,把明文分别加密和认证,然而认证算法是不一定能保证信息的私密性的,所以可能会导致明文信息泄露,不应该使用。
  • Encrypt-then-MAC,先把明文加密,然后对密文进行认证。推荐使用。
  • MAC-then-Encrypt,先对明文进行认证,然后把密文和签名一起进行加密。在某些情况下能保证安全,某些情况下不能。谨慎使用(其实就是别用)。

我还是使用了较为稳妥的 Encrypt-then-MAC。代码如下:

# utils/authencrypt.py

import base64
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Hash import HMAC


# 加密/认证算法只接受字符串,如果是unicode需要先转换
def to_str(text):
    if isinstance(text, unicode):
        text = text.encode('utf-8')
    return text


class AuthenticationError(Exception): pass


class AESCipher(object):
    def __init__(self, key):
        self.key = key

    def encrypt(self, plaintext):
        plaintext = to_str(plaintext)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CFB, iv)
        return base64.b64encode(iv+cipher.encrypt(plaintext))

    def decrypt(self, ciphertext):
        ciphertext = base64.b64decode(ciphertext)
        iv = ciphertext[:16]
        cipher = AES.new(self.key, AES.MODE_CFB, iv)
        return cipher.decrypt(ciphertext[16:]).decode('utf-8')


class Authen(object):
    def __init__(self, key):
        self.key = to_str(key)

    def get_signature(self, text):
        text = to_str(text)
        hmac = HMAC.new(self.key)
        hmac.update(text)
        return base64.b64encode(hmac.digest())

    def authenticated(self, text, signature):
        return self.get_signature(text) == signature


class AE(object):
    def __init__(self, key):
        self.aes = AESCipher(key)
        self.authen = Authen(key)

    def encrypt(self, plaintext):
        ciphertext = self.aes.encrypt(plaintext)
        signature = self.authen.get_signature(ciphertext)
        return ciphertext, signature

    def decrypt(self, ciphertext, signature):
        if not self.authen.authenticated(ciphertext, signature):
            raise AuthenticationError
        return self.aes.decrypt(ciphertext)

下面是使用范例:

>>> from utils.authencrypt import AE
>>> key='1234567890zxcvbn'
>>> ae=AE(key)
>>> plain='attack at dawn'
>>> cipher, signature=ae.encrypt(plain)
>>> cipher
'C8qh7rZ0lKXvenjG4JOOHRnuO0MiWtQyNXfsZV2G'
>>> signature
'Hpx0c5zpe7GUQPczePjF7g=='
>>> decrypted=ae.decrypt(cipher, signature)
>>> decrypted
u'attack at dawn'

这样,文章开头的 URL 被转化为如下的形式:

http://repeater.applinzi.com/search/?cipher=C8qh7rZ0lKXvenjG4JOOHRnuO0MiWtQyNXfsZV2G&signature=Hpx0c5zpe7GUQPczePjF7g==

服务器接收到 GET 请求后,先验证签名,签名正确再解密,并利用解析出的地理坐标返回相应的结果。注意,不管其间出现了怎样的异常,如签名错误、解析不出坐标还是解析出的坐标没有对应的结果,都应该返回统一的错误提示,以防止攻击。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容