84669 person learning
152542 person learning
20005 person learning
5487 person learning
7821 person learning
359900 person learning
3350 person learning
180660 person learning
48569 person learning
18603 person learning
40936 person learning
1549 person learning
1183 person learning
32909 person learning
本人新手,在《PHP安全编码》中提到“不要直接使用$_GET”,同时又提到“可以尝试在php.ini中开启magic_quotes_gpc,这样对于所有由用户GET、POST、COOKIE中传入的特殊字符都会转义”,我很纠结,是否开启magic_quotes_gpc就可以直接使用$_GET?
如下面例子中的代码本人感觉很不安全,因为没有做验证,但又不知道如何改进,希望大神能帮忙,谢谢。
学习是最好的投资!
你是想要filter_input函数,多看手册:
http://www.w3school.com.cn/php/func_filter_input.asp
纯数字的参数intval强制取整 其他参数值进行过滤或者转义 protected function zaddslashes($string, $force = 0, $strip = FALSE) { if (!defined('MAGIC_QUOTES_GPC')) { define('MAGIC_QUOTES_GPC', ''); } if (!MAGIC_QUOTES_GPC || $force) { if (is_array($string)) { foreach ($string as $key => $val) { $string[$key] = $this->zaddslashes($val, $force, $strip); } } else { $string = ($strip ? stripslashes($string) : $string); $string = htmlspecialchars($string); } } return $string; }
我一般都对$_POST $_GET都使用zaddslashes,然后整数的参数值进行取整,防止XSS和SQL注入
HTTP头信息:IP、浏览器信息、等也进行转义过滤防止HTTP头注入
magic_quotes_gpc开启后会影响图片上传等,自动将内容引号转义
注意PHP5.5包括之后已经将magic_quotes_gpc配置废弃
除此之外,最好在服务器方面也做关键词过滤,Mysql为业务使用到的库创建用户和赋权
可以把自己应用放服务器上,装个sqlmap注入下自己试试,以上几点做到一般情况下不会被搞,至少不会被getshell
乌云白帽子路过...
1. 像用户名这种有格式的东西,应该取到之后马上用正则表达式验证,比如preg_match('/\A\w{6,14}\z/', $user)就验证了它是不是6~14位的数字字母下划线。不要使用系统自带的filter,那个管不了什么用。
preg_match('/\A\w{6,14}\z/', $user)
2. 不要使用mysql开头的函数,要使用mysqli,而且最好进行参数化查询而不是addslashes,后者会有编码问题。
mysql
mysqli
addslashes
3. 输出html的时候,默认使用htmlspecialchars,这个函数可以指定编码。或者你可以用现成的模板引擎。
htmlspecialchars
4. 比较字符串的时候,强制使用strcmp,不要使用双等号。
strcmp
5. 不要使用$_REQUEST。
$_REQUEST
这样可以防掉95%。至于magic_quotes_gpc,应该早就废了吧。
magic_quotes_gpc
现在市面上这些书真的害人不浅,随便下结论或者是楼主没有仔细读。为什么直接使用 $_GET $_POST 不安全?
看了楼主的例子,应该是直接将$_GET 用在拼接SQL上,这样肯定是不安全的,所以核心信息应该是:直接将 $_GET/$_POST等用户输入的内容用于SQL拼接是不安全的,如何避免?
例如:
sqlselect * from user where username= "$_GET['username']"
sql
select * from user where username= "$_GET['username']"
如果用户提交的username 为
sql" 0 or true or username ="
" 0 or true or username ="
那么就会变成这样:
sqlselect * from user where username = "0" or true or username=""
select * from user where username = "0" or true or username=""
那么会返回所有的用户记录。当然这里只是粗暴的举了一个例子。实际上要做XSS要熟知代码或者猜测到运行的逻辑等了解很多东西。
最简单的过滤方法是使用 mysql_real_escape_string 函数
至于 magic_quotes,是php最失败的一个改进,现已废弃,就算是低版本的PHP也一定要关闭它。
如果 $_GET首先判断是否为空然后对值进行判断举个例子:只接受数字 那就使用 php自带函数 is_numeric
一般 GET 也只是传递某个标识总之在数据库或其他操作之前 先验证 传过来的变量 是否为自己预期的值
可以先对post或者get请求过滤,php有内置函数进行过滤,然后在使用
同意二楼的要有一个过滤,不过只是系统自带的肯定不行,最好自己再根据情况做一个过滤等之类的处理。
防止XSS攻击,最简单粗暴的做法就是用htmlspecialchars把特殊字符(&,",',<,>)转换为HTML实体(&"'<>)后输出.
&,",',<,>
&"'<>
防止XSS攻击,最复杂的就是自己写正则过滤,不过还好有HTMLPurifier库,除了能过滤XSS代码,还能把不完整的标签补全或者去掉.Yii框架也用到了这个XSS过滤库.http://htmlpurifier.org/download
purify($html);
上面说的是防御XSS,下面说防御SQL注入:PDO和MySQLi等都提供有绑定参数查询的功能,而绑定参数的目的就是防止SQL注入.http://php.net/manual/zh/pdo.prepared-statements.php
很多更成熟的数据库都支持预处理语句的概念.什么是预处理语句?可以把它看作是想要运行的SQL的一种编译过的模板,它可以使用变量参数进行定制.预处理语句可以带来两大好处:1.查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次.当查询准备好后,数据库将分析/编译/优化执行该查询的计划.对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度.通过使用预处理语句,可以避免重复分析/编译/优化周期.简言之,预处理语句占用更少的资源,因而运行得更快.2.提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理.如果应用程序只使用预处理语句,可以确保不会发生SQL注入.然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在SQL注入的风险.
预处理语句如此有用,以至于它们唯一的特性是在驱动程序不支持的时候,PDO将模拟处理.这样可以确保不管数据库是否具有这样的功能,都可以确保应用程序可以用相同的数据访问模式.
prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindParam(':calories', $calories, PDO::PARAM_INT); $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12); $sth->execute();
上面参与查询的变量$calories被绑定为整型,$colour被绑定为长度为12个字符的字符串型.MySQLi里同样提供有像PDO bindParam一样的bind_param,这时就不需要用addslashes,mysqli_real_escape_string之类的函数了,也不需要依赖magic_quotes_gpc配置了(该配置从PHP5.4开始已经被移除).用PDO操作MySQL时注意禁用模拟预处理,这样才会使用真正的预处理,这样才能确保程序先发送SQL模板给MySQL编译,然后再传参数过去执行,这样可以确保这些参数不被SQL注入.MySQLi扩展的预处理默认就是真正的预处理.
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
这些都可以通过MySQL的general_log日志或者WireShark观察到.
prepare('SELECT * FROM users WHERE username = ?'); $stmt->bind_param('s', $_GET['username']); //s表示用户名被绑定为字符串型,整型用i. $stmt->execute();
对于一些要求是整型的参数,其实还可以直接用intval($calories)拿到整型值.
intval($calories)
如果你要验证和过滤一些用户输入的数据,又不想自己写正则表达式,那就可以用filter_input/filter_var函数,比如验证邮箱,IP等:http://php.net/manual/zh/filter.filters.php
我来回答个无关的:Are PDO prepared statements sufficient to prevent SQL injection?
PDO是否可以防住SQL注入。
建议你先看看joomla-framework的input类库,地址在这里或者先把joomla-framework的input类库在你的代码中使用(前期就不要考虑性能之类的问题),先搞明白对于$_GET(包括$_POST、$_FILES、$_COOKIE等)要进行怎样的处理,然后在以后的使用过程中自己选择是否实现简单版本。
你是想要filter_input函数,多看手册:
http://www.w3school.com.cn/php/func_filter_input.asp
我一般都对$_POST $_GET都使用zaddslashes,然后整数的参数值进行取整,防止XSS和SQL注入
HTTP头信息:IP、浏览器信息、等也进行转义过滤防止HTTP头注入
magic_quotes_gpc开启后会影响图片上传等,自动将内容引号转义
注意PHP5.5包括之后已经将magic_quotes_gpc配置废弃
除此之外,最好在服务器方面也做关键词过滤,Mysql为业务使用到的库创建用户和赋权
可以把自己应用放服务器上,装个sqlmap注入下自己试试,以上几点做到一般情况下不会被搞,至少不会被getshell
乌云白帽子路过...
1. 像用户名这种有格式的东西,应该取到之后马上用正则表达式验证,比如
preg_match('/\A\w{6,14}\z/', $user)
就验证了它是不是6~14位的数字字母下划线。不要使用系统自带的filter,那个管不了什么用。2. 不要使用
mysql
开头的函数,要使用mysqli
,而且最好进行参数化查询而不是addslashes
,后者会有编码问题。3. 输出html的时候,默认使用
htmlspecialchars
,这个函数可以指定编码。或者你可以用现成的模板引擎。4. 比较字符串的时候,强制使用
strcmp
,不要使用双等号。5. 不要使用
$_REQUEST
。这样可以防掉95%。至于
magic_quotes_gpc
,应该早就废了吧。现在市面上这些书真的害人不浅,随便下结论或者是楼主没有仔细读。为什么直接使用 $_GET $_POST 不安全?
看了楼主的例子,应该是直接将$_GET 用在拼接SQL上,这样肯定是不安全的,所以核心信息应该是:直接将 $_GET/$_POST等用户输入的内容用于SQL拼接是不安全的,如何避免?
例如:
如果用户提交的username 为
那么就会变成这样:
那么会返回所有的用户记录。当然这里只是粗暴的举了一个例子。实际上要做XSS要熟知代码或者猜测到运行的逻辑等了解很多东西。
最简单的过滤方法是使用 mysql_real_escape_string 函数
至于 magic_quotes,是php最失败的一个改进,现已废弃,就算是低版本的PHP也一定要关闭它。
如果 $_GET
首先判断是否为空
然后对值进行判断
举个例子:
只接受数字 那就使用 php自带函数 is_numeric
一般 GET 也只是传递某个标识
总之在数据库或其他操作之前 先验证 传过来的变量 是否为自己预期的值
可以先对post或者get请求过滤,php有内置函数进行过滤,然后在使用
同意二楼的要有一个过滤,不过只是系统自带的肯定不行,最好自己再根据情况做一个过滤等之类的处理。
防止XSS攻击,最简单粗暴的做法就是用htmlspecialchars把特殊字符(
&,",',<,>
)转换为HTML实体(&"'<>
)后输出.防止XSS攻击,最复杂的就是自己写正则过滤,不过还好有HTMLPurifier库,除了能过滤XSS代码,还能把不完整的标签补全或者去掉.Yii框架也用到了这个XSS过滤库.
http://htmlpurifier.org/download
上面说的是防御XSS,下面说防御SQL注入:
PDO和MySQLi等都提供有绑定参数查询的功能,而绑定参数的目的就是防止SQL注入.
http://php.net/manual/zh/pdo.prepared-statements.php
预处理语句如此有用,以至于它们唯一的特性是在驱动程序不支持的时候,PDO将模拟处理.
这样可以确保不管数据库是否具有这样的功能,都可以确保应用程序可以用相同的数据访问模式.
上面参与查询的变量$calories被绑定为整型,$colour被绑定为长度为12个字符的字符串型.
MySQLi里同样提供有像PDO bindParam一样的bind_param,这时就不需要用addslashes,mysqli_real_escape_string之类的函数了,也不需要依赖magic_quotes_gpc配置了(该配置从PHP5.4开始已经被移除).
用PDO操作MySQL时注意禁用模拟预处理,这样才会使用真正的预处理,这样才能确保程序先发送SQL模板给MySQL编译,然后再传参数过去执行,这样可以确保这些参数不被SQL注入.MySQLi扩展的预处理默认就是真正的预处理.
这些都可以通过MySQL的general_log日志或者WireShark观察到.
对于一些要求是整型的参数,其实还可以直接用
intval($calories)
拿到整型值.如果你要验证和过滤一些用户输入的数据,又不想自己写正则表达式,那就可以用filter_input/filter_var函数,比如验证邮箱,IP等:
http://php.net/manual/zh/filter.filters.php
我来回答个无关的:
Are PDO prepared statements sufficient to prevent SQL injection?
PDO是否可以防住SQL注入。
建议你先看看
joomla-framework的input类库,地址在这里
或者先把joomla-framework的input类库在你的代码中使用(前期就不要考虑性能之类的问题),先搞明白对于$_GET(包括$_POST、$_FILES、$_COOKIE等)要进行怎样的处理,然后在以后的使用过程中自己选择是否实现简单版本。