php 接口安全解決方案,php接口數據安全解決方案(一)

前言

目的:

1.實現前后端代碼分離,分布式部署

2.利用token替代session實現狀態保持,token是有時效性的滿足退出登錄,token存入redis可以解決不同服務器之間session不同步的問題,滿足分布式部署

3.利用sign,前端按照約定的方式組合加密生成字符串來校驗用戶傳遞的參數跟后端接收的參數是否一直,保障接口數據傳遞的安全

4.利用nonce,timestamp來保障每次請求的生成sign不一致,并將sign與nonce組合存入redis,來防止api接口重放

目錄介紹

├── Core

│?? ├── Common.php(常用的公用方法)

│?? ├── Controller.php (控制器基類)

│?? └── RedisService.php (redis操作類)

├── config.php (redis以及是否開啟關閉接口校驗的配置項)

├── login.php (登錄獲取token入口)

└── user.php(獲取用戶信息,執行整個接口校驗流程)

登錄鑒權圖

d6cf9278833613a3b94ceb2af950da8b.png

接口請求安全性校驗整體流程圖

2da5c39af1341372bf3cef31b87f383e.png

代碼展示

common.php

namespace Core;

/**

* @desc 公用方法

* Class Common

*/

class Common{

/**

* @desc 輸出json數據

* @param $data

*/

public static function outJson($code,$msg,$data=null){

$outData = [

'code'=>$code,

'msg'=>$msg,

];

if(!empty($data)){

$outData['data'] = $data;

}

echo json_encode($outData);

die();

}

/***

* @desc 創建token

* @param $uid

*/

public static function createToken($uid){

$time = time();

$rand = mt_rand(100,999);

$token = md5($time.$rand.'jwt-token'.$uid);

return $token;

}

/**

* @desc 獲取配置信息

* @param $type 配置信息的類型,為空獲取所有配置信息

*/

public static function getConfig($type=''){

$config = include "./config.php";

if(empty($type)){

return $config;

}else{

if(isset($config[$type])){

return $config[$type];

}

return [];

}

}

}

RedisService.php

namespace Core;

/*

*@desc redis類操作文件

**/

class RedisService{

private $redis;

protected $host;

protected $port;

protected $auth;

protected $dbId=0;

static private $_instance;

public $error;

/*

*@desc 私有化構造函數防止直接實例化

**/

private function __construct($config){

$this->redis = new \Redis();

$this->port = $config['port'] ? $config['port'] : 6379;

$this->host = $config['host'];

if(isset($config['db_id'])){

$this->dbId = $config['db_id'];

$this->redis->connect($this->host, $this->port);

}

if(isset($config['auth']))

{

$this->redis->auth($config['auth']);

$this->auth = $config['auth'];

}

$this->redis->select($this->dbId);

}

/**

*@desc 得到實例化的對象

***/

public static function getInstance($config){

if(!self::$_instance instanceof self) {

self::$_instance = new self($config);

}

return self::$_instance;

}

/**

*@desc 防止克隆

**/

private function __clone(){}

/*

*@desc 設置字符串類型的值,以及失效時間

**/

public function set($key,$value=0,$timeout=0){

if(empty($value)){

$this->error = "設置鍵值不能夠為空哦~";

return $this->error;

}

$res = $this->redis->set($key,$value);

if($timeout){

$this->redis->expire($key,$timeout);

}

return $res;

}

/**

*@desc 獲取字符串類型的值

**/

public function get($key){

return $this->redis->get($key);

}

}

Controller.php

namespace Core;

use Core\Common;

use Core\RedisService;

/***

* @desc 控制器基類

* Class Controller

* @package Core

*/

class Controller{

//接口中的token

public $token;

public $mid;

public $redis;

public $_config;

public $sign;

public $nonce;

/**

* @desc 初始化處理

* 1.獲取配置文件

* 2.獲取redis對象

* 3.token校驗

* 4.校驗api的合法性check_api為true校驗,為false不用校驗

* 5.sign簽名驗證

* 6.校驗nonce,預防接口重放

*/

public function __construct()

{

//1.獲取配置文件

$this->_config = Common::getConfig();

//2.獲取redis對象

$redisConfig = $this->_config['redis'];

$this->redis = RedisService::getInstance($redisConfig);

//3.token校驗

$this->checkToken();

//4.校驗api的合法性check_api為true校驗,為false不用校驗

if($this->_config['checkApi']){

// 5. sign簽名驗證

$this->checkSign();

//6.校驗nonce,預防接口重放

$this->checkNonce();

}

}

/**

* @desc 校驗token的有效性

*/

private function checkToken(){

if(!isset($_POST['token'])){

Common::outJson('10000','token不能夠為空');

}

$this->token = $_POST['token'];

$key = "token:".$this->token;

$mid = $this->redis->get($key);

if(!$mid){

Common::outJson('10001','token已過期或不合法,請先登錄系統 ');

}

$this->mid = $mid;

}

/**

* @desc 校驗簽名

*/

private function checkSign(){

if(!isset($_GET['sign'])){

Common::outJson('10002','sign校驗碼為空');

}

$this->sign = $_GET['sign'];

$postParams = $_POST;

$params = [];

foreach($postParams as $k=>$v) {

$params[] = sprintf("%s%s", $k,$v);

}

sort($params);

$apiSerect = $this->_config['apiSerect'];

$str = sprintf("%s%s%s", $apiSerect, implode('', $params), $apiSerect);

if ( md5($str) != $this->sign ) {

Common::outJson('10004','傳遞的數據被篡改,請求不合法');

}

}

/**

* @desc nonce校驗預防接口重放

*/

private function checkNonce(){

if(!isset($_POST['nonce'])){

Common::outJson('10003','nonce為空');

}

$this->nonce = $_POST['nonce'];

$nonceKey = sprintf("sign:%s:nonce:%s", $this->sign, $this->nonce);

$nonV = $this->redis->get($nonceKey);

if ( !empty($nonV)) {

Common::outJson('10005','該url已經被調用過,不能夠重復使用');

} else {

$this->redis->set($nonceKey,$this->nonce,360);

}

}

}

config.php

return [

//redis的配置

'redis' => [

'host' => 'localhost',

'port' => '6379',

'auth' => '123456',

'db_id' => 0,//redis的第幾個數據庫倉庫

],

//是否開啟接口校驗,true開啟,false,關閉

'checkApi'=>true,

//加密sign的鹽值

'apiSerect'=>'test_jwt'

];

login.php

/**

* @desc 自動加載類庫

*/

spl_autoload_register(function($className){

$arr = explode('\\',$className);

include $arr[0].'/'.$arr[1].'.php';

});

use Core\Common;

use Core\RedisService;

if(!isset($_POST['username']) || !isset($_POST['pwd']) ){

Common::outJson(-1,'請輸入用戶名和密碼');

}

$username = $_POST['username'];

$pwd = $_POST['pwd'];

if($username!='admin' || $pwd!='123456' ){

Common::outJson(-1,'用戶名或密碼錯誤');

}

//創建token并存入redis,token對應的值為用戶的id

$config = Common::getConfig('redis');

$redis = RedisService::getInstance($config);

//假設用戶id為2

$uid = 2;

$token = Common::createToken($uid);

$key = "token:".$token;

$redis->set($key,$uid,3600);

$data['token'] = $token;

Common::outJson(0,'登錄成功',$data);

user.php

/**

* @desc 自動加載類庫

*/

spl_autoload_register(function($className){

$arr = explode('\\',$className);

include $arr[0].'/'.$arr[1].'.php';

});

use Core\Controller;

use Core\Common;

class UserController extends Controller{

/***

* @desc 獲取用戶信息

*/

public function getUser(){

$userInfo = [

"id"=>2,

"name"=>'巴八靈',

"age"=>30,

];

if($this->mid==$_POST['mid']){

Common::outJson(0,'成功獲取用戶信息',$userInfo);

}else{

Common::outJson(-1,'未找到該用戶信息');

}

}

}

//獲取用戶信息

$user = new UserController();

$user->getUser();

演示用戶登錄

簡要描述:

用戶登錄接口

請求URL:

http://localhost/login.php

請求方式:

POST

參數:

參數名

必選

類型

說明

username

string

用戶名

pwd

string

密碼

返回示例

{

"code": 0,

"msg": "登錄成功",

"data": {

"token": "86b58ada26a20a323f390dd5a92aec2a"

}

}

{

"code": -1,

"msg": "用戶名或密碼錯誤"

}

演示獲取用戶信息

簡要描述:

獲取用戶信息,校驗整個接口安全的流程

請求URL:

http://localhost/user.php?sign=f39b0f2dea817dd9dbef9e6a2bf478de

請求方式:

POST

參數:

參數名

必選

類型

說明

token

string

token

mid

int

用戶id

nonce

string

防止用戶重放字符串 md5加密串

timestamp

int

當前時間戳

返回示例

{

"code": 0,

"msg": "成功獲取用戶信息",

"data": {

"id": 2,

"name": "巴八靈",

"age": 30

}

}

{

"code": "10005",

"msg": "該url已經被調用過,不能夠重復使用"

}

{

"code": "10004",

"msg": "傳遞的數據被篡改,請求不合法"

}

{

"code": -1,

"msg": "未找到該用戶信息"

}

文章完整代碼地址

后記

上面完整的實現了整個api的安全過程,包括接口token生成時效性合法性驗證,接口數據傳輸防篡改,接口防重放實現。僅僅靠這還不能夠最大限制保證接口的安全。條件滿足的情況下可以使用https協議從數據底層來提高安全性,另外本實現過程token是使用redis存儲,下一篇文章我們將使用第三方開發的庫實現JWT的規范操作,來替代redis的使用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/537922.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537922.shtml
英文地址,請注明出處:http://en.pswp.cn/news/537922.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Teamview連接Windows server問題

場景: 服務器在集團總部杭州,網管在集團寧波分公司,連接服務器通過內網遠程桌面。過程: 網管給了tv的賬號,密碼。連接的時候一直連不上去。卡在“正在初始化連接參數”。后來網管不信,遠程桌面了下&#xf…

nginx An attempt was made to access a socket in a way forbidden by its access permissions

在安裝了 sqlserver2008 的win7 與 win2008 上啟動 nginx,綁定80端口,報錯: nginx An attempt was made to access a socket in a way forbidden by its access permissions查了百度,說修改注冊表,但我的電腦上找不到文…

php codesniffer 代碼規范,規范三:PHP_CodeSniffer 輔佐代碼規范

>也可以參考此文:https://www.cnblogs.com/huangbx/p/php_codesniffer.html[TOC]我用的是wamp,環境是php7.0.23# (一)下載 pear打開http://pear.php.net/go-pear.phar,會顯示代碼,不用管他,直接copys復制到本地&…

php的cms是什么意思,phpcms是什么系統

什么是phpcms?Phpcms 是國內領先的網站內容管理系統,同時也是一個開源的PHP開發框架。Phpcms由內容模型、會員、問吧、專題、財務、訂單、廣告、郵件訂閱、 短消息、自定義表單、全站搜索等20多個功能模塊組成,內置新聞、圖片、下載、信息、產…

【python】 time模塊和datetime模塊詳解 【轉】

一、time模塊 time模塊中時間表現的格式主要有三種: a、timestamp時間戳,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量 b、struct_time時間元組,共有九個元素組。 c、format time 格式化時間,已格式化的結構使時間更…

spring boot Exception in Thread “main” java.lang.classNoFoundException

在客戶測試環境部署,通過打包成jar,使用命令 nohup java -jar /usr/local/tomcat/shirencai/ct-peixun-provider.jar –spring.profiles.activestage > /usr/local/tomcat/shirencai/ct-peixun-provider-temp.txt & 報錯后來排查以為是內存不夠。…

php源碼自動識別文本中的鏈接,自動加載識別文件Auto.php

用于本應用的控制器自動加載類設置&#xff0c;用法如同\CodeIgniter\Config\AutoloadConfig自動加載識別文件:dayrui/App/應用目錄/Config/Auto.php語法格式&#xff1a;<?php // 自動加載識別文件return [/*** 命名空間映射關系*/psr4 > [],/*** 類名映射關系*/classm…

如何識別“答非所問”?使用gensim進行文本相似度計算

在文本處理中&#xff0c;比如商品評論挖掘&#xff0c;有時需要了解每個評論分別和商品的描述之間的相似度&#xff0c;以此衡量評論的客觀性。 評論和商品描述的相似度越高&#xff0c;說明評論的用語比較官方&#xff0c;不帶太多感情色彩&#xff0c;比較注重描述商品的屬性…

防抓包重放php,超簡單最基本的WEB抓包改包重放的方法

【注意&#xff1a;此文章為博主原創文章&#xff01;轉載需注意&#xff0c;請帶原文鏈接&#xff0c;至少也要是txt格式&#xff01;】很多很多剛剛接觸的同事問我如何抓包&#xff0c;如果講用工具可能還涉及什么裝證書&#xff0c;熟悉使用工具等等&#xff0c;特別繁瑣&am…

mysql查詢很慢優化方法1

解決方法&#xff1a; 關聯的字段建索引。 具體分析如下&#xff1a;舉例&#xff1a; 表格&#xff1a;培訓學生表&#xff0c;班級報名表 需求&#xff1a;查詢出學生報了哪些班級 兩表有個關聯字段“CD”&#xff08;學生學號&#xff09;。 視圖sql&#xff1a; SELECTt_px…

ubuntu進行apt-get時候出現Package ssh is not available, but is referred to by another package 錯誤...

今天在ubuntu進行ssh安裝的時候&#xff0c;出現如下錯誤。Reading package lists... Done Building dependency tree... Done Package ssh is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is …

php找出函數定義位置,WordPress如何快速定位PHP函數所在文件位置及代碼行號?

有時候我們需要修改別人源碼里的代碼&#xff0c;卻找不到對應的函數放在了哪兒&#xff0c;就可以用使用本文介紹的辦法&#xff0c;幫你快速定位函數位置。特別是某些寫法不規范的WordPress主題&#xff0c;各種模塊&#xff0c;函數到處放&#xff0c;找半天的那種。那么Wor…

微信公眾號每次調用接口正確或錯誤的返回碼

原文連接&#xff1a;https://blog.csdn.net/pansanday/article/details/65448868 ----------------------------------------- 公眾號每次調用接口時&#xff0c;可能獲得正確或錯誤的返回碼&#xff0c;開發者可以根據返回碼信息調試接口&#xff0c;排查錯誤。 全局返回碼…

Phoenix:全局索引設計實踐

概述 全局索引是Phoenix的重要特性&#xff0c;合理的使用二級索引能降低查詢延時&#xff0c;讓集群資源得以充分利用。 本文將講述如何高效的設計和使用索引。 全局索引說明 全局索引的根本是通過單獨的HBase表來存儲數據表的索引數據。我們通過如下示例看索引數據和主表數據…

php 美顏,懷念以前無濾鏡美顏的影視劇

濾鏡是為了照片質量更高一些&#xff0c;色彩更真實突出的一種補助工具。自從有了美顏和濾鏡后&#xff0c;大家的生活都變成了彩色。開了濾鏡美顏&#xff0c;小伙伴們有木有感覺生活水平變高了&#xff1f;但影視劇&#xff0c;好像變成了單色&#xff1f;&#xff01;(注意&…

select2控件動態更新option

原文連接&#xff1a;https://blog.csdn.net/u010784959/article/details/77893674 ----------------------------------------------------------------------------- 根據輸入框中內容&#xff0c;動態更新select2組件中option內容 監聽輸入框內容變化事件&#xff0c;先銷…

在Python中定義和使用抽象類的方法

https://www.jb51.net/article/87710.htm 像java一樣python也可以定義一個抽象類。 在講抽象類之前&#xff0c;先說下抽象方法的實現。 抽象方法是基類中定義的方法&#xff0c;但卻沒有任何實現。在java中&#xff0c;可以把方法申明成一個接口。而在python中實現一個抽象方法…

把 Rational Rose 的圖表保存為圖片文件

原文連接&#xff1a;https://blog.csdn.net/xiaobing_122613/article/details/56485456 ------------------------------------------------ Rational Rose 本身沒有保存為 JPG/GIF 圖片格式的功能。 1. 可以通過全選、復制、粘貼可以把圖表直接粘貼到打開的 Word 文檔里 …

lppl模型 matlab,對LPPL模型的思考

2013-05-10 16:19:29最近&#xff0c;LPPL模型在金融市場中的運用越來越廣&#xff0c;LPPL模型認為金融市場處于自組織臨界狀態&#xff0c;泡沫的產生往往伴隨著市場參與者之間行為的正反饋作用&#xff0c;泡沫也會因此越來越大&#xff0c;并在奇點處崩潰&#xff0c;詳細介…

代碼質量管理工具】——sonar

原文地址&#xff1a;https://blog.csdn.net/luckystar689/article/details/53871821 ------------------------------------------------------------------------ 【前言】 bug越改越多&#xff0c;程序一換數據就崩&#xff0c;這就是目前我們系統的一個現狀。在這之前&am…