加固-01/02: CWD 无关 include 改造 + UEditor 全入口鉴权 (P0-01)

A. 相对路径 include/require 全量改写为 __DIR__ 基址
   - 修复 nginx+fastcgi 下 php-cgi 继承启动目录 CWD (D:\phpstudy_pro\COM)
     导致 require '../function/...' 相对路径 include 全部失效;
     28 文件 101 处统一改为 __DIR__ 绝对基址,任意 Web 服务器行为一致。
   - 补齐带括号/缺斜杠漏改的 13 处 (controller.php、epay lib、
     payment.php、notify_url.php、return_url.php)。
   - function/config.inc.php 增加 config.local.inc.php 本地覆盖机制
     (该文件加入 .gitignore 不入库),仓库默认配置保持中立。

B. UEditor 后台入口安全加固 (P0-01)
   - admin/php/controller.php 全部 action 前置管理员会话校验
     (admin_username + admin_password),匿名无法上传/抓取/列目录/读配置。
   - 禁用远程图片抓取 catchimage (SSRF 向量),删除 action_crawler.php。
   - 上传/列表白名单剔除 .exe/.dll/.iso/.cab/.swf。
   - Uploader: 移除 iconv('unicode') Windows 告警行;
     getFileInfo/action_list 的 URL 拼接增加 REQUEST_SCHEME 回退。

验证: 匿名访问全部 action 返回未授权;登录态上传成功且 URL 正确;
catchimage 已禁用;JSON 合法;全量 php -l 0 错误;
nginx(8081) 与内置服务器(8082) 双通道回归通过。
This commit is contained in:
youpaishidifu
2026-10-10 11:10:29 +08:00
parent e4a7137206
commit 6669f4bc9c
33 changed files with 121 additions and 155 deletions
+14 -14
View File
@@ -5,7 +5,7 @@
* Date: 2017-10-19
* Time: 22:12
*/
require '../function/function_core.php';
require __DIR__ . '/../function/function_core.php';
if ($_GET['mod'] === 'login'){
@@ -29,7 +29,7 @@ if ($_GET['mod'] === 'login'){
if (empty($_POST['password'])) {
die(json_encode(array('code' => -2, 'msg' => '请输入您的密码')));
}
include '../function/VerificationCode.class.php';
include __DIR__ . '/../function/VerificationCode.class.php';
$verification = Verification::check($_POST['token']);
if ($verification !== true) {
die(json_encode(array('code' => '-88', 'msg' => '请先进行人机验证')));
@@ -356,7 +356,7 @@ switch ($_GET['mod']){
$backinfo['code'] = 0;
$backinfo['count'] = $db->select_count_row('sq_level',array(),'AND');
include "../function/function_app.php";
include __DIR__ . "/../function/function_app.php";
if(!$arr = $db->select_limit_row('sq_level','*',($_GET['page'] - 1) * $_GET['limit'] , $_GET['limit'], array(), 'AND')){
//$backinfo['code'] = -1;
@@ -403,7 +403,7 @@ switch ($_GET['mod']){
//echo $whereinfo;
$backinfo['code'] = 0;
$backinfo['count'] = $db->select_count_row('sq_user',$whereinfo,'AND');
include "../function/function_app.php";
include __DIR__ . "/../function/function_app.php";
$appinfo = app_idgetinfo($_GET['appid']);
if(!$arr = $db->select_limit_row('sq_user','*',($_GET['page'] - 1) * $_GET['limit'] , $_GET['limit'], $whereinfo, 'AND','ORDER BY ID DESC')){
//$backinfo['code'] = -1;
@@ -528,7 +528,7 @@ switch ($_GET['mod']){
}
break;
case 'getfidlist':
include '../function/function_app.php';
include __DIR__ . '/../function/function_app.php';
if(!$result = $db->select_limit_row('sq_fidlist','*',($_GET['page'] - 1) * $_GET['limit'] , $_GET['limit'], array(), 'AND')){
$backinfo['msg'] = $db->geterror();
@@ -606,7 +606,7 @@ switch ($_GET['mod']){
)));
break;
case 'getlevallist':
include '../function/function_app.php';
include __DIR__ . '/../function/function_app.php';
$list = '<option></option>';
$back = $db->select_all_row('sq_level','ID,lname',array(),'AND');
if (!empty($_POST['aid'])){
@@ -631,7 +631,7 @@ switch ($_GET['mod']){
}
break;
case 'getagentlist':
include '../function/function_app.php';
include __DIR__ . '/../function/function_app.php';
if(!$result = $db->select_limit_row('sq_agent','*',($_GET['page'] - 1) * $_GET['limit'] , $_GET['limit'], array(), 'AND')){
$backinfo['code'] = -1;
@@ -998,7 +998,7 @@ switch ($_GET['mod']){
}
$db->update('sq_trade',array('ID'=>$_POST['id']),'AND',array('status'=>3));
$tradeinfo['status'] = 2;
include '../function/trade.inc.php';
include __DIR__ . '/../function/trade.inc.php';
$back = trade_do($tradeinfo);
//print_r($back);
$back = json_decode($back,true);
@@ -1096,7 +1096,7 @@ switch ($_GET['mod']){
die(makejson(1,'success',array('items'=>$result)));
break;
case 'loadbuybody':
include "../function/function_app.php";
include __DIR__ . "/../function/function_app.php";
if(!$appinfo = app_idgetinfo($_POST['appid'])){
die();
}
@@ -1188,7 +1188,7 @@ switch ($_GET['mod']){
die($output);
break;
case 'buy_submit':
include "../function/function_app.php";
include __DIR__ . "/../function/function_app.php";
$_POST = json_decode($_POST['content'],true);
if (!$appinfo = app_idgetinfo($_POST['id'])){
die('应用信息获取失败');
@@ -1203,7 +1203,7 @@ switch ($_GET['mod']){
die('开通的数量不能为空');
}
$balance = $_POST['kt_num'];
include '../function/function_auth.php';
include __DIR__ . '/../function/function_auth.php';
if(!isset($_POST['kt_ip'])){
$_POST['kt_ip'] = '';
}
@@ -1285,7 +1285,7 @@ switch ($_GET['mod']){
die('../.'.$info['imgsrc']);
case 'gradelist':
include '../function/function_app.php';
include __DIR__ . '/../function/function_app.php';
$result = $db->select_all_row('sq_level','*','','');
$data['gradelist_op'] = '<option value="0">请选择一个代理级别进行设置</option>';
$data['gradelist_ad'] = '';
@@ -1345,7 +1345,7 @@ switch ($_GET['mod']){
}
die(json_encode($backinfo));
}else{
include_once '../function/function_app.php';
include_once __DIR__ . '/../function/function_app.php';
$info = '';
$backinfo['code'] = 0;
$backinfo['msg'] = '';
@@ -1457,7 +1457,7 @@ switch ($_GET['mod']){
}
break;
case 'fidlist_show':
include_once '../function/function_app.php';
include_once __DIR__ . '/../function/function_app.php';
$res = $db->select_all_row('sq_fidlist');
$str = '<option></option>';
foreach ($res as $info){
+1 -1
View File
@@ -5,7 +5,7 @@
* Date: 2017-10-15
* Time: 12:08
*/
require '../function/function_core.php';
require __DIR__ . '/../function/function_core.php';
if (empty($_SESSION['admin_username']) || empty($_SESSION['admin_password'])) {
+4 -2
View File
@@ -63,7 +63,8 @@ class Uploader
$this->upFile();
}
$this->stateMap['ERROR_TYPE_NOT_ALLOWED'] = iconv('unicode', 'utf-8', $this->stateMap['ERROR_TYPE_NOT_ALLOWED']);
// 原代码用 iconv('unicode','utf-8',...) 做错误信息国际化,Windows 下 'unicode' 非合法 charset 会告警且无实际意义,移除
// $this->stateMap['ERROR_TYPE_NOT_ALLOWED'] = iconv('unicode', 'utf-8', $this->stateMap['ERROR_TYPE_NOT_ALLOWED']);
}
/**
@@ -362,9 +363,10 @@ class Uploader
*/
public function getFileInfo()
{
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? strtolower($_SERVER['REQUEST_SCHEME']) : (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
return array(
"state" => $this->stateInfo,
"url" => $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . dirname(dirname(dirname($_SERVER['REQUEST_URI']))) . $this->fullName,
"url" => $scheme . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . dirname(dirname(dirname($_SERVER['REQUEST_URI']))) . $this->fullName,
"title" => $this->fileName,
"original" => $this->oriName,
"type" => $this->fileType,
-44
View File
@@ -1,44 +0,0 @@
<?php
/**
* 抓取远程图片
* User: Jinqn
* Date: 14-04-14
* Time: 下午19:18
*/
set_time_limit(0);
include("Uploader.class.php");
/* 上传配置 */
$config = array(
"pathFormat" => $CONFIG['catcherPathFormat'],
"maxSize" => $CONFIG['catcherMaxSize'],
"allowFiles" => $CONFIG['catcherAllowFiles'],
"oriName" => "remote.png"
);
$fieldName = $CONFIG['catcherFieldName'];
/* 抓取远程图片 */
$list = array();
if (isset($_POST[$fieldName])) {
$source = $_POST[$fieldName];
} else {
$source = $_GET[$fieldName];
}
foreach ($source as $imgUrl) {
$item = new Uploader($imgUrl, $config, "remote");
$info = $item->getFileInfo();
array_push($list, array(
"state" => $info["state"],
"url" => $info["url"],
"size" => $info["size"],
"title" => htmlspecialchars($info["title"]),
"original" => htmlspecialchars($info["original"]),
"source" => htmlspecialchars($imgUrl)
));
}
/* 返回抓取数据 */
return json_encode(array(
'state' => count($list) ? 'SUCCESS' : 'ERROR',
'list' => $list
));
+3 -2
View File
@@ -5,7 +5,7 @@
* Date: 14-04-09
* Time: 上午10:17
*/
include "Uploader.class.php";
include __DIR__ . "/Uploader.class.php";
/* 判断类型 */
switch ($_GET['action']) {
@@ -84,9 +84,10 @@ function getfiles($path, $allowFiles, &$files = array())
} else {
if (preg_match("/\.(" . $allowFiles . ")$/i", $file)) {
//echo $path2;
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? strtolower($_SERVER['REQUEST_SCHEME']) : (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
$files[] = array(
'url' => $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . dirname(dirname(dirname($_SERVER['REQUEST_URI']))) . substr($path2, strlen($G['sys']['rootdir'])),
'url' => $scheme . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . dirname(dirname(dirname($_SERVER['REQUEST_URI']))) . substr($path2, strlen($G['sys']['rootdir'])),
'mtime' => filemtime($path2)
);
}
+1 -1
View File
@@ -5,7 +5,7 @@
* Date: 14-04-09
* Time: 上午10:17
*/
include "Uploader.class.php";
include __DIR__ . "/Uploader.class.php";
/* 上传配置 */
$base64 = "upload";
+1 -6
View File
@@ -98,7 +98,6 @@
/* 上传大小限制,单位B,默认100MB */
"videoAllowFiles": [
".flv",
".swf",
".mkv",
".avi",
".rm",
@@ -157,8 +156,6 @@
".gz",
".7z",
".bz2",
".cab",
".iso",
".doc",
".docx",
".xls",
@@ -168,9 +165,7 @@
".pdf",
".txt",
".md",
".xml",
".exe",
".dll"
".xml"
],
/* 上传文件格式显示 */
+13 -6
View File
@@ -6,8 +6,15 @@ date_default_timezone_set("Asia/chongqing");
error_reporting(E_ERROR);
header("Content-Type: text/html; charset=utf-8");
$CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("config.json")), true);
$CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents(__DIR__ . "/config.json")), true);
//print_r($CONFIG);
/* 安全加固(P0):UEditor 全部入口必须处于已登录的管理员会话,杜绝匿名上传/抓取 */
if (empty($_SESSION['admin_username']) || empty($_SESSION['admin_password'])) {
header("Content-Type: application/json; charset=utf-8");
die(json_encode(array('state' => '未授权:请先登录管理后台')));
}
$action = $_GET['action'];
switch ($action) {
@@ -23,21 +30,21 @@ switch ($action) {
case 'uploadvideo':
/* 上传文件 */
case 'uploadfile':
$result = include("action_upload.php");
$result = include(__DIR__ . "/action_upload.php");
break;
/* 列出图片 */
case 'listimage':
$result = include("action_list.php");
$result = include(__DIR__ . "/action_list.php");
break;
/* 列出文件 */
case 'listfile':
$result = include("action_list.php");
$result = include(__DIR__ . "/action_list.php");
break;
/* 抓取远程文件 */
/* 抓取远程文件:安全加固(P0)后已禁用 —— 任意 URL 拉取可被用于 SSRF(内网探测/元数据端点读取) */
case 'catchimage':
$result = include("action_crawler.php");
$result = json_encode(array('state' => 'ERROR', 'list' => array(), 'msg' => '远程抓取功能已禁用'));
break;
default: