从某cmsV4.1.0 sql注入漏洞看程序开发安全隐患
字数 1114 2025-08-27 12:33:49
CMS V4.1.0 SQL注入漏洞分析与安全开发实践
一、CMS防护机制分析
1.1 程序入口过滤机制
set_globals方法
- 将GET与POST参数赋值到$GLOBALS数组
- 使用
gpc_stripslashes处理传入键值 - 特殊行为:当
MAGIC_QUOTES_GPC开启时,去除其添加的转义符
input方法
- 对$GLOBALS数组中的值通过
sql_replace进行SQL过滤 - 开发者意图:保持原始输入,按需进行特定过滤
sql_replace方法
str_replace(array("'",'"',"(",")",";"),"",$value)
- 对特殊字符(
',",(,),;)进行置空处理
safe_htm方法
- 对HTML特殊字符进行转义,防止XSS攻击
1.2 数据库操作类过滤
insert/update方法
- 对传入数组的值部分进行过滤处理
- 使用
escape_string方法进行转义
二、安全漏洞分析
2.1 第一类安全隐患:过滤方法使用不当
典型漏洞示例
文件:/api/sms_check.php
$code = strip_tags($GLOBALS['param']); // 错误:直接使用$GLOBALS
// 正确做法应为:
$code = strip_tags(input('param'));
漏洞原理
- 直接使用
$GLOBALS获取用户输入,绕过input方法过滤 - 参数直接拼接SQL语句导致注入
注入Payload
http://example.com/api/sms_check.php?param=1' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)--
2.2 第二类安全隐患:键名过滤缺失
典型漏洞示例
文件:/coreframe/app/content/admin/category.php
$formdata = $GLOBALS['form']; // 直接接收用户输入数组
$this->db->insert($formdata); // 键名未过滤
漏洞原理
- 数据库操作类只过滤数组值,不过滤键名
- 通过控制数组键名实现注入
注入Payload
&form[seo_description`)values(updatexml(1,concat(0x7e,version(),0x7e),1))#]=666
三、安全开发实践指南
3.1 输入处理规范
- 统一输入入口:所有用户输入必须通过
input方法获取 - 避免直接使用:
$_GET、$_POST、$GLOBALS等原生变量 - 二次过滤原则:避免重复过滤导致数据损坏
3.2 SQL注入防护
- 参数化查询:优先使用预处理语句
- 全面过滤:键名和键值都需要过滤
- 转义策略:
function escape_input($input) { if(is_array($input)) { return array_map('escape_input', $input); } return str_replace(array("'",'"',"(",")",";","\\"), "", $input); }
3.3 安全编码检查清单
- [ ] 所有SQL查询使用参数化或严格过滤
- [ ] 数组类型输入同时过滤键名和键值
- [ ] 避免在过滤后执行解码操作(如urldecode)
- [ ] 关键操作进行代码审计
3.4 安全函数实现示例
/**
* 安全获取输入
* @param string $key 参数名
* @param string $type 输入类型(get/post)
* @return mixed
*/
function safe_input($key, $type = 'get') {
$value = $type == 'get' ? $_GET[$key] : $_POST[$key];
// 去除魔术引号
if(get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
// SQL过滤
$value = str_replace(array("'",'"',"(",")",";","\\"), "", $value);
// HTML过滤
$value = htmlspecialchars($value, ENT_QUOTES);
return $value;
}
/**
* 安全数据库插入
* @param array $data 数据数组
*/
function safe_insert($table, $data) {
$fields = array();
$values = array();
foreach($data as $key => $value) {
$fields[] = '`'.str_replace('`', '', $key).'`'; // 过滤键名
$values[] = "'".mysql_real_escape_string($value)."'"; // 过滤键值
}
$sql = "INSERT INTO {$table} (".implode(',', $fields).") VALUES (".implode(',', $values).")";
return execute($sql);
}
四、总结与建议
- 框架层面:建立统一的输入输出处理机制
- 开发层面:制定严格的安全编码规范
- 审计层面:重点关注:
- 直接使用
$GLOBALS/$_GET/$_POST的地方 - 数组键名直接用于SQL拼接的地方
- 过滤后执行解码操作的地方
- 直接使用
- 运维层面:关闭
magic_quotes_gpc,统一由应用层处理
通过系统化的安全防护策略和严格的编码规范,可以有效避免此类SQL注入漏洞的产生。