概述在我们的工作中,无时无刻不在和接口打交道,有的调用别人的接口,有的为别人提供接口,这个过程中肯定离不开验签。在设计签名验证时,必须满足以下几点:可变性:每个签名必须是不同的。时效性:每个请求的时效性,过期和作废。唯一性:每个签名都是唯一的。完整性:验证传入数据不被篡改的能力。下面主要分享一些工作中常用的加解密方法。普通验证示例:/api/login?username=xxx&password=xxx&sign=xxx发送方和接收方约定一个加密的salt值生成签名。示例代码://创建签名私有函数_createSign(){$strSalt='1scv6zfzSR1wLaWN';$strVal='';如果($this->params){$params=$this->params;ksort($参数);$strVal=http_build_query($params,'','&',PHP_QUERY_RFC3986);}returnmd5(md5($strSalt).md5($strVal));}//验证签名if($_GET['sign']!=$this->_createSign()){echo'InvalidSign.';}上面使用的是MD5方法,MD5属于单向散列加密。单向散列加密定义将任意长的输入字符串变为固定长度的输出字符串,并且很难从输出字符串中获取输入字符串。这种方法称为单项哈希加密。常用算法MD5SHAMACCRC的优点以MD5为例。存储方便:加密后都是固定大小(32位)的字符串,可以分配固定大小的存储空间。低开销:加密/加密对性能的开销最小。文件加密:只需要一个32位的字符串来验证一个巨大文件的完整性。不可逆:在大多数情况下是不可逆的,具有很好的安全性。缺点是存在暴力破解的可能。最好通过加盐来提高安全性。应用场景用于敏感数据,如用户密码、请求参数、文件加密等。存储密码的推荐方法password_hash()使用足够强大的单向哈希算法来创建密码的哈希。示例代码://密码加密$password='123456';$strPwdHash=password_hash($password,PASSWORD_DEFAULT);//密码验证if(password_verify($password,$strPwdHash)){//Success}else{//Fail}PHP手册地址:http://php.net/manual/zh/func...对称加密定义是同一个密钥可以同时用于数据的加密和解密。这种方法称为对称加密。常用算法DESAESAES是DES的升级版,密钥长度更长,选择更多,更灵活,安全性更高,速度更快。优点算法公开,计算量小,加密速度快,加密效率高。缺点:发送方和接收方必须就密钥达成一致,然后双方才能保存密钥,密钥管理成为双方的负担。应用场景是数据量比较大或者关键数据的加密。AESAES加密类库在网上很容易找到,请注意类库中的mcrypt_encrypt和mcrypt_decrypt方法!在PHP7.2版本已经弃用,新版本使用openssl_encrypt和openssl_decrypt方法。示例代码(类库):classAes{/***varstring$method加解密方法*/protected$method;/***varstring$secret_key加解密密钥*/protected$secret_key;/***varstring$iv加密解密向量*/protected$iv;/***varint$options*/protected$options;/***构造函数*@paramstring$key密钥*@paramstring$method加密方法*@paramstring$ivvector*@paramint$options*/publicfunction__construct($key='',$method='AES-128-CBC',$iv='',$options=OPENSSL_RAW_DATA){$this->secret_key=isset($key)?$key:'CWq3g0hgl7Ao2OKI';$this->method=in_array($method,openssl_get_cipher_methods())?$方法:'AES-128-CBC';$this->iv=$iv;$this->options=in_array($options,[OPENSSL_RAW_DATA,OPENSSL_ZERO_PADDING])?$选项:OPENSSL_RAW_DATA;}/***加密*@paramstring$data加密数据*@returnstring*/publicfunctionencrypt($data=''){returnbase64_encode(openssl_encrypt($data,$this->method,$this->secret_key,$this->options,$this->iv));}/***Decrypt*@paramstring$data解密数据*@returnstring*/publicfunctiondecrypt($data=''){returnopenssl_decrypt(base64_decode($data),$this->method,$this->secret_key,$this->options,$this->iv);}}示例代码:$aes=newAes('HFu8Z5SjAT7CudQc');$encrypted=$aes->encrypt('HoeWoRiDangNoon');echo'加密前:hoeHeRidangWu
加密后:',$encrypted,'
';$decrypted=$aes->decrypt($encrypted);echo'加密后:',$encrypted,'
解密后:',$decrypted;运行结果:非对称加密定义需要加密和解密两个密钥,这两个密钥分别是公钥和私钥,这种方法称为相对于对称加密,非对称加密常用的算法RSA具有更好的安全性。加密和解密需要不同的密钥,公钥和私钥都可以相互加密和解密。缺点加解密时间长,速度慢,只适合加密少量数据。应用场景适用于安全性要求高的场景,适用于加密少量数据,如支付数据、登录数据等RSA和RSA2算法名称标准名称备注RSA2SHA256WithRSA要求RSA密钥长度至少为2048。RSASHA1WithRSA不限制RSA密钥的长度。建议使用2048位以上。RSA2具有比RSA更强的安全能力。蚂蚁金服和新浪微博都在使用RSA2算法。创建公钥和私钥:opensslgenrsa-outprivate_key.pem2048opensslrsa-inprivate_key.pem-pubout-outpublic_key.pem执行上面的命令,会生成两个文件private_key.pem和public_key.pem。示例代码(类库):classRsa2{privatestatic$PRIVATE_KEY='private_key.pem内容';privatestatic$PUBLIC_KEY='public_key.pem内容';/***获取私钥*@returnbool|resource*/privatestaticfunctiongetPrivateKey(){$privateKey=self::$PRIVATE_KEY;返回openssl_pkey_get_private($privateKey);}/***获取公钥*@returnbool|resource*/privatestaticfunctiongetPublicKey(){$publicKey=self::$PUBLIC_KEY;返回openssl_pkey_get_public($publicKey);}/***私钥加密*@paramstring$data*@returnnull|string*/publicstaticfunctionprivateEncrypt($data=''){if(!is_string($data)){returnnull;}返回openssl_private_encrypt($data,$encrypted,self::getPrivateKey())?base64_encode($encrypted):空;}/***公钥加密*@paramstring$data*@returnnull|string*/publicstaticfunctionpublicEncrypt($data=''){if(!is_string($data)){返回空值;}返回openssl_public_encrypt($data,$encrypted,self::getPublicKey())?base64_encode($encrypted):空;}/***私钥解密*@paramstring$encrypted*@returnnull*/publicstaticfunctionprivateDecrypt($encrypted=''){if(!is_string($encrypted)){returnnull;}返回(openssl_private_decrypt(base64_decode($encrypted),$decrypted,self::getPrivateKey()))?$解密:空;}/***公钥解密*@paramstring$encrypted*@returnnull*/publicstaticfunctionpublicDecrypt($encrypted=''){if(!is_string($encrypted)){returnnull;}返回(openssl_public_decrypt(base64_decode($encrypted),$decrypted,self::getPublicKey()))?$解密:空;}/***创建签名*@paramstring$data数据*@returnnull|string*/publicfunctioncreateSign($data=''){if(!is_string($data)){返回空值;}返回openssl_sign($data,$sign,self::getPrivateKey(),OPENSSL_ALGO_SHA256)?base64_encode($sign):空;}/***验证签名*@paramstring$datadata*@paramstring$signsignature*@returnbool*/publicfunctionverifySign($data='',$sign=''){if(!is_string($sign)||!is_string($sign)){返回false;}return(bool)openssl_verify($data,base64_decode($sign),self::getPublicKey(),OPENSSL_ALGO_SHA256);}}示例代码:$rsa2=newRsa2();$privateEncrypt=$rsa2->privateEncrypt('和合日当中午');echo'私钥加密后:'.$privateEncrypt.'
';$publicDecrypt=$rsa2->publicDecrypt($privateEncrypt);echo'公钥解密后:'.$publicDecrypt.'
';$publicEncrypt=$rsa2->publicEncrypt('公钥加密:'.$publicEncrypt.'
';$privateDecrypt=$rsa2->privateDecrypt($publicEncrypt);echo'私钥解密后:'.$privateDecrypt.'
';$sign=$rsa2->createSign('和合日当中午');echo'生成签名:'.$privateEncrypt.'
';$status=$rsa2->verifySign('锄地之日',$sign);echo'验证签名:'.($status?'success':'failure');运行结果:部分数据The截图如下:JS-RSAJSEncrypt:Javascriptlibrary执行OpenSSLRSA加密解密和密钥生成的Git源码:https://github.com/travist/js...应用场景:当我们在做WEB登录功能的时候一般,通过Form提交或者Ajax方式提交给服务器进行校验。为了防止被抓包,必须先对登录密码进行RSA加密(RSA),然后提交给服务器验证。一些大公司都在用,比如淘宝、京东、新浪等,示例代码就不提供了,Git上提供的代码很全。密钥安全管理这些加密技术,实现安全加密效果的前提是密钥的保密性。在实际工作中,不同环境(开发环境、预发布环境、正式环境)的key应该是不同的。那么,密钥应该如何安全保管呢?环境变量将密钥设置到一个环境变量中,每次都从环境变量中加载。配置中心将密钥保存在配置中心统一管理。密钥过期策略设置了密钥的有效期,比如每月重置一次。在此希望大家提供新思路~界面调试工具Postman是一款功能强大的Chrome插件,用于网页调试和发送网页HTTP请求。这个不用介绍了,想必大家都用过。SocketLogGit源码:https://github.com/luofei614/...解决痛点:运行API有bug,不能在文件中使用var_dump进行调试,会影响客户端调用。把日志写到文件里查看不是很方便。我们在二次开发新系统的时候,想要查看执行了哪些Sql语句,以及程序的警告、通知等错误信息。SocketLog可以解决以上问题。它通过WebSocket将调试日志输出到浏览器控制台。如何使用安装配置Chrome插件SocketLogServer安装PHP并使用SocketLog调试配置日志类型及相关参数在线接口文档接口开发完成,需要将接口文档提供给请求方。现在大部分文档都是用Markdown格式写的。还有一些开源系统可以下载安装到自己的服务器上。还有一些在线系统,既可以在线使用,也支持离线导出。根据自身情况,选择适合自己的文档平台。常用的接口文档平台:eolinkerApizzaYapiRAP2DOCleverextension1.HTTP和RPC的选择可能会有一些疑惑。RPC框架的配置比较复杂。明明可以用HTTP,为什么还要选择RPC呢?下面简单介绍一下HTTP和RPC的区别。传输协议:HTTP基于HTTP协议。RPC可以是HTTP协议,也可以是TCP协议。HTTP也是一种实现RPC的方式。性能消耗:HTTP大多基于JSON实现,序列化需要时间和性能。RPC可以基于二进制传输,性能消耗小。推荐一个新的序列化类库MessagePack,它很像JSON,但是比JSON传输速度更快,成本更低。官网地址:https://msgpack.org/在服务治理和负载均衡配置上也存在一些差异。使用场景:如浏览器界面、APP界面、第三方界面,推荐使用HTTP。比如群组内的服务调用,推荐使用RPC。与HTTP相比,RPC具有更低的性能消耗、更高的传输效率和方便的服务管理。推荐的RPC框架:Thrift。2.动态令牌下面简单介绍一下动态令牌,有兴趣的可以多了解一下。OTP:One-TimePassword一次性密码。HOTP:HMAC-basedOne-TimePassword基于HMAC算法加密的一次性密码。TOTP:Time-basedOne-TimePassword基于时间戳算法的一次性密码。使用场景:公司VPN登录双因素认证服务器登录动态密码验证网银、网络游戏实体动态token令牌银行转账动态密码……总结本文讲了签名验证设计需要满足的一些条件:可变性、及时性、唯一性、完整性。它还谈到了一些加密方法:单向散列加密、对称加密和非对称加密。同时分析了各种加密方式的优缺点。您可以根据自己的业务特点自由选择。提供了Aes、Rsa相关代码示例。分享了一个可以编写接口文档的在线系统。分享了开发过程中使用的接口调试工具。在扩展中,分析了HTTP和RPC的区别,动态令牌的引入等。这也提出了一个问题,如何安全地管理密钥?,欢迎各位前辈/大哥提供新思路~推荐阅读系统详解-SSO单点登录系统详解-PHPWEB安全防御系统详解-PHP缓存技术系统详解-PHP浮点高精度计算一起学习