PHP安全 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
学习目标: 一些提高安全的方法: 1、Register Globals register_globals 参数在 PHP 的 4.2.0 及以上版本中默认为屏蔽。虽然这并不认为是一个安全漏洞,但是的确是一个安全风险。因此,应该始终在开发过程和运行环境中屏蔽 register_globals。 } if($authorized) } ?> 当参数 register_globals 开启的时候,这个页面可以使用 ?authorized=1 的参数访问,从而绕过访问控制。当然,这个明显的漏洞是糟糕的开发造成的,而不是 register_globals 的原因,但是这明显增加了产生危险漏洞的可能。消除了这个影响,普通的全局变量(比如本例中的 $authorized)将不再受到客户端提交的数据的影响。最好的方式是初始化全部变量并且在开发时将参数 error_reporting 设置为 E_ALL,这样使用未初始化的变量就不会在开发的时候被忽略。 <?php include "$path/script.php"; ?> $mod = isset ($_GET['mod']) ? $_GET['mod'] : 'index'; If (in_array ($mod,array ('school','qq'))){ Include $mod.'.class.php'; } 当参数 register_globals 开启的时候,这个页面可以使用 ?path=http%3A%2F%2Fevil.example.org%2F%3F 的参数访问,使得本例中的代码和下面的代码等同: <?php include ''; ?> 如果参数 allow_url_fopen 开启的时候(即便是在 php.ini-recommended 中,默认也是开启的),这将如同包含本地文件一般包含 这样的远程文件。这是一个常见的安全漏洞,甚至在一些非常著名的开源项目中都发现。 初始化 $path 可以避免这个隐患,而且不用屏蔽参数 register_globals 。然而开发人员的失误可能会产生没有初始化的变量,修改全局配置以屏蔽参数 register_globals 可以尽可能的避免这种隐患被忽视。 2、错误报告 从早期的版本到 2004 年 7 月 13 日发布的 PHP 5,错误报告都是相当简单的。除了小心编写程序,还要留意一些特定的 PHP 配置项目: error_reporting 这个项目设置了错误报告的等级。开发环境中,强烈建议将这个参数设置为 E_ALL。 运行环境中,也建议设置为E_ALL。 display_errors 这个项目决定是否将错误显示在屏幕上(包含在输出中)。应当在开发中设置为 On,这样可以在开发时就发现错误;应当在运行环境中设置为 Off,这样在所有用户(和潜在攻击者)面前错误将被隐藏。 log_errors 这个项目决定是否将错误写入日志。虽然这会引起性能损失,但是对于并不经常出现的错误这是非常必要的。如果在硬盘上记录错误带来了巨大的 I/O 负荷,比起应用程序的效率来说,这或许应当引起更多的注意。应当在开发环境和运行环境中设置为 On。 error_log 这个项目决定了日志文件存放的位置和名字。一定要确保 web 服务器对指定文件拥有权限。 设置 error_reporting 为 E_ALL 对于强制初始化变量有帮助,因为使用一个未定义的变量会产生提示(notice)。 一个非常好的错误处理和报告函数在 PHP 手册中有所介绍: PHP 5 包含异常处理。了解更多信息,请查阅: 对各种可能的情况,进行充分测试,找到并排除错误。 3、数据过滤 使用正则表达式来检查电子邮件、网址、电话、用户名等信息。 相关详细说明
4、欺骗表单提交 为了进一步了解数据过滤的必要,思考下面这个表单(假想的): : <select name="color"> <option value="red">red</option> <option value="green">green</option> <option value="blue">blue</option> </select> <input type="submit" /> </form> 设想一个攻击者保存了这段 HTML 并修改为: <form action="" method="POST"> <input type="text" name="color" /> <input type="submit" /> 这个新的表单可以存放在任何地方(web 服务器并不是必须的,只要浏览器可以访问的即可),并可以随意使用。action 属性设定的绝对 URL 将 POST 请求发到相同的地方。 进一步,可以通过域名判断: <?php echo $_SERVER['HTTP_REFERER'];?>可以得到链接/提交当前页的父页面URL.另外,可以使用一些简单的问题来实现验证的作用,比如出一个这样的问题: 5、目录及文件安全 有这样一个文件,保存了数据库的相关信息: 这个例子包含连接到数据库的全部信息,并保存为文件 db.inc。它在一个文件里保存了帐户信息,这看起来是非常省心的。问题出现在这个文件保存在在根文档(document root)下面的某个地方。这是非常普通的,因为这样使用 include 和 require 语句更加简单。但是这也将导致暴露你的数据库帐户信息。 一定要记住,在根文档(document root)下的所有东西都有一个 URL 与之关联。例如,如果根文档(document root)在 /usr/local/apache/htdocs,当一个文件存储在 /usr/local/apache/htdocs/inc/db.inc 时,则可以通过 URL 访问到它。 mysql_escape_string (PHP 4 >= 4.0.3, PHP 5, PECL mysql:1.0) mysql_escape_string — 转义一个字符串用于 mysql_query 说明 string mysql_escape_string ( string $unescaped_string ) 本函数将 unescaped_string 转义,使之可以安全用于 mysql_query()。 Note: mysql_escape_string() 并不转义 % 和 _。 本函数和 mysql_real_escape_string() 完全一样,除了 mysql_real_escape_string() 接受的是一个连接句柄并根据当前字符集转移字符串之外。mysql_escape_string() 并不接受连接参数,也不管当前字符集设定。 Example#1 mysql_escape_string() 例子 <?php $item = "Zak's Laptop"; $escaped_item = mysql_escape_string($item); printf ("Escaped string: %s ", $escaped_item); ?> 以上例子将产生如下输出: Escaped string: Zak's Laptop <?php ?> 这个语句由 $_POST 构成,这是毫无疑问的。 假设这个语句创建了一个新帐号。用户提供了想要的用户名和邮件帐号。注册程序产生临时的密码并发送邮件到用户处用于验证邮件地址。设想用户输入下面的内容作为用户名:('good_guybad_guy', 'mypass', ''), 这当然不是一个合法的用户名,但是关键的地方没有数据过滤,应用程序无法判断。如果提供一个合法的邮件地址(例如 shiflett@php.net),而应用程序生成密码为 1234,SQL 语句将变为: <?php $sql = "INSERT INTO users (reg_username, reg_password, reg_email) VALUES ('bad_guy', 'mypass', ''), ('good_guy', '1234', 'shiflett@php.net')"; ?> 除了用合法的邮件地址创建了一个帐号(good_guy),应用程序还创建了第二个帐号(bad_guy),用户提供了所有关于这个帐号的信息。 虽然这个特殊的例子看起来并没有什么很大的伤害,不过一旦攻击者可以修改 SQL 语句会造成多么大的损失也是相当明确的。 $str = "'"; $sql = "SELECT * FROM `message` WHERE 1 "; $sql .= "AND `content` LIKE '%".addslashes_deep($str)."%' "; $res = $db->getAll($sql); echo '<pre>'; print_r ($res); echo '</pre>'; 8、PHP的safe mode模式 safe_mode是唯一PHP_INI_SYSTEM属性,必须通过php.ini或httpd.conf来设置。要启用safe_mode,只需修改php.ini: safe_mode = On 或者修改httpd.conf,定义目录: Options FollowSymLinks php_admin_value safe_mode 1 重启apache后safe_mode就生效了。启动safe_mode,会对许多PHP函数进行限制,特别是和系统相关的文件打开、命令执行等函数。 默认情况下,所有操作文件的函数将只能操作与脚本UID相同的文件。 9、权限认证 ajax调用的PHP程序,也要进行权限判断。 10、禁用PHP的一些系统操作相关的函数 这个选项是从PHP-4.3.2开始才有的,它可以禁用某些类,如果有多个用逗号分隔类名。disable_classes也不能在httpd.conf里设置,只能在php.ini配置文件里修改。 12、open_basedir 14、上传文件 上传文件时,应判断上传文件的类型(判断文件的后缀,并要判断文件的type)。 上传文件后,应将文件重新命名,不要使用上传之前的文件名。 15、清除HTML或JavaScript 16、不要在运行的站点上保留phpinfo()脚本 18、尽量使用POST而不是GET方式提交数据 其他程序安全措施: session_save_path 当然,PHP的安全并不等于整个网站的安全,整个网站的安全,还涉及到:
|