阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

PHP-RSA加密跨域通讯实战

94次阅读
没有评论

共计 17151 个字符,预计需要花费 43 分钟才能阅读完成。

AUTH:PHILO EMAIL:lijianying12 at gmail.com

基于 POST GET 的 http 通讯虽然非常成熟,但是很容易被人监听。并且如果使用跨域 jsonp 的通讯很容易在历史记录中发现通讯网址以及参数。为了克服这些问题,并且降低服务器成本,我们没有使用 SSL 而使用 RSA 加密。文章中的 php 加密解密 JS 的加密解密 互相加密解密 都能验证通过。

其中 PHP 依赖常见的 OPENSSL LIB。JS 依赖 jsencrypt。

我们使用 jsonp get RSA 加密通讯好处如下:

  1. 前后分离适合 cdn 加速。
  2. 安全跨域更适合松散结构的网站。
  3. 不用去买 ssl 证书了。

PHP-RSA 加密跨域通讯实战

首先要生成密匙对

  1. openssl genrsa 1024>private.key
  2. openssl rsa inprivate.key pubout >public.key

JS 的 RSA 加密流程

下载最新版本请移步到 github:jsencrypt 代码在目录 BIN 下面是否用压缩的根据情况决定。

生成 KEY

  1. var keySize =1024;// 加密强度
  2. var crypt =newJSEncrypt({default_key_size: keySize});//RSA 操作对象
  3. // 方法 1 (async)
  4. crypt.getKey(function(){
  5. crypt.getPrivateKey();
  6. crypt.getPublicKey();
  7. });
  8. // 方法 2:
  9. crypt.getKey();
  10. crypt.getPrivateKey();
  11. crypt.getPublicKey();

客户端加密场景:

  1. var crypt1 =newJSEncrypt();// 新建 rsa 对象
  2. var publickey =‘\
  3. —–BEGIN PUBLIC KEY—–\
  4. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3N8LJFqlsa6loCgFpgZVMr/Sx\
  5. DMQY7pr0euNQfh2g+UVPbB0MGhoc7nWL0FQhCgDedbjQw/nGFStFx7W1+0o1oRTY\
  6. u5ebNVivZSobraUv7LJvwT8O66Zs8cxbKLqQ/nE/WwJvXomSIckH6R8iOUO8/QT9\
  7. kv6/L0Uma3qA07pmDQIDAQAB\
  8. —–END PUBLIC KEY—–\
  9. ;
  10. crypt1.setPublicKey(publickey );// 添加来自服务端的 publickey
  11. crypt1.encrypt(‘abc’);// 返回值为加密后的结果

客户端解密场景:

  1. var privatekey =‘—–BEGIN RSA PRIVATE KEY—–\
  2. MIICXQIBAAKBgQC3N8LJFqlsa6loCgFpgZVMr/SxDMQY7pr0euNQfh2g+UVPbB0M\
  3. Ghoc7nWL0FQhCgDedbjQw/nGFStFx7W1+0o1oRTYu5ebNVivZSobraUv7LJvwT8O\
  4. 66Zs8cxbKLqQ/nE/WwJvXomSIckH6R8iOUO8/QT9kv6/L0Uma3qA07pmDQIDAQAB\
  5. AoGBAKba3UWModbfZXQeSJLxNCqWw9zJp3ydL/keQQ35DLqgyIJAD2QKEWXvtJUT\
  6. sMo19fyicSGOmFXQyYvPCKkmpLkOMAj1XaNpSMtSrcMx+gC01PO6Ey9rsUxW1g3u\
  7. fpqbEk9E3a5AtCS0I61nbUpRL6rqMtR5o2wcNR3TLtJt7pjxAkEA7hlFJKU1zWGp\
  8. OvvkJDnHc2NOCEJoGjqCR9wwv96+/xAykl2laI6WvEbbhjoO0+8+d17oigjhneS5\
  9. 2UKFcfqw7wJBAMT+MCQ5TYLQlvjrBaDMqOdLsqtaDE6CpkrgwV820QMvHOo3R4Xd\
  10. uSbrA2tOr9t2/x+FzF971lRGdPFIch9UYMMCQQCZtO6SDaWCBP3++gX57OL5dq41\
  11. XsldxU+9nERMWTvr5UUAgDv8F7Dvsr6dFHXmE5i77yUnlzwvdi0UOIF1Z2U5AkBV\
  12. wyRKYPgx34Ya0JcerntKV1Zt60I4XADx0G/feAn/DN/VyENHMISPQPm4GgXN0jy4\
  13. CJQ1bcCd6B65fQTSRvXpAkA2Vv5yXzeKDls/AyxHEoros/VYftVc1HOFC++q13Rw\
  14. NH2rnlRT8FMTFEqL9MYRqvvYAFf5VmH0M1Nx5t4LRN+l\
  15. —–END RSA PRIVATE KEY—–\
  16. ;
  17. var crypt2 =newJSEncrypt();// 新建加密对象
  18. crypt2.setPrivateKey(privatekey);// 给加密对象设置 privatekey
  19. crypt2.getPublicKey();//Tip 我们是不需要存储 publickey 的直接用 private 能得到 publickey
  20. crypt2.decrypt(“MeUqWB5LwTh8crzPqbZtEtKuZxYvPWH9CTCChK1qoBzIgIXGPCdzNMbiH0cCYHl5qWSERIDOgDIgv4dXsIMjEJ5q0cp/qNQYHM5va0iw0UvKvQB1E8aWtY2nFEPy4F+ArQ0Mj/ijr/CntEP1jHKC3WU9nu2kYrBIBnbj14Bs+kI=”);// 调用解密方法

但是虽然写到了这里,加密方面还是不够用,因为 1024 长度的 RSA 加密最多只能加密长度为 117 的字符串。而 URL 长度最多为 4k 因此这里我们要让加密长度达到 2691 以达到能用的程度。

那么这种加密长度大概能容纳多少数据呢?我们借助 json-generator 来帮忙生成 JSON

  1. sdata =[
  2. {
  3. “_id”:“542f9ac2359c7d881bc0298e”,
  4. “index”:0,
  5. “guid”:“db1dacc1-b870-4e3c-bc1a-80dfd9506610”,
  6. “isActive”:false,
  7. “balance”:“$1,570.15”,
  8. “picture”:“http://placehold.it/32×32”,
  9. “age”:36,
  10. “eyeColor”:“blue”,
  11. “name”:“Effie Barr”,
  12. “gender”:“female”,
  13. “company”:“ZORK”,
  14. “email”:“effiebarr@zork.com”,
  15. “phone”:“+1 (802) 574-3379”,
  16. “address”:“951 Cortelyou Road, Wikieup, Colorado, 4694”,
  17. “about”:“Sunt reprehenderit do laboris velit qui elit duis velit qui. Nostrud sit eiusmod cillum exercitation veniam ad sint irure cupidatat sunt consectetur magna. Amet nisi velit laboris amet officia et velit nisi nostrud ipsum. Cupidatat et fugiat esse minim occaecat cillum enim exercitation laboris velit nisi est enim aute. Enim do pariatur\r\n”,
  18. “registered”:“2014-05-08T15:26:35 -08:00”,
  19. “latitude”:48.576424,
  20. “longitude”:146.634137,
  21. “tags”:[
  22. “esse”,
  23. “proident”,
  24. “quis”,
  25. “consectetur”,
  26. “magna”,
  27. “tempor”,
  28. “anim”
  29. ],
  30. “friends”:[
  31. {
  32. “id”:0,
  33. “name”:“Trisha Cannon”
  34. },
  35. {
  36. “id”:1,
  37. “name”:“Todd Bullock”
  38. },
  39. {
  40. “id”:2,
  41. “name”:“Eileen Drake”
  42. },
  43. {
  44. “id”:3,
  45. “name”:“Ferrell Kelly”
  46. },
  47. {
  48. “id”:4,
  49. “name”:“Fischer Blankenship”
  50. },
  51. {
  52. “id”:5,
  53. “name”:“Morales Mann”
  54. },
  55. {
  56. “id”:6,
  57. “name”:“Brandie Pittman”
  58. },
  59. {
  60. “id”:7,
  61. “name”:“Virgie Kerr”
  62. }
  63. ],
  64. “greeting”:“Hello, Effie Barr! You have 1 unread messages.”,
  65. “favoriteFruit”:“apple”
  66. },
  67. {
  68. “_id”:“542f9ac21c260d03e763a4f2”,
  69. “index”:1,
  70. “guid”:“9e3a3d8a-26f8-46b7-aca0-336a194808b1”,
  71. “isActive”:true,
  72. “balance”:“$3,617.89”,
  73. “picture”:“http://placehold.it/32×32”,
  74. “age”:31,
  75. “eyeColor”:“brown”,
  76. “name”:“Butler Best”,
  77. “gender”:“male”,
  78. “company”:“SPORTAN”,
  79. “email”:“butlerbest@sportan.com”,
  80. “phone”:“+1 (905) 428-3046”,
  81. “address”:“798 Joval Court, Wanship, Delaware, 8974”,
  82. “about”:“Nostrud occaecat id sunt pariatur ad nisi do veniam sit officia non consequat amet fugiat. Est eiusmod labore ut cillum qui eu elit ut eiusmod exercitation. Ut anim nostrud eiusmod voluptate tempor proident id do pariatur. In Lorem ullamco ea irure adipisicing. Quis est dolor ex commodo aliqua nisi elit sit elit anim fugiat sunt amet. Enim consequat ipsum occaecat ipsum tempor deserunt dolor veniam nostrud. Anim cillum ullamco cupidatat aute velit fugiat sit enim in amet anim mollit dolor eiusmod.\r\n”,
  83. “registered”:“2014-08-02T06:15:44 -08:00”,
  84. “latitude”:20.529765,
  85. “longitude”:2.396578,
  86. “tags”:[
  87. “consequat”,
  88. “enim”,
  89. “magna”,
  90. “sunt”,
  91. “Lorem”,
  92. “quis”,
  93. “commodo”
  94. ],
  95. “friends”:[
  96. {
  97. “id”:0,
  98. “name”:“Kenya Rice”
  99. },
  100. {
  101. “id”:1,
  102. “name”:“Hale Knowles”
  103. },
  104. {
  105. “id”:2,
  106. “name”:“Michael Stephens”
  107. },
  108. {
  109. “id”:3,
  110. “name”:“Holder Bailey”
  111. },
  112. {
  113. “id”:4,
  114. “name”:“Garner Luna”
  115. },
  116. {
  117. “id”:5,
  118. “name”:“Alyce Sawyer”
  119. },
  120. {
  121. “id”:6,
  122. “name”:“Rivas Owens”
  123. },
  124. {
  125. “id”:7,
  126. “name”:“Jan Petersen”
  127. }
  128. ],
  129. “greeting”:“Hello, Butler Best! You have 8 unread messages.”,
  130. “favoriteFruit”:“banana”
  131. }
  132. ] 

表单 json 能达到这么长已经是很极端的情况了。因此这种方法绝对是够用的。

长表单内容加解密方法:

  1. function encrypt_data(publickey,data)
  2. {
  3. if(data.length>2691){return;}// length limit
  4. var crypt =newJSEncrypt();
  5. crypt.setPublicKey(publickey);
  6. crypt_res =“”;
  7. for(var index=0; index <(data.length data.length%117)/117+1; index++)
  8. {
  9. var subdata = data.substr(index *117,117);
  10. crypt_res += crypt.encrypt(subdata);
  11. }
  12. return crypt_res;
  13. }
  14. function decrypt_data(privatekey,data)
  15. {
  16. var crypt =newJSEncrypt();
  17. crypt.setPrivateKey(privatekey);
  18. datas=data.split(‘=’);
  19. var decrypt_res=“”;
  20. datas.forEach(function(item)
  21. {
  22. if(item!=“”){de_res += crypt.decrypt(item);}
  23. });
  24. return decrypt_res;
  25. }

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2014-10/107881p2.htm

PHP 的 RSA 加密

php 加密解密类

首先要检查 phpinfo 里面有没有 openssl 支持

  1. class mycrypt {
  2.  
  3. public $pubkey;
  4. public $privkey;
  5.  
  6. function __construct(){
  7. $this->pubkey = file_get_contents(‘./public.key’);
  8. $this->privkey = file_get_contents(‘./private.key’);
  9. }
  10.  
  11. publicfunction encrypt($data){
  12. if(openssl_public_encrypt($data, $encrypted, $this->pubkey))
  13. $data = base64_encode($encrypted);
  14. else
  15. thrownewException(‘Unable to encrypt data. Perhaps it is bigger than the key size?’);
  16.  
  17. return $data;
  18. }
  19.  
  20. publicfunction decrypt($data){
  21. if(openssl_private_decrypt(base64_decode($data), $decrypted, $this->privkey))
  22. $data = $decrypted;
  23. else
  24. $data =;
  25.  
  26. return $data;
  27. }
  28.  
  29. }

密匙文件位置问题,是放到访问接口的附近就可以了如果是 CI 的话就放到 index.php 旁边就行了。 但是要注意一点,一定要做访问设置,不然 key 会暴出来的,那时候信息一旦截获就惨了。

类的使用

  1. $rsa =new mycrypt();
  2. echo $rsa -> encrypt(‘abc’);
  3. echo $rsa -> decrypt(‘W+ducpssNJlyp2XYE08wwokHfT0bm87yBz9vviZbfjAGsy/U9Ns9FIed684lWjYyyofi/1YWrU0Mp8vLOYi8l6CfklBY=’);

长数据加密解密

  1. function encrypt_data($publickey,$data)
  2. {
  3. $rsa =new mycrypt();
  4. if($publickey !=“”){
  5. $rsa -> pubkey = $publickey;
  6. }
  7. $crypt_res =“”;
  8. for($i=0;$i<((strlen($data) strlen($data)%117)/117+1); $i++)
  9. {
  10. $crypt_res = $crypt_res.($rsa -> encrypt(mb_strcut($data, $i*117,117,‘utf-8’)));
  11. }
  12. return $crypt_res;
  13. }
  14. function decrypt_data($privatekey,$data)
  15. {
  16. $rsa =new mycrypt();
  17. if($privatekey !=“”){// if null use default
  18. $rsa ->privkey = $privatekey;
  19. }
  20. $decrypt_res =“”;
  21. $datas = explode(‘=’,$data);
  22. foreach($datas as $value)
  23. {
  24. $decrypt_res = $decrypt_res.$rsa -> decrypt($value);
  25. }
  26. return $decrypt_res;
  27. }

JSONP 跨域通讯

我们经过千辛万苦经过加密终于能做到通讯安全了。当然我们的下一步是通过 JSONP 的 get 通讯来实现跨域通讯啦。经过测试:我们的 JS 中最长的 Case url 长度是 3956 在加上跨域 url callbac 参数,经过测试正好差 20 到 4095(一般的 URI 长度限制为 4K)

  1. $.ajax({
  2. type:“get”,
  3. async:false,// 设置同步通讯或者异步通讯
  4. url:“http://22500e31b5a12457.sinaapp.com/ubtamat/getPubKey?c=hknHQKIy3dyeeajyAwZ+raUkV1ezFbgU8zk+54cNQtrcEGozUjXpYhbC6fxz2hCOgp9feIsM1xKJFm5pkAGQ2UcUOc5EJNCAz6L0mXkZbTBmh3PufWxOE7TaicqRCRtZGGNB2qpm2WruXjYg1lPcrPz/rhFZx4DSJvEHkCm7ZU0=……(加密后的结果太长,省略)”,
  5. dataType:“jsonp”,
  6. jsonp:“”,
  7. });

 

  1. header(“Content-type: application/javascript; charset=utf-8”);
  2. $response =“console.log(‘test response!’)”;
  3. $callback = $this->input->GET(‘callback’);
  4. echo $callback.$response;

PHP 代码是 CI 框架 controler 中的部分代码 并且经过了必要的裁剪。更加细节的参数都放到 GET 里面就可以了。处理之后按照上面的形式处理返回值就 ok 如果你配置成功了,你将会在网页的控制台上看到自己动态的,或者像我一样静态的控制台输出。如果要是想获取数据到网页的话还是要借助 回调函数 来实现

JSONP 跨域获取通讯结果

请看下面代码:

客户端代码

  1. varglobal=null;
  2. function jpc(result)
  3. {
  4. global= result.msg;
  5. }
  6.  
  7. $.ajax({
  8. type:“get”,
  9. async:false,// 设置同步通讯或者异步通讯
  10. url:“http://22500e31b5a12457.sinaapp.com/ubtamat/getPubKey”,
  11. dataType:“jsonp”,
  12. jsonp:“jpc”,
  13. });

服务器端代码

  1. header(“Content-type: application/javascript; charset=utf-8”);
  2. $response =“jpc({‘msg’:123456})”;
  3. $callback = $this->input->GET(‘callback’);
  4. echo $callback.$response;

此次通讯的结果会在 jcp 当中调用执行,并且返回的内容会记录到 global 变量当中。

AUTH:PHILO EMAIL:lijianying12 at gmail.com

基于 POST GET 的 http 通讯虽然非常成熟,但是很容易被人监听。并且如果使用跨域 jsonp 的通讯很容易在历史记录中发现通讯网址以及参数。为了克服这些问题,并且降低服务器成本,我们没有使用 SSL 而使用 RSA 加密。文章中的 php 加密解密 JS 的加密解密 互相加密解密 都能验证通过。

其中 PHP 依赖常见的 OPENSSL LIB。JS 依赖 jsencrypt。

我们使用 jsonp get RSA 加密通讯好处如下:

  1. 前后分离适合 cdn 加速。
  2. 安全跨域更适合松散结构的网站。
  3. 不用去买 ssl 证书了。

PHP-RSA 加密跨域通讯实战

首先要生成密匙对

  1. openssl genrsa 1024>private.key
  2. openssl rsa inprivate.key pubout >public.key

JS 的 RSA 加密流程

下载最新版本请移步到 github:jsencrypt 代码在目录 BIN 下面是否用压缩的根据情况决定。

生成 KEY

  1. var keySize =1024;// 加密强度
  2. var crypt =newJSEncrypt({default_key_size: keySize});//RSA 操作对象
  3. // 方法 1 (async)
  4. crypt.getKey(function(){
  5. crypt.getPrivateKey();
  6. crypt.getPublicKey();
  7. });
  8. // 方法 2:
  9. crypt.getKey();
  10. crypt.getPrivateKey();
  11. crypt.getPublicKey();

客户端加密场景:

  1. var crypt1 =newJSEncrypt();// 新建 rsa 对象
  2. var publickey =‘\
  3. —–BEGIN PUBLIC KEY—–\
  4. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3N8LJFqlsa6loCgFpgZVMr/Sx\
  5. DMQY7pr0euNQfh2g+UVPbB0MGhoc7nWL0FQhCgDedbjQw/nGFStFx7W1+0o1oRTY\
  6. u5ebNVivZSobraUv7LJvwT8O66Zs8cxbKLqQ/nE/WwJvXomSIckH6R8iOUO8/QT9\
  7. kv6/L0Uma3qA07pmDQIDAQAB\
  8. —–END PUBLIC KEY—–\
  9. ;
  10. crypt1.setPublicKey(publickey );// 添加来自服务端的 publickey
  11. crypt1.encrypt(‘abc’);// 返回值为加密后的结果

客户端解密场景:

  1. var privatekey =‘—–BEGIN RSA PRIVATE KEY—–\
  2. MIICXQIBAAKBgQC3N8LJFqlsa6loCgFpgZVMr/SxDMQY7pr0euNQfh2g+UVPbB0M\
  3. Ghoc7nWL0FQhCgDedbjQw/nGFStFx7W1+0o1oRTYu5ebNVivZSobraUv7LJvwT8O\
  4. 66Zs8cxbKLqQ/nE/WwJvXomSIckH6R8iOUO8/QT9kv6/L0Uma3qA07pmDQIDAQAB\
  5. AoGBAKba3UWModbfZXQeSJLxNCqWw9zJp3ydL/keQQ35DLqgyIJAD2QKEWXvtJUT\
  6. sMo19fyicSGOmFXQyYvPCKkmpLkOMAj1XaNpSMtSrcMx+gC01PO6Ey9rsUxW1g3u\
  7. fpqbEk9E3a5AtCS0I61nbUpRL6rqMtR5o2wcNR3TLtJt7pjxAkEA7hlFJKU1zWGp\
  8. OvvkJDnHc2NOCEJoGjqCR9wwv96+/xAykl2laI6WvEbbhjoO0+8+d17oigjhneS5\
  9. 2UKFcfqw7wJBAMT+MCQ5TYLQlvjrBaDMqOdLsqtaDE6CpkrgwV820QMvHOo3R4Xd\
  10. uSbrA2tOr9t2/x+FzF971lRGdPFIch9UYMMCQQCZtO6SDaWCBP3++gX57OL5dq41\
  11. XsldxU+9nERMWTvr5UUAgDv8F7Dvsr6dFHXmE5i77yUnlzwvdi0UOIF1Z2U5AkBV\
  12. wyRKYPgx34Ya0JcerntKV1Zt60I4XADx0G/feAn/DN/VyENHMISPQPm4GgXN0jy4\
  13. CJQ1bcCd6B65fQTSRvXpAkA2Vv5yXzeKDls/AyxHEoros/VYftVc1HOFC++q13Rw\
  14. NH2rnlRT8FMTFEqL9MYRqvvYAFf5VmH0M1Nx5t4LRN+l\
  15. —–END RSA PRIVATE KEY—–\
  16. ;
  17. var crypt2 =newJSEncrypt();// 新建加密对象
  18. crypt2.setPrivateKey(privatekey);// 给加密对象设置 privatekey
  19. crypt2.getPublicKey();//Tip 我们是不需要存储 publickey 的直接用 private 能得到 publickey
  20. crypt2.decrypt(“MeUqWB5LwTh8crzPqbZtEtKuZxYvPWH9CTCChK1qoBzIgIXGPCdzNMbiH0cCYHl5qWSERIDOgDIgv4dXsIMjEJ5q0cp/qNQYHM5va0iw0UvKvQB1E8aWtY2nFEPy4F+ArQ0Mj/ijr/CntEP1jHKC3WU9nu2kYrBIBnbj14Bs+kI=”);// 调用解密方法

但是虽然写到了这里,加密方面还是不够用,因为 1024 长度的 RSA 加密最多只能加密长度为 117 的字符串。而 URL 长度最多为 4k 因此这里我们要让加密长度达到 2691 以达到能用的程度。

那么这种加密长度大概能容纳多少数据呢?我们借助 json-generator 来帮忙生成 JSON

  1. sdata =[
  2. {
  3. “_id”:“542f9ac2359c7d881bc0298e”,
  4. “index”:0,
  5. “guid”:“db1dacc1-b870-4e3c-bc1a-80dfd9506610”,
  6. “isActive”:false,
  7. “balance”:“$1,570.15”,
  8. “picture”:“http://placehold.it/32×32”,
  9. “age”:36,
  10. “eyeColor”:“blue”,
  11. “name”:“Effie Barr”,
  12. “gender”:“female”,
  13. “company”:“ZORK”,
  14. “email”:“effiebarr@zork.com”,
  15. “phone”:“+1 (802) 574-3379”,
  16. “address”:“951 Cortelyou Road, Wikieup, Colorado, 4694”,
  17. “about”:“Sunt reprehenderit do laboris velit qui elit duis velit qui. Nostrud sit eiusmod cillum exercitation veniam ad sint irure cupidatat sunt consectetur magna. Amet nisi velit laboris amet officia et velit nisi nostrud ipsum. Cupidatat et fugiat esse minim occaecat cillum enim exercitation laboris velit nisi est enim aute. Enim do pariatur\r\n”,
  18. “registered”:“2014-05-08T15:26:35 -08:00”,
  19. “latitude”:48.576424,
  20. “longitude”:146.634137,
  21. “tags”:[
  22. “esse”,
  23. “proident”,
  24. “quis”,
  25. “consectetur”,
  26. “magna”,
  27. “tempor”,
  28. “anim”
  29. ],
  30. “friends”:[
  31. {
  32. “id”:0,
  33. “name”:“Trisha Cannon”
  34. },
  35. {
  36. “id”:1,
  37. “name”:“Todd Bullock”
  38. },
  39. {
  40. “id”:2,
  41. “name”:“Eileen Drake”
  42. },
  43. {
  44. “id”:3,
  45. “name”:“Ferrell Kelly”
  46. },
  47. {
  48. “id”:4,
  49. “name”:“Fischer Blankenship”
  50. },
  51. {
  52. “id”:5,
  53. “name”:“Morales Mann”
  54. },
  55. {
  56. “id”:6,
  57. “name”:“Brandie Pittman”
  58. },
  59. {
  60. “id”:7,
  61. “name”:“Virgie Kerr”
  62. }
  63. ],
  64. “greeting”:“Hello, Effie Barr! You have 1 unread messages.”,
  65. “favoriteFruit”:“apple”
  66. },
  67. {
  68. “_id”:“542f9ac21c260d03e763a4f2”,
  69. “index”:1,
  70. “guid”:“9e3a3d8a-26f8-46b7-aca0-336a194808b1”,
  71. “isActive”:true,
  72. “balance”:“$3,617.89”,
  73. “picture”:“http://placehold.it/32×32”,
  74. “age”:31,
  75. “eyeColor”:“brown”,
  76. “name”:“Butler Best”,
  77. “gender”:“male”,
  78. “company”:“SPORTAN”,
  79. “email”:“butlerbest@sportan.com”,
  80. “phone”:“+1 (905) 428-3046”,
  81. “address”:“798 Joval Court, Wanship, Delaware, 8974”,
  82. “about”:“Nostrud occaecat id sunt pariatur ad nisi do veniam sit officia non consequat amet fugiat. Est eiusmod labore ut cillum qui eu elit ut eiusmod exercitation. Ut anim nostrud eiusmod voluptate tempor proident id do pariatur. In Lorem ullamco ea irure adipisicing. Quis est dolor ex commodo aliqua nisi elit sit elit anim fugiat sunt amet. Enim consequat ipsum occaecat ipsum tempor deserunt dolor veniam nostrud. Anim cillum ullamco cupidatat aute velit fugiat sit enim in amet anim mollit dolor eiusmod.\r\n”,
  83. “registered”:“2014-08-02T06:15:44 -08:00”,
  84. “latitude”:20.529765,
  85. “longitude”:2.396578,
  86. “tags”:[
  87. “consequat”,
  88. “enim”,
  89. “magna”,
  90. “sunt”,
  91. “Lorem”,
  92. “quis”,
  93. “commodo”
  94. ],
  95. “friends”:[
  96. {
  97. “id”:0,
  98. “name”:“Kenya Rice”
  99. },
  100. {
  101. “id”:1,
  102. “name”:“Hale Knowles”
  103. },
  104. {
  105. “id”:2,
  106. “name”:“Michael Stephens”
  107. },
  108. {
  109. “id”:3,
  110. “name”:“Holder Bailey”
  111. },
  112. {
  113. “id”:4,
  114. “name”:“Garner Luna”
  115. },
  116. {
  117. “id”:5,
  118. “name”:“Alyce Sawyer”
  119. },
  120. {
  121. “id”:6,
  122. “name”:“Rivas Owens”
  123. },
  124. {
  125. “id”:7,
  126. “name”:“Jan Petersen”
  127. }
  128. ],
  129. “greeting”:“Hello, Butler Best! You have 8 unread messages.”,
  130. “favoriteFruit”:“banana”
  131. }
  132. ] 

表单 json 能达到这么长已经是很极端的情况了。因此这种方法绝对是够用的。

长表单内容加解密方法:

  1. function encrypt_data(publickey,data)
  2. {
  3. if(data.length>2691){return;}// length limit
  4. var crypt =newJSEncrypt();
  5. crypt.setPublicKey(publickey);
  6. crypt_res =“”;
  7. for(var index=0; index <(data.length data.length%117)/117+1; index++)
  8. {
  9. var subdata = data.substr(index *117,117);
  10. crypt_res += crypt.encrypt(subdata);
  11. }
  12. return crypt_res;
  13. }
  14. function decrypt_data(privatekey,data)
  15. {
  16. var crypt =newJSEncrypt();
  17. crypt.setPrivateKey(privatekey);
  18. datas=data.split(‘=’);
  19. var decrypt_res=“”;
  20. datas.forEach(function(item)
  21. {
  22. if(item!=“”){de_res += crypt.decrypt(item);}
  23. });
  24. return decrypt_res;
  25. }

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2014-10/107881p2.htm

实战

从上文中,我们已经找到了整个加密过程方法了,但是距离实战还是有一定距离的。首先我们实战的话需要克服接口比较少,功能比较多,单个接口维护用时比较长的问题。

为了解决上面的问题我们做出如下设计。

客户端方面:

设计一个通讯类:只管跟服务器通讯。别的业务什么都不管。

  1. //create connection object.
  2. varConnServ=newObject();
  3.  
  4. ConnServ.tmpResponse =“not initial”;
  5.  
  6. //call back function register slot.
  7. ConnServ.CallBackFunction=function(){console.log(
  8. “call back function set error ! U must set a business call back function!”
  9. )};
  10.  
  11. //input only encrypted data!!!
  12. //send data to server
  13. ConnServ.send=function(data)
  14. {
  15. data = data.replace(/\+/g,“$”);//replace all + as $
  16. $.ajax({
  17. type:“get”,
  18. async:false,
  19. url:“http://22500e317.sinaapp.com/ubtamat?c=”+data,
  20. dataType:“jsonp”,
  21. jsonp:“jpc”
  22. });
  23. return“Send Finish”;
  24. }
  25.  
  26. //default call back funcation
  27. function jpc(res)
  28. {
  29. ConnServ.tmpResponse = res.msg;
  30. ConnServ.CallBackFunction();
  31. }
  32.  
  33.  
  34. //public key store.
  35. ConnServ.getpublickey =function()
  36. {
  37. return“\-“+
  38. “—-BEGIN PUBLIC KEY—– “+
  39. ……………………………………………
  40. “—–END PUBLIC KEY—–“;
  41. }

在上面代码中请注意,RSA 加密过后的字符串当中有一个非法字符 + 要转换成其他合法字符发送到服务器才可以。不然参数会错误。等传输到服务器中自己转换回来在解密就好了。

服务器端方面:

首先我们接收到消息之后要对消息进行解密,之后根据报文内容选择服务器上的功能。然后把其他参数输入到业务类中执行即可。因此我们使用了命令模式来实现单一接口的丰富业务功能。其他的我们需要对 CI 框架的配置进行调整:首先 global config 里面需要调整 $config[‘global_xss_filtering’] = FALSE; 因为如果传输过来的报文解密不了就直接抛弃不进行处理(防止 CC 攻击第一层)这样就从 url 上防止了攻击的可能性。当然我们还是没有完全避免注入风险这时我们就需要在业务类里面调用安全模块:

  1. $this->security->xss_clean()

来实现第二层的 XSS 攻击。这是服务器端设计主要需要说的位置。

服务器获取数据处理全过程

  1. 从 get 接口获得参数 c 的加密数据
  2. 对数据进行 RSA 解密。
  3. 判断数据包时间戳。如果超时直接抛弃(防止从浏览器记录中直接发送 request 到服务器,下面是安全方面的说明)
    • 首先如果不修改数据只修改时间戳不可能从截获的数据报文中实现,因为需要重新加密,如果想得到内容需要服务器上的 privatekey 解密保证安全
    • 如果数据包截获直接发送数据包在超时范围内直接获取数据包内容,也不能实现攻击,因为在客户端有临时 RSA 密匙对生成并且在发送的时候会同时发送 publickey 给服务器做 session 的存储内容并且伪装客户的客户端没有 privatekey 所以获取任何关于登陆之后的消息根本无法解析。
  4. 对解密后的数据进行 xss 检查
  5. 解析报文中需要调用什么功能直接调用反射得到业务类的实例
  6. 调度业务类,并且把得到的参数赋值给业务执行函数的参数。

服务器处理数据过程只跟业务有关

服务器返回数据全过程

  1. 业务处理完成之后针对每一个用户的登陆情况对返回值进行加密。
  2. response

以上业务涉及的部分代码(给出的代码未涉及以上说的安全部分。)

  1. //CI 控制器里面的方法
  2. publicfunction index()
  3. {
  4. header(“Content-Type: text/html;charset=UTF-8”);
  5. $callback = $this -> input->GET(‘callback’);
  6. $input_data = str_replace(“$”,“+”,$this->input->GET(‘c’));
  7. $input_data =$this -> rsa->decrypt_data($input_data);
  8. if($input_data ==“”){return;}// 如果数据不对解析就会失败,直接抛弃数据包,避免 cracker 构造数据包问题
  9. // 这里插入时间戳检查代码
  10. // 这插入 xss 检查
  11. $output_data = command($input_data);
  12. $response =“jpc({‘msg’:”.$output_data.“})”;
  13. $callback = $this->input->GET(‘callback’);
  14. echo $callback.$response;
  15. }

 

  1. // 命令模式中的业务调度方法
  2. function command($input)
  3. {
  4. try
  5. {
  6. $obj_input = json_decode($input);
  7. $action = $obj_input ->{“action”};
  8. $business_action =newReflectionClass($action);
  9. $instance = $business_action->newInstanceArgs();
  10. $output = $instance->Action($obj_input);
  11. // 对 output 变量进行 rsa 加密
  12. return“‘”.$output.“‘”;// here only accept string
  13. }
  14. catch(Exception $e)
  15. {
  16. return“‘”.$e->getMessage().“‘”;
  17. }
  18. }

 

以下是配合业务进行的工具函数:

  1. // 命令接口定义
  2. interfaceICommand{
  3. functionAction($arg_obj);
  4. }
  5. // 把此函数放到 system/core/common.php
  6. // 实现了输入一个文件夹就自动加载所有文件夹中的所有的类。
  7. if(! function_exists(‘require_once_dir’))
  8. {
  9. function require_once_dir($path)
  10. {
  11. $dir_list = scandir($path);
  12. foreach($dir_list as $file)
  13. {
  14. if( $file !=“..”&& $file !=“.”)
  15. {
  16. require_once($path.“/”.$file);
  17. }
  18. }
  19. }
  20. }
  21.  
  22. // 使用:
  23. // 在 application/config/autoload.php 中添加类似如下代码:
  24. require_once_dir(APPPATH.“/controllers/lib”);
  25. require_once_dir(APPPATH.“/controllers/actions”);

以下是实现业务的例子:

  1. classregisterimplementsICommand{
  2. publicfunctionAction($arg_obj)
  3. {
  4. return“we are do nothing: “.json_encode($arg_obj);
  5. }
  6. }

通过以上基本方法,我们可以实现,只要业务继承我们声明的接口就可以开始写业务了。别的什么都不用管,专注于业务即可,其他的安全、IO 等问题都已经一并解决。并且每一个业务都进行了 rsa 加密 xss 攻击过滤伪造数据包攻击。以及在 response 加密只能是固定客户端才能看到报文内容的全过程。但是一定要注意一点,注册这个业务后面要嵌套登陆进行,不然看不到返回值。

数据包必须包含的要素:

  1. acton(业务名)
  2. req_time (请求时间)
  3. public_key (如果是注册跟登陆时候需要提交临时公匙)

总结

因为时间仓促所以只能写到这里了。如果您发现了我文章中的 bug 欢迎发 email 批评指正。非常感谢!同时本方案也会成为我们开源社区 linux52.com 后台系统中的接口设计方案。当然我们社区所有维护的文档都会进行反复验证,如果出问题我们会及时更新。以维护文档的正确性。点击 = 这 = 里 = 查看文档最新版本。

关键词

php js rsa get jsonp 跨域 安全

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计17151字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中