AES加解密在php接口请求过程中的应用示例


Posted in PHP onOctober 26, 2016

在php请求接口的时候,我们经常需要考虑的一个问题就是数据的安全性,因为数据传输过程中很有可能会被用fillder这样的抓包工具进行截获。一种比较好的解决方案就是在客户端请求发起之前先对要请求的数据进行加密,服务端api接收到请求数据后再对数据进行解密处理,返回结果给客户端的时候也对要返回的数据进行加密,客户端接收到返回数据的时候再解密。因此整个api请求过程中数据的安全性有了一定程度的提高。

今天结合一个简单的demo给大家分享一下AES加解密技术在php接口请求中的应用。

首先,准备一个AES加解密的基础类:

<?php

/**
 * 加密基础类
 */

class Crypt_AES
{
  protected $_cipher = "rijndael-128";
  protected $_mode = "cbc";
  protected $_key;
  protected $_iv = null;
  protected $_descriptor = null;

  /**
   * 是否按照PKCS #7 的标准进行填充
   * 为否默认将填充“\0”补位
   * @var boolean
   */
  protected $_PKCS7 = false;

  /**
   * 构造函数,对于密钥key应区分2进制字符串和16进制的。
   * 如需兼容PKCS#7标准,应选项设置开启PKCS7,默认关闭
   * @param string $key 
   * @param mixed $iv   向量值
   * @param array $options
   */
  public function __construct($key = null, $iv = null, $options = null)
  {
    if (null !== $key) {
      $this->setKey($key);
    }

    if (null !== $iv) {
      $this->setIv($iv);
    }

    if (null !== $options) {
      if (isset($options['chipher'])) {
        $this->setCipher($options['chipher']);
      }

      if (isset($options['PKCS7'])) {
        $this->isPKCS7Padding($options['PKCS7']);
      }

      if (isset($options['mode'])) {
        $this->setMode($options['mode']);
      }
    }
  }

  /**
   * PKCS#7状态查看,传入Boolean值进行设置
   * @param boolean $flag
   * @return boolean
   */
  public function isPKCS7Padding($flag = null)
  {
    if (null === $flag) {
      return $this->_PKCS7;
    }
    $this->_PKCS7 = (bool) $flag;
  }

  /**
   * 开启加密算法
   * @param string $algorithm_directory locate the encryption 
   * @param string $mode_directory
   * @return Crypt_AES
   */
  public function _openMode($algorithm_directory = "" , $mode_directory = "") 
  {
    $this->_descriptor = mcrypt_module_open($this->_cipher, 
                        $algorithm_directory, 
                        $this->_mode,
                        $mode_directory);
    return $this;
  }

  public function getDescriptor()
  {
    if (null === $this->_descriptor) {
      $this->_openMode();
    }
    return $this->_descriptor;
  }

  protected function _genericInit()
  {
    return mcrypt_generic_init($this->getDescriptor(), $this->getKey(), $this->getIv());
  }

  protected function _genericDeinit()
  {
    return mcrypt_generic_deinit($this->getDescriptor());
  }

  public function getMode()
  {
    return $this->_mode;
  }
  
  public function setMode($mode)
  {
    $this->_mode = $mode;
    return $this;
  }

  public function getCipher()
  {
    return $this->_cipher;
  }
  
  public function setCipher($cipher)
  {
    $this->_cipher = $cipher;
    return $this;
  }  
  /**
   * 获得key
   * @return string
   */
  public function getKey()
  {
    return $this->_key;
  }
  
  /**
   * 设置可以
   * @param string $key
   */
  public function setKey($key)
  {
    $this->_key = $key;
    return $this;
  }  


  /**
   * 获得加密向量块,如果其为null时将追加当前Descriptor的IV大小长度
   *
   * @return string
   */
  public function getIv()
  {
    if (null === $this->_iv && in_array($this->_mode, array( "cbc", "cfb", "ofb", ))) {
      $size = mcrypt_enc_get_iv_size($this->getDescriptor());
      $this->_iv = str_pad("", 16, "\0");
    }
    return $this->_iv;
  }

  /**
   * 获得向量块
   *
   * @param string $iv
   * @return Crypt_AES $this
   */
  public function setIv($iv)
  {
    $this->_iv = $iv;
    return $this;
  }  

  /**
   * 加密
   * @param string $str 被加密文本
   * @return string
   */
  public function encrypt($str){
    $td = $this->getDescriptor();
    $this->_genericInit();
    $bin = mcrypt_generic($td, $this->padding($str));
    $this->_genericDeinit();

    return $bin;
  }
 
  public function padding($dat)
  {
    if ($this->isPKCS7Padding()) {
      $block = mcrypt_enc_get_block_size($this->getDescriptor());
   
      $len = strlen($dat);
      $padding = $block - ($len % $block);
      $dat .= str_repeat(chr($padding),$padding);      
    }

    return $dat;
  }

  public function unpadding($str)
  {
    if ($this->isPKCS7Padding()) {
      $pad = ord($str[($len = strlen($str)) - 1]);
      $str = substr($str, 0, strlen($str) - $pad);
    }
    return $str;
  }

  /**
   * 解密
   * @param string $str 
   * @return string
   */
  public function decrypt($str){
    $td = $this->getDescriptor();

    $this->_genericInit();
    $text = mdecrypt_generic($td, $str);
    $this->_genericDeinit();

    return $this->unpadding($text);
  }
  
  /**
   * 16进制转成2进制数据
   * @param string $hexdata 16进制字符串
   * @return string
   */
  public static function hex2bin($hexdata) 
  {
    return pack("H*" , $hexdata);
  }

  /**
   * 字符串转十六进制
   * @param string $hexdata 16进制字符串
   * @return string
   */
  public static function strToHex($string)
  {
    $hex='';
    for($i=0;$i<strlen($string);$i++)
      $hex.=dechex(ord($string[$i]));
    $hex=strtoupper($hex);
    return $hex;
  }

  /**
   * 十六进制转字符串
   * @param string $hexdata 16进制字符串
   * @return string
   */
  function hexToStr($hex)
  {
    $string='';
    for($i=0;$i<strlen($hex)-1;$i+=2)
      $string.=chr(hexdec($hex[$i].$hex[$i+1]));
    return $string;
  }
}

客户端请求部分:

<?php 

include 'AES.php';

$md5Key = 'ThisIsAMd5Key';               // 对应服务端:$md5key = 'ThisIsAMd5Key';
$aesKey = Crypt_AES::strToHex('1qa2ws4rf3edzxcv');   // 对应服务端:$aesKey = '3171613277733472663365647A786376';
$aesKey = Crypt_AES::hex2bin($aesKey);
$aesIV = Crypt_AES::strToHex('dfg452ws');       // 对应服务端:$aesIV = '6466673435327773';
$aes = new Crypt_AES($aesKey,$aesIV,array('PKCS7'=>true, 'mode'=>'cbc'));

// var_dump($aes);

$data['name'] = 'idoubi';
$data['sex']= 'male';
$data['age'] = 23;
$data['signature'] = '白天我是一个程序员,晚上我就是一个有梦想的演员。';

$content = base64_encode($aes->encrypt(json_encode($data)));
$content = urlencode($content);
$sign = md5($content.$md5Key);

$url = 'http://localhost/aesdemo/api.php';
$params = "version=1.0&sign=$sign&content=$content";

// 请求接口
post($url, $params);

/**
 * 接口请求函数
 */
function post($url, $params) {
  $curlPost= $params;
  $ch = curl_init();   //初始化curl
  curl_setopt($ch, CURLOPT_URL, $url);  //提交到指定网页
  curl_setopt($ch, CURLOPT_HEADER, 0);  //设置header
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  //要求结果为字符串且输出到屏幕上
  curl_setopt($ch, CURLOPT_POST, 1);  //post提交方式
  curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
  $result = curl_exec($ch);//运行curl
  curl_close($ch);
  var_dump(json_decode($result, true));
}

接口处理逻辑:

<?php 


include 'AES.php';

$data = $_POST; // 接口请求得到的数据
$content = $data['content'];
$sign = $data['sign'];

$aesKey = '3171613277733472663365647A786376';
$aesIV = '6466673435327773';
$md5key = 'ThisIsAMd5Key';

// 校验数据
if(strcasecmp(md5(urlencode($content).$md5key),$sign) == 0) {
  // 数据校验成功
  $key = Crypt_AES::hex2bin($aesKey);
  $aes = new Crypt_AES($key, $aesIV, array('PKCS7'=>true, 'mode'=>'cbc'));

  $decrypt = $aes->decrypt(base64_decode($content));
  if (!$decrypt) {   // 解密失败
    echo json_encode('can not decrypt the data');
  } else {
    echo json_encode($decrypt);   // 解密成功
  }
} else{
  echo json_encode('data is not integrity');    // 数据校验失败
}

上述接口请求过程中定义了三个加解密需要用到的参数:$aesKey、$aesIV、$md5key,在实际应用过程中,只要与客户端用户约定好这三个参数,客户端程序员利用这几个参数对要请求的数据进行加密后再请求接口,服务端程序员在接收到数据后利用同样的加解密参数对数据进行解密,整个api请求过程中的数据就很安全了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
使用PHP socke 向指定页面提交数据
Jul 23 PHP
php 定界符格式引起的错误
May 24 PHP
php array的学习笔记
May 16 PHP
smarty内置函数{loteral}、{ldelim}和{rdelim}用法实例
Jan 22 PHP
PHP 双链表(SplDoublyLinkedList)简介和使用实例
May 12 PHP
Yii2框架BootStrap样式的深入理解
Nov 07 PHP
php遍历替换目录下文件指定内容的方法
Nov 10 PHP
PHP常见字符串处理函数用法示例【转换,转义,截取,比较,查找,反转,切割】
Dec 24 PHP
PHP编程获取图片的主色调的方法【基于Imagick扩展】
Aug 02 PHP
thinkPHP5.1框架使用SemanticUI实现分页功能示例
Aug 03 PHP
laravel 根据不同组织加载不同视图的实现
Oct 14 PHP
PHP与Web页面的交互示例详解一
Aug 04 PHP
centos+php+coreseek+sphinx+mysql之一coreseek安装篇
Oct 25 #PHP
在Thinkphp中使用ajax实现无刷新分页的方法
Oct 25 #PHP
PHP上传Excel文件导入数据到MySQL数据库示例
Oct 25 #PHP
详解PHP中foreach的用法和实例
Oct 25 #PHP
php array_keys 返回数组的键名
Oct 25 #PHP
php array_key_exists() 与 isset() 的区别
Oct 24 #PHP
PHP实现简易blog的制作
Oct 24 #PHP
You might like
用PHP实现登陆验证码(类似条行码状)
2006/10/09 PHP
PHP脚本数据库功能详解(中)
2006/10/09 PHP
PHP遍历二维数组的代码
2011/04/22 PHP
php实现MD5加密16位(不要默认的32位)
2013/08/12 PHP
PHP CURL或file_get_contents获取网页标题的代码及两者效率的稳定性问题
2015/11/30 PHP
php基于dom实现读取图书xml格式数据的方法
2017/02/03 PHP
Laravel 中使用 Vue.js 实现基于 Ajax 的表单提交错误验证操作
2017/06/30 PHP
win10 apache配置虚拟主机后localhost无法使用的解决方法
2018/01/27 PHP
TP5框架安全机制实例分析
2020/04/05 PHP
通过隐藏option实现select的联动效果
2009/11/10 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
2012/12/12 Javascript
jQuery插件的写法分享
2013/06/12 Javascript
javascript中数组的冒泡排序使用示例
2013/12/18 Javascript
jquery禁止输入数字以外的字符的示例(纯数字验证码)
2014/04/10 Javascript
IE浏览器不支持getElementsByClassName的解决方法
2014/08/27 Javascript
JS+CSS实现自动改变切换方向图片幻灯切换效果的方法
2015/03/02 Javascript
JS使用cookie设置样式的方法
2016/06/30 Javascript
如何解决jQuery EasyUI 已打开Tab重新加载问题
2016/12/19 Javascript
nodejs基础知识
2017/02/03 NodeJs
Bootstrap实现基于carousel.js框架的轮播图效果
2017/05/02 Javascript
react native实现往服务器上传网络图片的实例
2017/08/07 Javascript
微信小程序中button组件的边框设置的实例详解
2017/09/27 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
2018/04/12 Javascript
在angularJs中进行数据遍历的2种方法
2018/10/08 Javascript
Python实现在matplotlib中两个坐标轴之间画一条直线光标的方法
2015/05/20 Python
python中urlparse模块介绍与使用示例
2017/11/19 Python
使用Python读取安卓手机的屏幕分辨率方法
2018/03/31 Python
解决Tensorflow使用pip安装后没有model目录的问题
2018/06/13 Python
python如何创建TCP服务端和客户端
2018/08/26 Python
Python3删除排序数组中重复项的方法分析
2019/01/31 Python
兰蔻英国官网:Lancome英国
2019/04/30 全球购物
会计毕业自我鉴定
2014/02/05 职场文书
健康家庭事迹材料
2014/05/02 职场文书
岗位职责说明书
2014/05/07 职场文书
一年级数学上册复习计划
2015/01/17 职场文书
工作感言一句话
2015/08/01 职场文书