«

»

16 2017

在JS与PHP之间使用CryptoJS和mcrypt进行加密传输

虽然HTTPS的成本已经大幅度下降了,但是仍然会有一些需要再加密一层的传输需求。

本文将实现在客户端和服务端之间,使用CryptoJS和mcrypt进行加密传输的方法。

其实个人也没有搞明白所有细节,只不过是调通了 PHP MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC 与 JS AES ZeroPadding 之间的加解密通信而已。

用途,大概就是在一些环境下,在无法依赖 https 的情况下,需要传输一些需要加密的数据时使用。之前看了腾讯网页登录的方法,账号+密码+验证码 做多次哈希后传输,也可以保证无法破解和回放攻击。不过既然有AES这种高级加密方法,何尝不使用一下呢。

准备环境

  • 客户端:支持JS并可以发起Ajax请求即可,CryptoJS库
  • 服务端:HTTP服务,PHP,必须安装 php-mcrypt

建议

网络中传输的数据,使用base64编码之后传输

实现 PHP加密 —- JS解密

PHP代码:

得到:F0QOnmU79TFx6IhFLsUnfSvwJvmKP5uzU2h5jJH+MPY=

JS代码:


至此完成 PHP端加密 —- JS端解密 的过程。


实现 JS加密 —- PHP解密

JS代码

得到:F0QOnmU79TFx6IhFLsUnfSvwJvmKP5uzU2h5jJH+MPY=

PHP代码


至此完成 JS端加密 —- PHP端解密 的过程。


注意事项

1. JS与PHP的加密算法

严格地说,AES和Rijndael加密法并不完全一样,所以CryptoJS支持的AES与PHP中MCRYPT的RIJNDAEL也不是完全相同的。

PHP的Rijndael可以手动强制key长度,并且在php 5.4之前还会自动补齐。

JS的CryptoJS中,key的长度是根据传入的key自动判断的。

2. 关于’\0′

PHP 5.6 之后,不再接受无效长度的 key 和 iv 参数。 如果参数长度无效,则 mcrypt_decrypt() 函数会产生警告并且返回 FALSE。

对于PHP 5.6 之前版本中,对于长度不足的密钥和初始向量会在其后自动补齐 ‘\0’ 使其达到有效长度。

所以对于已经使用PHP7版本的我们,现在要手动补齐’\0’了。因为MCRYPT_RIJNDAEL_128的key长度和iv长度都是16,所以例子里偷懒了,没有根据加密方法做判断,写死了16。

而在JS的CryptoJS中,完全不会自动补齐,我们每次都需要检查 key 和 iv 的长度,并手动补齐。

代码和示例

暂无

参考资料

CryptoJS: https://code.google.com/archive/p/crypto-js/

RIJNDAEL: 维基百科Rijndael加密法

3 comments

  1. 萃香西瓜

    其实我对于基于js的加解密用途,感觉比较困惑
    毕竟js都是明文的,如果使用对称加密(比如文中AES),秘钥和算法都是明文公开的甚至直接写到js文件里的
    如果使用非对称加密(比如RSA),只要监听http也可以做到还原整个场景

    这种情况下只要外部想攻击,基本上没有门槛可言。不过对于扫描类型的撒网攻击,或许可以保护自己不会在第一轮就立马被人随便攻破。
    所以比较好奇CryptoJS的使用场景

    1. 石樱灯笼

      加密并不能确保安全,加密永远只是在一定程度上增加破解难度而已。对于像https这种情况,只不过是引入了一个第三方认证机构,来确保没有中间人攻击。在没有第三方认证机构或者第三方认证机构无赖的情况下(cnnic和wosign),https也只不过是装饰品。

      CryptoJS在网站网页上,因为双端秘钥和算法都是可见的,所以无法抵抗劫持级别的攻击,但对于网络上的简单连接劫持是非常有效的。网络上很多流量劫持都是没有动作分析功能的,无法自动分析你的算法文件和秘钥文件,而人工分析一般只有针对性的攻击才会做,需要看代码,确认秘钥和算法,有人力成本。如果进一步做JS代码混淆,想要破解就不是很方便了。

      虽然我这次研究这个东西只是为了利用iv防止回放攻击。

      另外对于客户端应用,CryptoJS将不再是从网络传输,而是与安装程序一同分发,代码将不透明,这是目前客户端加密的主要用途。

  2. 姜辰

    这样的加密解密的过程,对服务器的消耗?
    门外汉,还是不做评论仅仅膜拜比较好。

发表评论

电子邮件地址不会被公开。 必填项已用*标注