PHP框架中的安全要素
本文源于阅读阅读InitPHP框架源码时的总结,先多谢InitPHP的开源。
互联网火热,开发迭代快速,但是不能忽略了网络安全,特别是涉及个人信息和在线交易的一些平台。
信息安全无非是涉及两个端口的安全:一个是信息的入口安全(需要对输入系统的数据先进行一下过滤处理,避免一些不安全的数据录入到数据库,造成数据库数据的损坏)。二个是输出过滤。(对输出的变量进行过滤,避免不需要的,影响安全的脚本被输出到页面上去。)
在InitPHP 框架中,作者从以下几方面做了保护信息安全的工作。可以说涵盖了一个框架对安全问题的所有关注。非常值得学习,这里做一下摘录。
1.全局Filter机制。
内置了fliter()函数对$_GET、$_PSOT、$_COOKIE、$_SERVICE等容易被攻击的全局变量进行了过滤,框架执行时自动加载,对所有入口变量进行过滤。
2.提供丰富的过滤函数。
内部提供了过滤javascript,css,iframes,object等不安全参数的函数。
3.统一获取GET POST数据,并进行默认的过滤。
使用get_gp函数默认会过滤数据。
4.CSRF风险控制。
内置了公用的TOKEN机制,在框架运行的时候就能生成用户的唯一TOKEN,用户每次打开浏览器访问网站的TOKEN都是不同的。
5.XSS风险控制。
XSS防范主要是输出过滤。将输出到模板上的PHP变量都进行HTML过滤。
6.SQL安全问题防范。
提供了一整套SQL安全机制:sql_build和常用DB操作函数,一般的DB操作都可以使用我们提供的方法来实现。
----------------------------------------------------------------分隔线--------------------------------------------------------------------------------------------
1.全局Filter机制。
InitPHP框架内置了fliter()函数对$_GET、$_PSOT、$_COOKIE、$_SERVICE等容易被攻击的全局变量进行了过滤
fliter()函数在框架运行的时候会自动加载执行
代码:
 
/** * 安全过滤类-全局变量过滤 * 在Controller初始化的时候已经运行过该变量,对全局变量进行处理 * Controller中使用方法:$this->controller->fliter() * @return */ public function fliter() { if (is_array($_SERVER)) { foreach ($_SERVER as $k => $v) { if (isset($_SERVER[$k])) { $_SERVER[$k] = str_replace(array('<','>','"',"'",'%3C','%3E','%22','%27','%3c','%3e'), '', $v); } } } unset($_ENV, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS, $HTTP_ENV_VARS); self::fliter_slashes($_GET); self::fliter_slashes($_POST); self::fliter_slashes($_COOKIE); self::fliter_slashes($_FILES); self::fliter_slashes($_REQUEST); } /* 运行的时候执行 */ /** * 初始化控制器, */ public function __construct() { $this->fliter(); $this->set_token(); //生成全局TOKEN值,防止CRsf攻击 }
2.丰富的过滤函数。
 
/* 一部分类 */ /** * 安全过滤类-加反斜杠,放置SQL注入 * Controller中使用方法:$this->controller->fliter_slashes(&$value) * @param string $value 需要过滤的值 * @return string */ public static function fliter_slashes(&$value) { if (get_magic_quotes_gpc()) return false; //开启魔术变量 $value = (array) $value; foreach ($value as $key => $val) { if (is_array($val)) { self::fliter_slashes($value[$key]); } else { $value[$key] = addslashes($val); } } } /** * 安全过滤类-过滤javascript,css,iframes,object等不安全参数 过滤级别高 * Controller中使用方法:$this->controller->fliter_script($value) * @param string $value 需要过滤的值 * @return string */ public function fliter_script($value) { $value = preg_replace("/(javascript:)?on(click|load|key|mouse|error|abort|move|unload|change|dblclick|move|reset|resize|submit)/i","&111n\\2",$value); $value = preg_replace("/(.*?)<\/script>/si","",$value); $value = preg_replace("/(.*?)<\/iframe>/si","",$value); $value = preg_replace ("//iesU", '', $value); return $value; }
3.统一的get_gp函数,获取GET或者POST数据。
不建议用户使用$_GET和$_POST的方法获取GET或者POST数据
get_gp函数默认会过滤数据
该函数还提供数组获取方法,可以获取多个数据
 
/** * 安全过滤类-获取GET或者POST的参数值,经过过滤 * 如果不指定$type类型,则获取同名的,POST优先 * $isfliter 默认开启,强制转换请求的数据 * 该方法在Controller层中,获取所有GET或者POST数据,都需要走这个接口 * Controller中使用方法:$this->controller->get_gp($value, $type = null, $isfliter = true) * @param string|array $value 参数 * @param string|array $type 获取GET或者POST参数,P - POST , G - GET * @param bool $isfliter 变量是否过滤 * @return string|array */ public function get_gp($value, $type = null, $isfliter = true) { if (!is_array($value)) { if ($type === null) { if (isset($_GET[$value])) $temp = $_GET[$value]; if (isset($_POST[$value])) $temp = $_POST[$value]; } else { $temp = (strtoupper($type) == 'G') ? $_GET[$value] : $_POST[$value]; } $temp = ($isfliter === true) ? $this->fliter_escape($temp) : $temp; return $temp; } else { $temp = array(); foreach ($value as $val) { if ($type === null) { if (isset($_GET[$val])) $temp[$val] = $_GET[$val]; if (isset($_POST[$val])) $temp[$val] = $_POST[$val]; } else { $temp[$val] = (strtoupper($type) == 'G') ? $_GET[$val] : $_POST[$val]; } $temp[$val] = ($isfliter === true) ? $this->fliter_escape($temp[$val]) : $temp[$val]; } return $temp; } }
4.CSRF风险控制。
InitPHP框架内置了公用的TOKEN机制,在框架运行的时候就能生成用户的唯一TOKEN,用户每次打开浏览器访问网站的TOKEN都是不同的
你需要做的是:在你的POST和GET请求的地方,添加上TOKEN,然后在你的Action中验证TOKEN是否正确
 
/* TOKEN实现 */ /** * 类加载-获取全局TOKEN,防止CSRF攻击 * Controller中使用方法:$this->controller->get_token() * @return */ public function get_token() { return $_COOKIE['init_token']; } /** * 类加载-检测token值 * Controller中使用方法:$this->controller->check_token($ispost = true) * @return */ public function check_token($ispost = true) { if ($ispost && !$this->is_post()) return false; if ($this->get_gp('init_token') !== $this->get_token()) return false; return true; } /** * 类加载-设置全局TOKEN,防止CSRF攻击 * Controller中使用方法:$this->controller->set_token() * @return */ private function set_token() { if (!$_COOKIE['init_token']) { $str = substr(md5(time(). $this->get_useragent()), 5, 8); setcookie("init_token", $str); $_COOKIE['init_token'] = $str; } } /* 框架运行的时候生成TOKEN 和 模板赋值TOKEN */ /** * 初始化控制器, */ public function __construct() { $this->fliter(); $this->set_token(); //生成全局TOKEN值,防止CRsf攻击 } /** * 初始化 */ public function __construct() { global $InitPHP_conf; $this->controller = $this->load('controller', 'c'); //导入Controller $this->view = $this->load('view', 'v'); //导入View $this->view->set_template_config($InitPHP_conf['template']); //设置模板 $this->view->assign('init_token', $this->controller->get_token()); //全局输出init_token标记 } /* 如何使用:*/ GET方式提交-在URL或者GET提交上面,添加init_token= http://127.0.0.1/?init_token= POST的方法,用一个隐藏表单 表单名称init_token 值: 然后在Action中 $this->controller->check_token(); 来验证token是否一致
5.XSS风险控制。
XSS防范主要是输出过滤。将输出到模板上的PHP变量都进行HTML过滤
InitPHP开发框架提供两种方式:模板输出的时候对全局进行过滤;提供InitPHP::output()输出过滤函数
采用全局变量输出过滤的方式,需要开启配置:$InitPHP_conf['isviewfilter']
InitPHP::output()函数也可以还原已经被HTML过滤过的变量
 
/* 全局输出过滤 */ /** * 模板-显示视图 * 1. 在Controller中需要显示模板,就必须调用该函数 * 2. 模板解析可以设置 $InitPHP_conf['isviewfilter'] 值,对变量进行过滤 * Controller中使用方法:$this->view->display(); * @return array */ public function display() { global $InitPHP_conf; if (is_array($this->view)) { if ($InitPHP_conf['isviewfilter']) $this->out_put($this->view); //输出过滤 foreach ($this->view as $key => $val) { $$key = $val; } } $this->template_arr = $this->parse_template_arr($this->template_arr); //模板设置 foreach ($this->template_arr as $file_name) { if (in_array($file_name, $this->remove_tpl_arr)) continue; $complie_file_name = $this->template_run($file_name); //模板编译 if (!file_exists($complie_file_name)) InitPHP::initError($complie_file_name. ' is not exist!'); include_once($complie_file_name); } } /* 手工输出InitPHP::output函数 */ /** * 【静态】XSS过滤,输出内容过滤 * 1. 框架支持全局XSS过滤机制-全局开启将消耗PHP运行 * 2. 手动添加XSS过滤函数,在模板页面中直接调用 * 全局使用方法:InitPHP::output($string, $type = 'encode'); * @param string $string 需要过滤的字符串 * @param string $type encode HTML处理 | decode 反处理 * @return string */ public static function output($string, $type = 'encode') { $html = array("&", '"', "'", "<", ">"); $html_code = array("&", """, "'", "<", ">"); if ($type == 'encode') { if (function_exists('htmlspecialchars')) return htmlspecialchars($string); return str_replace($html, $html_code, $string); } else { if (function_exists('htmlspecialchars_decode')) return htmlspecialchars_decode($string); return str_replace($html_code, $html, $string); } }
6.SQL安全。
如果你的SQL语句出现了问题,那么黑客很容易攻破你的网站
InitPHP框架提供了一整套SQL安全机制:sql_build和常用DB操作函数
一般情况下你的DB操作我们提供的DB操作函数能满足你的需求了
如果你自己写SQL语句,并且SQL语句中包含变量,请用sql_build提供的相关函数组装SQL语句
 
public function get_one($id, $table_name, $id_key = 'id') { $id = (int) $id; if ($id < 1) return array(); $where = $this->build_where(array($id_key=>$id)); //组装函数 $sql = sprintf("SELECT * FROM %s %s LIMIT 1", $table_name, $where); $result = $this->query($sql, false); if (!$result) return false; $r = $this->fetch_assoc($result); $this->set_default_link_id(); //设置默认的link_id return $r; }
上面六个方面涵盖了一个框架应该考虑的安全问题。自己设计框架的时候可以考虑做参考。


 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号