PHP-RSA加密跨域通讯实战
AUTH:PHILO EMAIL:lijianying12 at gmail.com
基于POST GET 的http通讯虽然非常成熟,但是很容易被人监听。 并且如果使用跨域jsonp的通讯很容易在历史记录中发现通讯网址以及参数。为了克服这些问题, 并且降低服务器成本,我们没有使用SSL而使用 RSA加密。文章中的php加密解密 JS的加密解密 互相加密解密 都能验证通过。
其中PHP依赖常见的OPENSSL LIB 。 JS依赖 jsencrypt。
我们使用jsonp get RSA加密通讯好处如下:
- 前后分离适合cdn加速。
- 安全跨域更适合松散结构的网站。
- 不用去买ssl证书了。
首先要生成密匙对
1 |
|
JS的RSA加密流程
下载最新版本请移步到github:jsencrypt 代码在目录BIN下面是否用压缩的根据情况决定。
生成KEY
1 |
|
客户端加密场景:
1 |
|
客户端解密场景:
1 |
|
但是虽然写到了这里,加密方面还是不够用,因为1024长度的RSA加密最多只能加密长度为117的字符串。而URL长度最多为4k因此这里我们要让加密长度达到2691以达到能用的程度。
那么这种加密长度大概能容纳多少数据呢? 我们借助json-generator来帮忙生成JSON
1 |
|
表单json能达到这么长已经是很极端的情况了。因此这种方法绝对是够用的。
长表单内容加解密方法:
1 |
|
##########NextPage[title=]##########
PHP的RSA加密
php加密解密类
首先要检查phpinfo里面有没有openssl支持
1 |
|
密匙文件位置问题,是放到访问接口的附近就可以了如果是CI的话就放到index.php旁边就行了。 但是要注意一点,一定要做访问设置,不然key会暴出来的,那时候信息一旦截获就惨了。
类的使用
1 |
|
长数据加密解密
1 |
|
JSONP 跨域通讯
我们经过千辛万苦经过加密终于能做到通讯安全了。 当然我们的下一步是通过JSONP 的get通讯来实现跨域通讯啦。 经过测试:我们的JS中最长的Case url长度是3956 在加上跨域url callbac参数,经过测试正好差20到4095 (一般的URI长度限制为4K)
1 |
|
1 |
|
PHP代码是CI框架controler中的部分代码 并且经过了必要的裁剪。 更加细节的参数都放到GET里面就可以了。 处理之后按照上面的形式处理返回值就ok 如果你配置成功了,你将会在网页的控制台上看到自己动态的, 或者像我一样静态的控制台输出。 如果要是想获取数据到网页的话还是要借助回调函数来实现
JSONP跨域获取通讯结果
请看下面代码:
客户端代码
1 |
|
服务器端代码
1 |
|
此次通讯的结果会在jcp当中调用执行,并且返回的内容会记录到 global 变量当中。
实战
从上文中,我们已经找到了整个加密过程方法了,但是距离实战还是有一定距离的。 首先我们实战的话需要克服接口比较少,功能比较多,单个接口维护用时比较长的问题。
为了解决上面的问题我们做出如下设计。
客户端方面:
设计一个通讯类:只管跟服务器通讯。别的业务什么都不管。
1 |
|
在上面代码中请注意,RSA加密过后的字符串当中有一个非法字符+要转换成其他合法字符发送到服务器才可以。 不然参数会错误。 等传输到服务器中自己转换回来在解密就好了。
服务器端方面:
首先我们接收到消息之后要对消息进行解密,之后根据报文内容选择服务器上的功能。然后把其他参数输入到业务类中执行即可。 因此我们使用了命令模式来实现单一接口的丰富业务功能。 其他的我们需要对CI框架的配置进行调整: 首先global config里面需要调整 $config[‘global_xss_filtering’] = FALSE; 因为如果传输过来的报文解密不了就直接抛弃不进行处理(防止CC攻击第一层)这样就从url上防止了攻击的可能性。 当然我们还是没有完全避免注入风险这时我们就需要在业务类里面调用安全模块:
1 |
|
来实现第二层的XSS攻击。这是服务器端设计主要需要说的位置。
服务器获取数据处理全过程
- 从get接口获得参数c的加密数据
- 对数据进行RSA解密。
- 判断数据包时间戳。如果超时直接抛弃(防止从浏览器记录中直接发送request到服务器,下面是安全方面的说明)
- 首先如果不修改数据只修改时间戳不可能从截获的数据报文中实现,因为需要重新加密,如果想得到内容需要服务器上的privatekey解密保证安全
- 如果数据包截获直接发送数据包在超时范围内直接获取数据包内容,也不能实现攻击,因为在客户端有临时RSA密匙对生成并且在发送的时候会同时发送publickey 给服务器做session的存储内容并且伪装客户的客户端没有privatekey所以获取任何关于登陆之后的消息根本无法解析。
- 对解密后的数据进行xss检查
- 解析报文中需要调用什么功能直接调用反射得到业务类的实例
- 调度业务类,并且把得到的参数赋值给业务执行函数的参数。
服务器处理数据过程只跟业务有关
服务器返回数据全过程
- 业务处理完成之后针对每一个用户的登陆情况对返回值进行加密。
- response
以上业务涉及的部分代码(给出的代码未涉及以上说的安全部分。)
1 |
|
1 |
|
以下是配合业务进行的工具函数:
1 |
|
以下是实现业务的例子:
1 |
|
通过以上基本方法,我们可以实现,只要业务继承我们声明的接口就可以开始写业务了。 别的什么都不用管,专注于业务即可,其他的安全、IO等问题都已经一并解决。 并且每一个业务都进行了rsa加密xss攻击过滤伪造数据包攻击。 以及在response加密只能是固定客户端才能看到报文内容的全过程。 但是一定要注意一点,注册这个业务后面要嵌套登陆进行,不然看不到返回值。
数据包必须包含的要素:
- acton (业务名)
- req_time (请求时间)
- public_key (如果是注册跟登陆时候需要提交临时公匙)
总结
因为时间仓促所以只能写到这里了。 如果您发现了我文章中的bug欢迎发email批评指正。非常感谢! 同时本方案也会成为我们开源社区linux52.com后台系统中的接口设计方案。 当然我们社区所有维护的文档都会进行反复验证,如果出问题我们会及时更新。 以维护文档的正确性。 点击=这=里=查看文档最新版本。
关键词
php js rsa get jsonp 跨域 安全