api管理系统php源码(Api国内PHP开源接口框架)
2022-01-12 18:58:09

上一章起了个头,这一章咱们亲身做一下这个API的基础结构。

我们给它叫做“老赵API系统”。

首先,我们要做的这个API系统是私有的,不开源的,不分发给其它人一起用(当然你非要大力推广,也随便你)。

其次,我故意遗漏了一个小小的点子,这个点子我自己用,我也是怕我这个办法泄露后会有安全问题。

就当是抛砖引玉吧。

先说要注意的几点:

0、不要使用默认首页

1、不使用SESSION和COOKIE

2、每次访问都需要验证用户名密码

3、任何单个文件都不允许能正常运行

4、任何单个文件都不允许能单独实现任何功能

5、未验证成功身份时不输出任何错误提示

相信很多高人一看这几条就会知道我要怎么做。也会有一部分人会嗤之以鼻说太初级。

管他呢,反正这是我自己摸索出来的,就是黑客黑我也只能在操作系统方面下手,在我这套系统里他永远不可能有成功的访问请求。

下面详细说:

0、不要使用默认首页。

如果你的环境里首页设置了很多,比如index.,index.html,default.html,default.php之类的,那么你API的接口文件一定不能用这些,比如你可以用iLaoZhao_XX_api.php,这谁猜得到?

1、不使用SESSION和COOKIE。

COOKIE是用明文存在于用户端的,很容易查看和修改,这个大家都清楚。而PHP的SESSION也依赖于COOKIE来存储一个SESSION_ID。并且我们的API要每次访问就返回一次数据,很多访问方法并不会存储COOKIE,这会导致SESSION失效。

2、每次访问都验证用户名密码。

现在流行那个啥叫Token的方式,我懒得研究,倒不如每次都验证用户名和密码,这样等密码泄露后只要我改一个密码,他那边立马就不能用了。都不用等他那边信息过期。当然我们不能明文传递这些东西,需要做一定加密处理。

3、任何单个文件都不允许能正常运行。

资源文件夹不能有任何可执行文件。并且尽量多分几个文件,所有的文件相互依赖,并且把它们互相组织起来的文件又是另一个单独文件,这样即便别人知道了我们的文件路径和文件名,当访问这个文件时,也无法正常运行。

4、任何单个文件都不允许能单独实现任何功能。

某个文件要实现功能,必须依赖其它文件内的函数或类,并且当前文件不能知道这些函数和类具体在哪个文件里实现的。这样即便这个文件的源代码泄露,对方也不知道里面的依赖关系,不会连累到其它文件。

5、未验证成功身份时不输出任何错误提示。

在用户名密码出错时,系统不要输出任何有用的信息,或者输出一个假的404信息,这样别人在试探我们的系统时,根本不知道是哪一步出错了,而我们的客户端可以根据里面的暗语来判断状态。

我做一个小例子来说明一下,这个小例子只是抛砖引玉,并不是我最终的代码样子。

文件树结构:

如何用PHP写一个比较安全的API系统(实现)

老赵API文件树结构

根目录下只有一个文件夹,整个API系统都通过一个接口文件”DaYeLaiWanA.php”来调用。

怎么样,不知道文件结构的人根本猜不对你有哪些文件,也就不能访问任何文件。

下面的代码没有使用太先进的语法,比如类和对象啊命名空间啊啥的,新版本PHP添了好多特性,但我比较倾向于不去使用它们,我要尽量的让代码对环境没有要求,在尽可能多的版本环境下都能运行。

毕竟我们要的是安全,而不是让所有人能读懂我们的代码。

我们要尽可能的不使用教科书上的通用的写法,尽可能搞一套自己的写法。

下面是DaYeLaiWanA.php的代码:

<?php
//接口文件,单独调用这个文件没任何作用,参数必须得对,差一个字母这个文件都运行不出个毛线来。
//而参数是你自己定的,可随意加密修改。

//当然你还可以把这个路径也放到变量里,然后藏起来。
include "./iLaoZhao_funs/postget.php"; //没有依赖,但也不实现任何具体功能
include "./iLaoZhao_funs/login.php"; //依赖pdo,dbfuns,postget和接口文件
include "./iLaoZhao_funs/curl.php"; //没有依赖,但也不实现任何具体功能
include "./iLaoZhao_funs/dbfuns.php"; //依赖pdo和接口文件
//上面这些文件里涉及到安全的功能都有依赖,并且他们不知道要用的函数在哪
//全靠这个接口文件把它们组合到一起
//并且上面的函数里也会用到接口文件的函数(就是下面那个)
//这些因素缺一不可,只能由接口文件来整合他们
//上面这些文件和其它的API文件,都无法单独运行。不是缺这就是缺那。

//下面这俩函数是故意没单独放文件里的,为的就是其它文件缺少这个接口文件时在调用这个函数时会出错。
function output2Die($msg, $code = -1, $data = ){
    $dieMsg[code] = $code;
    $dieMsg[msg] = $msg;
	$dieMsg[data] = $data;
    echo json_encode($dieMsg);
    die();
}

function isPhone($phonenumber)
{
    return preg_match("/^1[3-9]d{9}$/", $phonenumber);
}

$area = POST("area");//要使用的API种类
$class = POST("class");//要使用的API小分类
$fun = POST("fun");//要使用的API功能

//清理POST
unset($_POST[area]);
unset($_POST[class]);
unset($_POST[fun]);

if ($class !== FALSE && $fun !== FALSE){
    
	if ($area == false){
		$area = "public";
	}
    
	//生成API文件全名,这里没加密,你可以自己变动这里。
    $incFile = dirname(__FILE__)."/{$area}/{$class}/{$fun}.php";

    if (file_exists($incFile)){ //检查API文件是否存在,其实不检查也行。
		include "./config/pdodb.php"; //创建数据库连接,依赖接口文件
        include $incFile;//将单独的API文件导入进来
    }else{
		//我因为调试的原因,显示了错误信息,要求高的可以去掉。
		output2Die("无效的请求", -1);
    }
}else{
	output2Die("无效的请求", -2);
}

文件我写了注释,方便大家看,实际在使用时不能有这些注释,这些注释只能方便别人破解我们的系统,并且这个接口文件尽可能进行代码混淆加密。

然后是一个获得当前用户信息的小例子API,这个API文件存在了
/iLaoZhao_api/public/login/usrMsg.php里面。在调用时大概URL是这样:

https://你的域名/iLaoZhao_api/DaYeLaiWanA.php
POST数据为:{
key:"用户名密码时间加密字符串运算后的结果",
class:"login",
fun:"usrMsg",
userName:"该用户的用户名"
}

API代码内容usrMsg.php为:

<?php
//示例文件,得到当前用户的所有信息
//文件依赖:接口文件、数据库连接文件、dbfuns文件、login文件
//单独访问这个文件根本不能运行
//依赖关系完全靠接口文件处理

//这个API读取post参数中的userName
checkUserNamePassWord(); //检查用户名密码,不对真接就终止运行了,对了的话就可以运行下面的代码
$dbArr[userName] = POST("userName");
if($dbArr[userName] !== false){ //这一步没必要,能验证过上面那个函数,这个参数肯定存在,但我就是写了,就是玩儿
	//一定要用PDO的绑定功能访问数据库,这种方式能避免SQL注入。
	$sql = "select * from tb_users where users_userName = :userName";
	$rec = db_query($sql,$dbArr);
	if($rec[count] > 0){
		output2Die("成功。",1,$rec);
	}else{
		output2Die("找不到该用户。",-1); //要求高的,不要输出错误信息。
	}
}
output2Die("失败",-2); //要求高的,不要输出错误信息。

这里面的checkUserNamePassWord()函数(在iLaoZhao_funs文件夹内的login.php文件里)也比较关键:

<?php
/**
 * 判断用户名密码的函数
 此函数不允许返回东西
 调用的时候直接调用
 用户正常自然没反应
 用户不正常,这个函数直接结束程序运行。
 */
function checkUserNamePassWord(){
	$keyStr = "这里是加密字符串,这个串只有你自己知道是什么。";
	
	$key = POST("key"); //这个key是客户端把用户名密码时间加密字符串运算后的结果

	//用当前日期当第二密钥,这个作用是每天的密钥都不一样。
	//即便被拦截了,也算不出规律来,当然源码泄露了就不行了。
	//不能太精确,因为客户端与服务器端的时间不可能完全一样。
	$keyStr_Today = date(Ymd,time());
	
	//访问数据库,一定要用PDO的这个参数方式。
	//这个方式在代入数据与直接写在SQL语句里不一样。
	//sql注入在这种使用方式下完全不会生效。
	$sqlPar[username] = POST("userName"); //这个没加密的必要,这个在输入框里就能看到,而且也会在很多地方显示。
	if($sqlPar[username] === false || $key === false){
		//非法调用
	}
	
	//不要在sql里直接比对用户名密码
	//而且传过来的数据也没有密码
	//要取出该用户的记录,然后计算后与传过来的加密身份信息对比
	$sql = "select * from tb_users where userName=:username"; //你可以在这limit 1
	$rec = db_query($sql, $sqlPar);
	if($rec[count] > 0){
		
		$keyInDB = md5(md5($keyStr).md5($rec[rows][0][userName]).md5($keyStr_Today).md5($rec[rows][0][passWord]));
		//上面这句是加密方式,把加密字符串、用户名、当前日期、密码的MD5连接起来并再计算一次MD5
		//当然你还可以再加点别的东西,比如字符串反转,以及其它变量之类的。
		//上面这句计算出来的和$key中的一样时,说明密码是对的。
		if($key == $keyInDB){
			//用户名密码对
			//此时我们啥也不做
			//或者你想设置某些变量也行
		}else{
			//否则
			die(); //结束程序运行,
		}
	}
}

代码里都有注释,应该能看清楚。而且还有其它的自定义函数我就不放代码了。

这样我们在扩充API时只需要在对应路径下写PHP代码文件就行,而且很多函数可以直接使用,不用include任何文件。

而且这个系统内所有的文件在单独访问时都会出错(可以设置PHP不显示错误信息),而接口文件在参数不正确的情况下也不会有什么具体运行结果。

也没有默认的首页文档可以访问。

文件路径和文件名都没规律,在网上都查不到参考。

那么想黑掉这套API只有两个办法:

0、黑掉服务器操作系统,再从文件系统入手。

1、破解客户端代码或者拦截访问数据,找到访问规律。

这两点暂时无能为力解决。

**边写文档边写代码,头有点乱,可能有遗漏的东西,不知道大家能不能看懂。

**此API系统还有很多地方可以进一步加密处理,但我个人感觉没必要了。已经够可以了。

**此代码没有使用太先进的语法,比如类啊命名空间啊啥的,新版本PHP添了好多特性,但我比较倾向于不去使用它们,我要尽量的让代码对环境没有要求,在尽可能多的版本环境下都能运行。

毕竟我们要的是安全,而不是让所有人能读懂我们的代码。

有啥忘了的以后再补充吧。

上一章起了个头,这一章咱们亲身做一下这个API的基础结构。

我们给它叫做“老赵API系统”。

首先,我们要做的这个API系统是私有的,不开源的,不分发给其它人一起用(当然你非要大力推广,也随便你)。

其次,我故意遗漏了一个小小的点子,这个点子我自己用,我也是怕我这个办法泄露后会有安全问题。

就当是抛砖引玉吧。

先说要注意的几点:

0、不要使用默认首页

1、不使用SESSION和COOKIE

2、每次访问都需要验证用户名密码

3、任何单个文件都不允许能正常运行

4、任何单个文件都不允许能单独实现任何功能

5、未验证成功身份时不输出任何错误提示

相信很多高人一看这几条就会知道我要怎么做。也会有一部分人会嗤之以鼻说太初级。

管他呢,反正这是我自己摸索出来的,就是黑客黑我也只能在操作系统方面下手,在我这套系统里他永远不可能有成功的访问请求。

下面详细说:

0、不要使用默认首页。

如果你的环境里首页设置了很多,比如index.,index.html,default.html,default.php之类的,那么你API的接口文件一定不能用这些,比如你可以用iLaoZhao_XX_api.php,这谁猜得到?

1、不使用SESSION和COOKIE。

COOKIE是用明文存在于用户端的,很容易查看和修改,这个大家都清楚。而PHP的SESSION也依赖于COOKIE来存储一个SESSION_ID。并且我们的API要每次访问就返回一次数据,很多访问方法并不会存储COOKIE,这会导致SESSION失效。

2、每次访问都验证用户名密码。

现在流行那个啥叫Token的方式,我懒得研究,倒不如每次都验证用户名和密码,这样等密码泄露后只要我改一个密码,他那边立马就不能用了。都不用等他那边信息过期。当然我们不能明文传递这些东西,需要做一定加密处理。

3、任何单个文件都不允许能正常运行。

资源文件夹不能有任何可执行文件。并且尽量多分几个文件,所有的文件相互依赖,并且把它们互相组织起来的文件又是另一个单独文件,这样即便别人知道了我们的文件路径和文件名,当访问这个文件时,也无法正常运行。

4、任何单个文件都不允许能单独实现任何功能。

某个文件要实现功能,必须依赖其它文件内的函数或类,并且当前文件不能知道这些函数和类具体在哪个文件里实现的。这样即便这个文件的源代码泄露,对方也不知道里面的依赖关系,不会连累到其它文件。

5、未验证成功身份时不输出任何错误提示。

在用户名密码出错时,系统不要输出任何有用的信息,或者输出一个假的404信息,这样别人在试探我们的系统时,根本不知道是哪一步出错了,而我们的客户端可以根据里面的暗语来判断状态。

我做一个小例子来说明一下,这个小例子只是抛砖引玉,并不是我最终的代码样子。

文件树结构:

如何用PHP写一个比较安全的API系统(实现)

老赵API文件树结构

根目录下只有一个文件夹,整个API系统都通过一个接口文件”DaYeLaiWanA.php”来调用。

怎么样,不知道文件结构的人根本猜不对你有哪些文件,也就不能访问任何文件。

下面的代码没有使用太先进的语法,比如类和对象啊命名空间啊啥的,新版本PHP添了好多特性,但我比较倾向于不去使用它们,我要尽量的让代码对环境没有要求,在尽可能多的版本环境下都能运行。

毕竟我们要的是安全,而不是让所有人能读懂我们的代码。

我们要尽可能的不使用教科书上的通用的写法,尽可能搞一套自己的写法。

下面是DaYeLaiWanA.php的代码:

<?php
//接口文件,单独调用这个文件没任何作用,参数必须得对,差一个字母这个文件都运行不出个毛线来。
//而参数是你自己定的,可随意加密修改。

//当然你还可以把这个路径也放到变量里,然后藏起来。
include "./iLaoZhao_funs/postget.php"; //没有依赖,但也不实现任何具体功能
include "./iLaoZhao_funs/login.php"; //依赖pdo,dbfuns,postget和接口文件
include "./iLaoZhao_funs/curl.php"; //没有依赖,但也不实现任何具体功能
include "./iLaoZhao_funs/dbfuns.php"; //依赖pdo和接口文件
//上面这些文件里涉及到安全的功能都有依赖,并且他们不知道要用的函数在哪
//全靠这个接口文件把它们组合到一起
//并且上面的函数里也会用到接口文件的函数(就是下面那个)
//这些因素缺一不可,只能由接口文件来整合他们
//上面这些文件和其它的API文件,都无法单独运行。不是缺这就是缺那。

//下面这俩函数是故意没单独放文件里的,为的就是其它文件缺少这个接口文件时在调用这个函数时会出错。
function output2Die($msg, $code = -1, $data = ){
    $dieMsg[code] = $code;
    $dieMsg[msg] = $msg;
	$dieMsg[data] = $data;
    echo json_encode($dieMsg);
    die();
}

function isPhone($phonenumber)
{
    return preg_match("/^1[3-9]d{9}$/", $phonenumber);
}

$area = POST("area");//要使用的API种类
$class = POST("class");//要使用的API小分类
$fun = POST("fun");//要使用的API功能

//清理POST
unset($_POST[area]);
unset($_POST[class]);
unset($_POST[fun]);

if ($class !== FALSE && $fun !== FALSE){
    
	if ($area == false){
		$area = "public";
	}
    
	//生成API文件全名,这里没加密,你可以自己变动这里。
    $incFile = dirname(__FILE__)."/{$area}/{$class}/{$fun}.php";

    if (file_exists($incFile)){ //检查API文件是否存在,其实不检查也行。
		include "./config/pdodb.php"; //创建数据库连接,依赖接口文件
        include $incFile;//将单独的API文件导入进来
    }else{
		//我因为调试的原因,显示了错误信息,要求高的可以去掉。
		output2Die("无效的请求", -1);
    }
}else{
	output2Die("无效的请求", -2);
}

文件我写了注释,方便大家看,实际在使用时不能有这些注释,这些注释只能方便别人破解我们的系统,并且这个接口文件尽可能进行代码混淆加密。

然后是一个获得当前用户信息的小例子API,这个API文件存在了
/iLaoZhao_api/public/login/usrMsg.php里面。在调用时大概URL是这样:

https://你的域名/iLaoZhao_api/DaYeLaiWanA.php
POST数据为:{
key:"用户名密码时间加密字符串运算后的结果",
class:"login",
fun:"usrMsg",
userName:"该用户的用户名"
}

API代码内容usrMsg.php为:

<?php
//示例文件,得到当前用户的所有信息
//文件依赖:接口文件、数据库连接文件、dbfuns文件、login文件
//单独访问这个文件根本不能运行
//依赖关系完全靠接口文件处理

//这个API读取post参数中的userName
checkUserNamePassWord(); //检查用户名密码,不对真接就终止运行了,对了的话就可以运行下面的代码
$dbArr[userName] = POST("userName");
if($dbArr[userName] !== false){ //这一步没必要,能验证过上面那个函数,这个参数肯定存在,但我就是写了,就是玩儿
	//一定要用PDO的绑定功能访问数据库,这种方式能避免SQL注入。
	$sql = "select * from tb_users where users_userName = :userName";
	$rec = db_query($sql,$dbArr);
	if($rec[count] > 0){
		output2Die("成功。",1,$rec);
	}else{
		output2Die("找不到该用户。",-1); //要求高的,不要输出错误信息。
	}
}
output2Die("失败",-2); //要求高的,不要输出错误信息。

这里面的checkUserNamePassWord()函数(在iLaoZhao_funs文件夹内的login.php文件里)也比较关键:

<?php
/**
 * 判断用户名密码的函数
 此函数不允许返回东西
 调用的时候直接调用
 用户正常自然没反应
 用户不正常,这个函数直接结束程序运行。
 */
function checkUserNamePassWord(){
	$keyStr = "这里是加密字符串,这个串只有你自己知道是什么。";
	
	$key = POST("key"); //这个key是客户端把用户名密码时间加密字符串运算后的结果

	//用当前日期当第二密钥,这个作用是每天的密钥都不一样。
	//即便被拦截了,也算不出规律来,当然源码泄露了就不行了。
	//不能太精确,因为客户端与服务器端的时间不可能完全一样。
	$keyStr_Today = date(Ymd,time());
	
	//访问数据库,一定要用PDO的这个参数方式。
	//这个方式在代入数据与直接写在SQL语句里不一样。
	//sql注入在这种使用方式下完全不会生效。
	$sqlPar[username] = POST("userName"); //这个没加密的必要,这个在输入框里就能看到,而且也会在很多地方显示。
	if($sqlPar[username] === false || $key === false){
		//非法调用
	}
	
	//不要在sql里直接比对用户名密码
	//而且传过来的数据也没有密码
	//要取出该用户的记录,然后计算后与传过来的加密身份信息对比
	$sql = "select * from tb_users where userName=:username"; //你可以在这limit 1
	$rec = db_query($sql, $sqlPar);
	if($rec[count] > 0){
		
		$keyInDB = md5(md5($keyStr).md5($rec[rows][0][userName]).md5($keyStr_Today).md5($rec[rows][0][passWord]));
		//上面这句是加密方式,把加密字符串、用户名、当前日期、密码的MD5连接起来并再计算一次MD5
		//当然你还可以再加点别的东西,比如字符串反转,以及其它变量之类的。
		//上面这句计算出来的和$key中的一样时,说明密码是对的。
		if($key == $keyInDB){
			//用户名密码对
			//此时我们啥也不做
			//或者你想设置某些变量也行
		}else{
			//否则
			die(); //结束程序运行,
		}
	}
}

代码里都有注释,应该能看清楚。而且还有其它的自定义函数我就不放代码了。

这样我们在扩充API时只需要在对应路径下写PHP代码文件就行,而且很多函数可以直接使用,不用include任何文件。

而且这个系统内所有的文件在单独访问时都会出错(可以设置PHP不显示错误信息),而接口文件在参数不正确的情况下也不会有什么具体运行结果。

也没有默认的首页文档可以访问。

文件路径和文件名都没规律,在网上都查不到参考。

那么想黑掉这套API只有两个办法:

0、黑掉服务器操作系统,再从文件系统入手。

1、破解客户端代码或者拦截访问数据,找到访问规律。

这两点暂时无能为力解决。

**边写文档边写代码,头有点乱,可能有遗漏的东西,不知道大家能不能看懂。

**此API系统还有很多地方可以进一步加密处理,但我个人感觉没必要了。已经够可以了。

**此代码没有使用太先进的语法,比如类啊命名空间啊啥的,新版本PHP添了好多特性,但我比较倾向于不去使用它们,我要尽量的让代码对环境没有要求,在尽可能多的版本环境下都能运行。

毕竟我们要的是安全,而不是让所有人能读懂我们的代码。

有啥忘了的以后再补充吧。

未解决
您可能还需要
天天领红包,单单有红包
apk文件苹果怎么打开安装(ios安装apk软件步骤)
api数据接口是什么(免费数据恢复软件推荐)
DMBA总裁班的主要内容是什么?
通过临时密码登录钉钉后无法修改密码怎么办?
智能社保里如何提交投保资料?
罗技视频设备插入电源后设备指示灯无法亮起?
2021年中国品牌电商服务商综合竞争力排行榜单TOP15
当贝f1跟f1c哪个好有区别吗
超级勋章不显示动态效果怎么办?
为什么设置了查看审批数据范围,但是全公司员工都能在查看数据看到(新版审批)
app初期推广怎么做,品牌初期推广的几个妙招
app初期怎么推广有效,推广app的方法及经验分享
app初期上线该怎么做,谷歌应用商店刷排名方法
app创业要考虑的因素有哪些,最热创业app平台推荐
app创业步骤有哪些,最热创业app软件推荐
app内容运营是做什么的,内容运营岗位职责
app内容营销模式有哪些,做好营销推广的9大手段
app关键词排名怎么优化(分享app关键词优化方)
app关键词排名怎么优化(4种优化方法及注意事项)
app做广告怎么收费(app打广告的收费及3大流程)
app优化的内容及策略(最值推荐的5大策略)
app优化方案,快速提高app应用市场排名的五个方法
app付费推广渠道有哪些(常用的7种推广渠道)
app付费推广有哪些形式,五种app付费推广方法
app产品运营模式有哪些(附淘客app的4种运营模式)
app产品运营模式有哪些(浅谈这5大运营模式)
app产品设计的思路和方法(全面了解app产品设计)
app产品设计包括哪些方面(app产品设计最核心的5大方面)
app产品经理需要的技能(必须掌握的5项技能)
app产品经理做什么(必须具备的13个基本职责)
正在加载...