织梦v57如何有效防SQL注入?

99ANYc3cd6
预计阅读时长 22 分钟
位置: 首页 织梦建站 正文

SQL注入是Web应用中最常见也是最危险的漏洞之一,织梦DedeCMS作为国内流行的CMS系统,由于其早期版本对用户输入的过滤不够严格,历史上曾多次曝出SQL注入漏洞,为V5.7版本进行安全加固是非常必要的。

织梦v57防sql注入
(图片来源网络,侵删)

防护SQL注入的核心思想是:永远不要信任用户的输入,所有来自客户端的数据(GET、POST、Cookie等)都应该被视为不可靠的,必须进行严格的过滤和验证。

以下是针对织梦V5.7的SQL注入防护方案,分为通用安全加固针对已知历史漏洞的专项修复两部分。


通用安全加固(普适性安全原则)

这些措施适用于所有PHP网站,是防御SQL注入的基础。

使用PDO预处理语句

这是最有效、最推荐的防御SQL注入的方法,它将SQL语句和数据分开处理,从根本上杜绝了SQL注入的可能性。

织梦v57防sql注入
(图片来源网络,侵删)

织梦V5.7的修改:

织梦的数据库操作封装在 /include/dedesql.class.php 文件中,要全面转向PDO,工作量较大,但我们可以修改核心类,让它在执行查询时默认使用预处理。

修改 /include/dedesql.class.php

找到 SetQuery()ExecuteQuery() 等方法,将原有的字符串拼接SQL查询的方式,修改为使用预处理语句。

织梦v57防sql注入
(图片来源网络,侵删)

示例(修改思路):

// 原来的方式(危险)
$this->SetQuery("SELECT * FROM dede_archives WHERE id = {$id}");
$this->ExecuteQuery('select');
// 修改后的方式(安全)
public function safeQuery($sql, $params = array()) {
    // 确保已经连接数据库
    if (!$this->linkID) return false;
    // 准备SQL语句
    $this->queryString = $sql;
    if ($this->result = $this->linkID->prepare($sql)) {
        // 绑定参数并执行
        if ($this->result->execute($params)) {
            return $this->result;
        } else {
            $this->DisplayError("SQL语句执行错误: " . $this->linkID->errorInfo());
            return false;
        }
    } else {
        $this->DisplayError("SQL语句预处理失败: " . $this->linkID->errorInfo());
        return false;
    }
}

注意: 全面修改织梦的数据库底层是一个大工程,需要非常谨慎,可能会影响现有功能,对于不想大改的用户,可以采用下面第二种方法。

使用 mysql_real_escape_stringaddslashes 进行转义

如果无法全面转向PDO,那么必须在所有SQL查询执行前,对用户输入进行转义处理。

修改 /include/dedesql.class.php

SetQuery() 方法中,自动对变量进行转义。

// 在 desql.class.php 中找到 SetQuery 方法
function SetQuery($sql) {
    // ... 原有代码 ...
    // 新增:自动转义查询中的变量
    // 这是一个简单的正则,查找类似 `WHERE field = '$var'` 或 `WHERE field = "$var"` 的模式
    // 并对变量进行转义,注意:这种方法不如预处理语句健壮。
    $sql = preg_replace("/(SELECT|UPDATE|INSERT|DELETE|DROP|CREATE|ALTER|TRUNCATE|SHOW|EXEC|UNION|INTO|LOAD_FILE|OUTFILE)\s+/i", " ", $sql); // 简单过滤关键字
    // 对单引号、双引号进行转义
    if (get_magic_quotes_gpc()) {
        $sql = stripslashes($sql);
    }
    $this->queryString = mysql_real_escape_string($sql, $this->linkID);
    // ... 原有代码 ...
}

更推荐的做法: 在每个接收用户输入的文件中,手动进行转义,在处理搜索请求的 plus/search.php 中:

// 在 plus/search.php 中
require_once(dirname(__FILE__)."/../include/config_base.php");
require_once(DEDEINC.'/dedetemplate.class.php');
require_once(DEDEINC.'/dedesql.class.php');
// 获取搜索关键词
$keyword = isset($keyword) ? trim($keyword) : '';
$keyword = addslashes($keyword); // 手动转义
// ... 后续使用 $keyword 构建SQL ...

开启PHP的魔术引号(已废弃,不推荐,但可作为一种兼容方案)

magic_quotes_gpc 是PHP的一个旧特性,它会自动为 GET, POST, COOKIE 数据中的单引号、双引号、反斜杠和 NULL 字符加上反斜杠。

  • 开启状态:可以提供一层基础保护,但不推荐依赖它,因为它可能导致数据二次转义,且已在PHP 5.4.0中移除。
  • 关闭状态必须手动对所有用户输入进行转义,如上所述。

检查方法: echo (get_magic_quotes_gpc() ? '开启' : '关闭');

修改 php.ini 配置

  • register_globals = Off:这是非常重要的设置,如果开启,任何提交的变量都会自动成为全局变量,极易被恶意利用,确保它设置为 Off
  • display_errors = Off:在生产环境中,关闭错误显示,详细的错误信息(如数据库结构、路径等)会泄露给攻击者。
  • log_errors = On:开启错误日志,方便管理员排查问题。

针对织梦V5.7已知历史漏洞的专项修复

除了通用加固,我们还需要修复织梦历史上曝出的具体SQL注入点,这些漏洞通常存在于接收用户输入并直接用于查询的文件中。

漏洞点一:plus/search.php 搜索注入

问题: 搜索关键词 keyword 未经过滤,直接拼接到SQL中。

修复方法:

打开 /plus/search.php 文件。

找到类似这样的代码:

// 危险代码示例
$row = $dsql->GetOne("SELECT * FROM `#@__search_keywords` WHERE keyword LIKE '{$keyword}%' ");

修改为:

// 安全代码
$keyword = isset($keyword) ? trim($keyword) : '';
$keyword = addslashes($keyword); // 或使用 mysql_real_escape_string
// 如果使用PDO,最佳实践是:
// $sql = "SELECT * FROM `#@__search_keywords` WHERE keyword LIKE ?";
// $row = $dsql->GetOne($sql, array($keyword . '%'));
// 如果必须用字符串拼接,确保已转义
if ($keyword != '') {
    $row = $dsql->GetOne("SELECT * FROM `#@__search_keywords` WHERE keyword LIKE '{$keyword}%' ");
}

漏洞点二:member/mtjs.php 会员中心JS注入

问题: 会员ID mid 未过滤,直接用于查询。

修复方法:

打开 /member/mtjs.php 文件。

找到类似这样的代码:

// 危险代码示例
$mid = isset($mid) ? $mid : 0;
$row = $dsql->GetOne("SELECT * FROM `#@__member` WHERE mid = $mid ");

修改为:

// 安全代码
$mid = isset($mid) ? intval($mid) : 0; // 使用 intval 强制转换为整数
if ($mid > 0) {
    $row = $dsql->GetOne("SELECT * FROM `#@__member` WHERE mid = $mid ");
}

对于ID类字段,使用 intval() 是最简单有效的过滤方法。

漏洞点三:plus/list.php 列表页注入

问题: tid (栏目ID) 等参数未过滤。

修复方法:

打开 /plus/list.php 文件。

找到获取 tid 的地方:

// 危险代码示例
$tid = isset($tid) ? $tid : 0;

修改为:

// 安全代码
$tid = isset($tid) ? intval($tid) : 0;

漏洞点四:feedback.php 评论/留言本注入

问题: msg (留言内容)、aid (文章ID) 等参数未过滤。

修复方法:

打开 /feedback.php 文件。

// 危险代码示例
$msg = htmlspecialchars($msg); // htmlspecialchars只转义HTML,不转义SQL
$aid = isset($aid) ? $aid : 0;
// 插入数据库时...
$dsql->ExecuteNoneQuery("INSERT INTO `#@__feedback` (`aid`, `mid`, `msg`, `ip`) VALUES ('$aid', '$mid', '$msg', '$ip')");

修改为:

// 安全代码
$msg = isset($msg) ? trim($msg) : '';
$msg = addslashes($msg); // 必须对SQL进行转义
$aid = isset($aid) ? intval($aid) : 0;
$mid = isset($mid) ? intval($mid) : 0;
$ip = GetIP();
// 插入数据库时...
$dsql->ExecuteNoneQuery("INSERT INTO `#@__feedback` (`aid`, `mid`, `msg`, `ip`) VALUES ('$aid', '$mid', '$msg', '$ip')");

综合安全建议

  1. 及时更新: 访问织梦官方论坛,关注安全公告,及时下载并安装最新的安全补丁,这是最省心的方法。
  2. 文件权限: 将网站目录的权限设置为 755,文件权限设置为 644,确保 datatemplets 等可写目录的权限尽可能严格(如 755750),防止Web用户写入恶意文件。
  3. 删除无用文件: 删除安装目录 /install 和后台管理目录 /dede/ 下的 install_lock.txt(如果存在),以及所有演示数据文件。
  4. 使用安全插件: 可以考虑使用一些专门为织梦开发的安全插件,它们通常集成了防注入、防篡改、后台登录验证等功能。
  5. 定期备份: 定期备份网站文件和数据库,以便在网站被入侵后能快速恢复。

为织梦V5.7防SQL注入,最佳实践是:

  1. 核心思想:对所有用户输入进行“不信任”原则处理。
  2. 最佳方案全面改造数据库操作类,使用PDO预处理语句,这是最根本、最彻底的解决方法。
  3. 次优方案:如果不想大改代码,则在所有接收用户输入的文件中,手动使用 addslashes()mysql_real_escape_string() 对变量进行转义,并对ID类参数使用 intval() 强制转换。
  4. 专项修复:针对已知的、高发的历史漏洞点(如 plus/search.phpmember/mtjs.php 等)进行逐一排查和修复。
  5. 辅助措施:结合文件权限管理、及时更新、定期备份等综合安全手段,构建一个纵深防御体系。

请务必在修改前备份您的网站文件和数据库,以防修改导致意外错误。

-- 展开阅读全文 --
头像
C语言的设计与演化核心思想是什么?
« 上一篇 01-11
C语言中do while与for循环该如何选择?
下一篇 » 01-11

相关文章

取消
微信二维码
支付宝二维码

目录[+]