mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-16 17:08:54 +00:00

git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@61229 c90b9560-bf6c-de11-be94-00142212c4b1
815 lines
33 KiB
XML
815 lines
33 KiB
XML
<?xml encoding="iso-8859-1"?>
|
|
<!-- $Revision: 1.30 $ -->
|
|
<chapter id="security">
|
|
<title>Security</title>
|
|
|
|
<simpara>
|
|
PHP is a powerful language and the interpreter, whether included
|
|
in a web server as a module or executed as a separate
|
|
<acronym>CGI</acronym> binary, is able to access files, execute
|
|
commands and open network connections on the server. These
|
|
properties make anything run on a web server insecure by default.
|
|
PHP is designed specifically to be a more secure language for
|
|
writing CGI programs than Perl or C, and with correct selection of
|
|
compile-time and runtime configuration options, and proper coding
|
|
practices, it can give you exactly the combination of freedom and
|
|
security you need.
|
|
</simpara>
|
|
<simpara>
|
|
As there are many different ways of utilizing PHP, there are many
|
|
configuration options controlling its behaviour. A large
|
|
selection of options guarantees you can use PHP for a lot of
|
|
purposes, but it also means there are combinations of these
|
|
options and server configurations that result in an insecure
|
|
setup.
|
|
</simpara>
|
|
<simpara>
|
|
The configuration flexibility of PHP is equally rivalled by the
|
|
code flexibility. PHP can be used to build complete server
|
|
applications, with all the power of a shell user, or it can be used
|
|
for simple server-side includes with little risk in a tightly
|
|
controlled environment. How you build that environment, and how
|
|
secure it is, is largely up to the PHP developer.
|
|
</simpara>
|
|
<simpara>
|
|
This chapter starts by explaining the different configuration
|
|
option combinations and the situations they can be safely used. It
|
|
then describes different considerations in coding for different
|
|
levels of security, and ends with some general security advice.
|
|
</simpara>
|
|
|
|
<sect1 id="security.general">
|
|
<title>General considerations</title>
|
|
<simpara>
|
|
A completely secure system is a virtual impossibility, so an
|
|
approach often used in the security profession is one of balancing
|
|
risk and usability. If every variable submitted by a user required
|
|
two forms of biometric validation (such as a retinal scan and a
|
|
fingerprint), you would have an extremely high level of
|
|
accountability. It would also take half an hour to fill out a fairly
|
|
complex form, which would tend to encourage users to find ways of
|
|
bypassing the security.
|
|
</simpara>
|
|
<simpara>
|
|
The best security is often inobtrusive enough to suit the
|
|
requirements without the user being prevented from accomplishing
|
|
their work, or over-burdening the code author with excessive
|
|
complexity. Indeed, some security attacks are merely exploits of
|
|
this kind of overly built security, which tends to erode over time.
|
|
</simpara>
|
|
<simpara>
|
|
A phrase worth remembering: A system is only as good as the weakest
|
|
link in a chain. If all transactions are heavily logged based on
|
|
time, location, transaction type, etc. but the user is only
|
|
verified based on a single cookie, the validity of tying the users
|
|
to the transaction log is severely weakened.
|
|
</simpara>
|
|
<simpara>
|
|
When testing, keep in mind that you will not be able to test all
|
|
possibilities for even the simplest of pages. The input you
|
|
may expect will be completely unrelated to the input given by
|
|
a disgruntled employee, a cracker with months of time on their
|
|
hands, or a housecat walking across the keyboard. This is why it's
|
|
best to look at the code from a logical perspective, to discern
|
|
where unexpected data can be introduced, and then follow how it is
|
|
modified, reduced, or amplified.
|
|
</simpara>
|
|
<simpara>
|
|
The Internet is filled with people trying to make a name for
|
|
themselves by breaking your code, crashing your site, posting
|
|
inappropriate content, and otherwise making your day interesting.
|
|
It doesn't matter if you have a small or large site, you are
|
|
a target by simply being online, by having a server that can be
|
|
connected to. Many cracking programs do not discern by size, they
|
|
simply trawl massive IP blocks looking for victims. Try not to
|
|
become one.
|
|
</simpara>
|
|
</sect1>
|
|
|
|
<sect1 id="security.cgi">
|
|
<title>Installed as CGI binary</title>
|
|
|
|
<sect2 id="security.cgi.attacks">
|
|
<title>Possible attacks</title>
|
|
<simpara>
|
|
Using PHP as a <acronym>CGI</acronym> binary is an option for
|
|
setups that for some reason do not wish to integrate PHP as a
|
|
module into server software (like Apache), or will use PHP with
|
|
different kinds of CGI wrappers to create safe chroot and setuid
|
|
environments for scripts. This setup usually involves installing
|
|
executable PHP binary to the web server cgi-bin directory. CERT
|
|
advisory <ulink url="&url.cert;">CA-96.11</ulink> recommends
|
|
against placing any interpreters into cgi-bin. Even if the PHP
|
|
binary can be used as a standalone interpreter, PHP is designed
|
|
to prevent the attacks this setup makes possible:
|
|
</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
Accessing system files: <filename
|
|
role="url">http://my.host/cgi-bin/php?/etc/passwd</filename>
|
|
</simpara>
|
|
<simpara>
|
|
The query information in a url after the question mark (?) is
|
|
passed as command line arguments to the interpreter by the CGI
|
|
interface. Usually interpreters open and execute the file
|
|
specified as the first argument on the command line.
|
|
</simpara>
|
|
<simpara>
|
|
When invoked as a CGI binary, PHP refuses to interpret the
|
|
command line arguments.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Accessing any web document on server: <filename
|
|
role="url">http://my.host/cgi-bin/php/secret/doc.html</filename>
|
|
</simpara>
|
|
<simpara>
|
|
The path information part of the url after the PHP binary name,
|
|
<filename role="uri">/secret/doc.html</filename> is
|
|
conventionally used to specify the name of the file to be
|
|
opened and interpreted by the <acronym>CGI</acronym> program.
|
|
Usually some web server configuration directives (Apache:
|
|
Action) are used to redirect requests to documents like
|
|
<filename
|
|
role="url">http://my.host/secret/script.php</filename> to the
|
|
PHP interpreter. With this setup, the web server first checks
|
|
the access permissions to the directory <filename
|
|
role="uri">/secret</filename>, and after that creates the
|
|
redirected request <filename
|
|
role="url">http://my.host/cgi-bin/php/secret/script.php</filename>.
|
|
Unfortunately, if the request is originally given in this form,
|
|
no access checks are made by web server for file <filename
|
|
role="uri">/secret/script.php</filename>, but only for the
|
|
<filename role="uri">/cgi-bin/php</filename> file. This way
|
|
any user able to access <filename
|
|
role="uri">/cgi-bin/php</filename> is able to access any
|
|
protected document on the web server.
|
|
</simpara>
|
|
<simpara>
|
|
In PHP, compile-time configuration option <link
|
|
linkend="install.configure.enable-force-cgi-redirect">--enable-force-cgi-redirect</link>
|
|
and runtime configuration directives <link
|
|
linkend="ini.doc-root">doc_root</link> and <link
|
|
linkend="ini.user-dir">user_dir</link> can be used to prevent
|
|
this attack, if the server document tree has any directories
|
|
with access restrictions. See below for full the explanation
|
|
of the different combinations.
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
<sect2 id="security.cgi.default">
|
|
<title>Case 1: only public files served</title>
|
|
|
|
<simpara>
|
|
If your server does not have any content that is not restricted
|
|
by password or ip based access control, there is no need for
|
|
these configuration options. If your web server does not allow
|
|
you to do redirects, or the server does not have a way to
|
|
communicate to the PHP binary that the request is a safely
|
|
redirected request, you can specify the option <link
|
|
linkend="install.configure.enable-force-cgi-redirect">--enable-force-cgi-redirect</link>
|
|
to the configure script. You still have to make sure your PHP
|
|
scripts do not rely on one or another way of calling the script,
|
|
neither by directly <filename
|
|
role="php">http://my.host/cgi-bin/php/dir/script.php</filename>
|
|
nor by redirection <filename
|
|
role="php">http://my.host/dir/script.php</filename>.
|
|
</simpara>
|
|
<simpara>
|
|
Redirection can be configured in Apache by using AddHandler and
|
|
Action directives (see below).
|
|
</simpara>
|
|
</sect2>
|
|
|
|
<sect2 id="security.cgi.force-redirect">
|
|
<title>Case 2: using --enable-force-cgi-redirect</title>
|
|
<simpara>
|
|
This compile-time option prevents anyone from calling PHP
|
|
directly with a url like <filename
|
|
role="php">http://my.host/cgi-bin/php/secretdir/script.php</filename>.
|
|
Instead, PHP will only parse in this mode if it has gone through
|
|
a web server redirect rule.
|
|
</simpara>
|
|
<simpara>
|
|
Usually the redirection in the Apache configuration is done with
|
|
the following directives:
|
|
</simpara>
|
|
<programlisting role="apache-conf">
|
|
Action php-script /cgi-bin/php
|
|
AddHandler php-script .php
|
|
</programlisting>
|
|
<simpara>
|
|
This option has only been tested with the Apache web server, and
|
|
relies on Apache to set the non-standard CGI environment variable
|
|
<envar>REDIRECT_STATUS</envar> on redirected requests. If your
|
|
web server does not support any way of telling if the request is
|
|
direct or redirected, you cannot use this option and you must use
|
|
one of the other ways of running the CGI version documented
|
|
here.
|
|
</simpara>
|
|
</sect2>
|
|
|
|
<sect2 id="security.cgi.doc-root">
|
|
<title>Case 3: setting doc_root or user_dir</title>
|
|
<simpara>
|
|
To include active content, like scripts and executables, in the
|
|
web server document directories is sometimes consider an insecure
|
|
practice. If, because of some configuration mistake, the scripts
|
|
are not executed but displayed as regular HTML documents, this
|
|
may result in leakage of intellectual property or security
|
|
information like passwords. Therefore many sysadmins will prefer
|
|
setting up another directory structure for scripts that are
|
|
accessible only through the PHP CGI, and therefore always
|
|
interpreted and not displayed as such.
|
|
</simpara>
|
|
<simpara>
|
|
Also if the method for making sure the requests are not
|
|
redirected, as described in the previous section, is not
|
|
available, it is necessary to set up a script doc_root that is
|
|
different from web document root.
|
|
</simpara>
|
|
<simpara>
|
|
You can set the PHP script document root by the configuration
|
|
directive <link linkend="ini.doc-root">doc_root</link> in the
|
|
<link linkend="configuration.file">configuration file</link>, or
|
|
you can set the environment variable
|
|
<envar>PHP_DOCUMENT_ROOT</envar>. If it is set, the CGI version
|
|
of PHP will always construct the file name to open with this
|
|
<parameter>doc_root</parameter> and the path information in the
|
|
request, so you can be sure no script is executed outside this
|
|
directory (except for <parameter>user_dir</parameter>
|
|
below).
|
|
</simpara>
|
|
<simpara>
|
|
Another option usable here is <link
|
|
linkend="ini.user-dir">user_dir</link>. When user_dir is unset,
|
|
only thing controlling the opened file name is
|
|
<parameter>doc_root</parameter>. Opening an url like <filename
|
|
role="url">http://my.host/~user/doc.php</filename> does not
|
|
result in opening a file under users home directory, but a file
|
|
called <filename role="uri">~user/doc.php</filename> under
|
|
doc_root (yes, a directory name starting with a tilde
|
|
[<literal>~</literal>]).
|
|
</simpara>
|
|
<simpara>
|
|
If user_dir is set to for example <filename
|
|
role="dir">public_php</filename>, a request like <filename
|
|
role="url">http://my.host/~user/doc.php</filename> will open a
|
|
file called <filename>doc.php</filename> under the directory
|
|
named <filename role="dir">public_php</filename> under the home
|
|
directory of the user. If the home of the user is <filename
|
|
role="dir">/home/user</filename>, the file executed is
|
|
<filename>/home/user/public_php/doc.php</filename>.
|
|
</simpara>
|
|
<simpara>
|
|
<parameter>user_dir</parameter> expansion happens regardless of
|
|
the <parameter>doc_root</parameter> setting, so you can control
|
|
the document root and user directory access
|
|
separately.
|
|
</simpara>
|
|
</sect2>
|
|
|
|
<sect2 id="security.cgi.shell">
|
|
<title>Case 4: PHP parser outside of web tree</title>
|
|
<para>
|
|
A very secure option is to put the PHP parser binary somewhere
|
|
outside of the web tree of files. In <filename
|
|
role="dir">/usr/local/bin</filename>, for example. The only real
|
|
downside to this option is that you will now have to put a line
|
|
similar to:
|
|
<informalexample>
|
|
<programlisting>
|
|
#!/usr/local/bin/php
|
|
</programlisting>
|
|
</informalexample>
|
|
as the first line of any file containing PHP tags. You will also
|
|
need to make the file executable. That is, treat it exactly as
|
|
you would treat any other CGI script written in Perl or sh or any
|
|
other common scripting language which uses the
|
|
<literal>#!</literal> shell-escape mechanism for launching
|
|
itself.
|
|
</para>
|
|
<para>
|
|
To get PHP to handle <envar>PATH_INFO</envar> and
|
|
<envar>PATH_TRANSLATED</envar> information correctly with this
|
|
setup, the php parser should be compiled with the <link
|
|
linkend="install.configure.enable-discard-path">--enable-discard-path</link>
|
|
configure option.
|
|
</para>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="security.apache">
|
|
<title>Installed as an Apache module</title>
|
|
<simpara>
|
|
When PHP is used as an Apache module it inherits Apache's user
|
|
permissions (typically those of the "nobody" user). This has several
|
|
impacts on security and authorization. For example, if you are using
|
|
PHP to access a database, unless that database has built-in access
|
|
control, you will have to make the database accessable to the
|
|
"nobody" user. This means a malicious script could access and modify
|
|
the database, even without a username and password. It's entirely
|
|
possible that a web spider could stumble across a database
|
|
administrator's web page, and drop all of your databases. You can
|
|
protect against this with Apache authorization, or you can design
|
|
your own access model using LDAP, .htaccess files, etc. and include
|
|
that code as part of your PHP scripts.
|
|
</simpara>
|
|
<simpara>
|
|
Often, once security is established to the point where the PHP user
|
|
(in this case, the apache user) has very little risk attached to it,
|
|
it is discovered that PHP is now prevented from writing any files
|
|
to user directories. Or perhaps it has been prevented from accessing
|
|
or changing databases. It has equally been secured from writing
|
|
good and bad files, or entering good and bad database transactions.
|
|
</simpara>
|
|
<simpara>
|
|
A frequent security mistake made at this point is to allow apache
|
|
root permissions, or to escalate apache's abilitites in some other
|
|
way.
|
|
</simpara>
|
|
<simpara>
|
|
Escalating the Apache user's permissions to root is extremely
|
|
dangerous and may compromise the entire system, so sudo'ing,
|
|
chroot'ing, or otherwise running as root should not be considered by
|
|
those who are not security professionals.
|
|
</simpara>
|
|
<simpara>
|
|
There are some simpler solutions. By using
|
|
<link linkend="ini.open-basedir">open_basedir</link> you can control and restrict what
|
|
directories are allowed to be used for PHP. You can also set up
|
|
apache-only areas, to restrict all web based activity to non-user,
|
|
or non-system, files.
|
|
</simpara>
|
|
</sect1>
|
|
|
|
<sect1 id="security.filesystem">
|
|
<title>Filesystem Security</title>
|
|
<simpara>
|
|
PHP is subject to the security built into most server systems with
|
|
respect to permissions on a file and directory basis. This allows
|
|
you to control which files in the filesystem may be read. Care
|
|
should be taken with any files which are world readable to ensure
|
|
that they are safe for reading by all users who have access to that
|
|
filesystem.
|
|
</simpara>
|
|
<simpara>
|
|
Since PHP was designed to allow user level access to the filesystem,
|
|
it's entirely possible to write a PHP script that will allow you
|
|
to read system files such as /etc/password, modify your ethernet
|
|
connections, send massive printer jobs out, etc. This has some
|
|
obvious implications, in that you need to ensure that the files
|
|
that you read from and write to are the appropriate ones.
|
|
</simpara>
|
|
<simpara>
|
|
Consider the following script, where a user indicates that they'd
|
|
like to delete a file in their home directory. This assumes a
|
|
situation where a PHP web interface is regularly used for file
|
|
management, so the Apache user is allowed to delete files in
|
|
the user home directories.
|
|
</simpara>
|
|
<para>
|
|
<example>
|
|
<title>Poor variable checking leads to....</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
// remove a file from the user's home directory
|
|
$username = $HTTP_POST_VARS['user_submitted_name'];
|
|
$homedir = "/home/$username";
|
|
$file_to_delete = "$userfile";
|
|
unlink ($homedir/$userfile);
|
|
echo "$file_to_delete has been deleted!";
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
Since the username is postable from a user form, they can submit
|
|
a username and file belonging to someone else, and delete files.
|
|
In this case, you'd want to use some other form of authentication.
|
|
Consider what could happen if the variables submitted were
|
|
"../etc/" and "passwd". The code would then effectively read:
|
|
<example>
|
|
<title>... A filesystem attack</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
// removes a file from anywhere on the hard drive that
|
|
// the PHP user has access to. If PHP has root access:
|
|
$username = "../etc/";
|
|
$homedir = "/home/../etc/";
|
|
$file_to_delete = "passwd";
|
|
unlink ("/home/../etc/passwd");
|
|
echo "/home/../etc/passwd has been deleted!";
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
There are two important measures you should take to prevent these
|
|
issues.
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
Only allow limited permissions to the PHP web user binary.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Check all variables which are submitted.
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
Here is an improved script:
|
|
<example>
|
|
<title>More secure file name checking</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
// removes a file from the hard drive that
|
|
// the PHP user has access to.
|
|
$username = $HTTP_SERVER_VARS['REMOTE_USER']; // using an authentication mechanisim
|
|
|
|
$homedir = "/home/$username";
|
|
|
|
$file_to_delete = basename("$userfile"); // strip paths
|
|
unlink ($homedir/$file_to_delete);
|
|
|
|
$fp = fopen("/home/logging/filedelete.log","+a"); //log the deletion
|
|
$logstring = "$username $homedir $file_to_delete";
|
|
fputs ($fp, $logstring);
|
|
fclose($fp);
|
|
|
|
echo "$file_to_delete has been deleted!";
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
However, even this is not without it's flaws. If your authentication
|
|
system allowed users to create their own user logins, and a user
|
|
chose the login "../etc/", the system is once again exposed. For
|
|
this reason, you may prefer to write a more customized check:
|
|
<example>
|
|
<title>More secure file name checking</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
$username = $HTTP_SERVER_VARS['REMOTE_USER']; // using an authentication mechanisim
|
|
$homedir = "/home/$username";
|
|
|
|
if (!ereg('^[^./][^/]*$', $userfile))
|
|
die('bad filename'); //die, do not process
|
|
|
|
if (!ereg('^[^./][^/]*$', $username))
|
|
die('bad username'); //die, do not process
|
|
//etc...
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Depending on your operating system, there are a wide variety of files
|
|
which you should be concerned about, including device entries (/dev/
|
|
or COM1), configuration files (/etc/ files and the .ini files),
|
|
well known file storage areas (/home/, My Documents), etc. For this
|
|
reason, it's usually easier to create a policy where you forbid
|
|
everything except for what you explicitly allow.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="security.errors">
|
|
<title>Error Reporting</title>
|
|
<para>
|
|
With PHP security, there are two sides to error reporting. One is
|
|
beneficial to increasing security, the other is detrimental.
|
|
</para>
|
|
<para>
|
|
A standard attack tactic involves profiling a system by feeding
|
|
it improper data, and checking for the kinds, and contexts, of the
|
|
errors which are returned. This allows the system cracker to probe
|
|
for information about the server, to determine possible weaknesses.
|
|
For example, if an attacker had gleaned information about a page
|
|
based on a prior form submission, they may attempt to override
|
|
variables, or modify them:
|
|
<example>
|
|
<title>Attacking Variables with a custom HTML page</title>
|
|
<programlisting role="php">
|
|
<form method="post" action="attacktarget?username=badfoo&password=badfoo">
|
|
<input type="hidden" name="username" value="badfoo">
|
|
<input type="hidden" name="password" value="badfoo">
|
|
</form>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The PHP errors which are normally returned can be quite helpful to a
|
|
developer who is trying to debug a script, indicating such things
|
|
as the function or file that failed, the PHP file it failed in,
|
|
and the line number which the failure occured in. This is all
|
|
information that can be exploited. It is not uncommon for a php
|
|
developer to use <function>show_source</function>,
|
|
<function>highlight_string</function>, or
|
|
<function>highlight_file</function> as a debugging measure, but in
|
|
a live site, this can expose hidden variables, unchecked syntax,
|
|
and other dangerous information. Especially dangerous is running
|
|
code from known sources with built-in debugging handlers, or using
|
|
common debugging techniques. If the attacker can determine what
|
|
general technique you are using, they may try to brute-force a page,
|
|
by sending various common debugging strings:
|
|
<example>
|
|
<title>Exploiting common debugging variables</title>
|
|
<programlisting role="php">
|
|
<form method="post" action="attacktarget?errors=Y&showerrors=1"&debug=1">
|
|
<input type="hidden" name="errors" value="Y">
|
|
<input type="hidden" name="showerrors" value="1">
|
|
<input type="hidden" name="debug" value="1">
|
|
</form>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
Regardless of the method of error handling, the ability to probe a
|
|
system for errors leads to providing an attacker with more
|
|
information.
|
|
</para>
|
|
<para>
|
|
For example, the very style of a generic PHP error indicates a system
|
|
is running PHP. If the attacker was looking at an .html page, and
|
|
wanted to probe for the back-end (to look for known weaknesses in
|
|
the system), by feeding it the wrong data they may be able to
|
|
determine that a system was built with PHP.
|
|
</para>
|
|
<para>
|
|
A function error can indicate whether a system may be running a
|
|
specific database engine, or give clues as to how a web page or
|
|
programmed or designed. This allows for deeper investigation into
|
|
open database ports, or to look for specific bugs or weaknesses
|
|
in a web page. By feeding different pieces of bad data, for example,
|
|
an attacker can determine the order of authentication in a script,
|
|
(from the line number errors) as well as probe for exploits that
|
|
may be exploited in different locations in the script.
|
|
</para>
|
|
<para>
|
|
A filesystem or general PHP error can indicate what permissions
|
|
the webserver has, as well as the structure and organization of
|
|
files on the web server. Developer written error code can aggravate
|
|
this problem, leading to easy exploitation of formerly "hidden"
|
|
information.
|
|
</para>
|
|
<para>
|
|
There are three major solutions to this issue. The first is to
|
|
scrutinize all functions, and attempt to compensate for the bulk
|
|
of the errors. The second is to disable error reporting entirely
|
|
on the running code. The third is to use PHP's custom error
|
|
handling functions to create your own error handler. Depending
|
|
on your security policy, you may find all three to be applicable
|
|
to your situation.
|
|
</para>
|
|
<para>
|
|
One way of catching this issue ahead of time is to make use of
|
|
PHP's own <function>error_reporting</function>, to help you
|
|
secure your code and find variable usage that may be dangerous.
|
|
By testing your code, prior to deployment, with E_ALL, you can
|
|
quickly find areas where your variables may be open to poisoning
|
|
or modification in other ways. Once you are ready for deployment,
|
|
by using E_NONE, you insulate your code from probing.
|
|
<example>
|
|
<title>Finding dangerous variables with E_ALL</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
if ($username) { // Not initialized or checked before usage
|
|
$good_login = 1;
|
|
}
|
|
if ($good_login == 1) { // If above test fails, not initialized or checked before usage
|
|
fpassthru ("/highly/sensitive/data/index.html");
|
|
}
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="security.registerglobals">
|
|
<title>Using Register Globals</title>
|
|
<para>
|
|
One feature of PHP that can be used to enhance security is configuring PHP with
|
|
<link linkend="ini.register-globals">register_globals</link> = off.
|
|
By turning off the ability for any user-submitted variable to be injected
|
|
into PHP code, you can reduce the amount of variable
|
|
poisoning a potential attacker may inflict. They will have
|
|
to take the additional time to forge submissions, and your
|
|
internal variables are effectively isolated from user
|
|
submitted data.
|
|
</para>
|
|
<para>
|
|
While it does slightly increase the amount of effort required
|
|
to work with PHP, it has been argued that the benefits far
|
|
outweigh the effort.
|
|
<example>
|
|
<title>Working without register_globals=off</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
if ($username) { // can be forged by a user in get/post/cookies
|
|
$good_login = 1;
|
|
}
|
|
|
|
if ($good_login == 1) { // can be forged by a user in get/post/cookies,
|
|
fpassthru ("/highly/sensitive/data/index.html");
|
|
}
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
<example>
|
|
<title>Working with register_globals = off</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
if($HTTP_COOKIE_VARS['username']){
|
|
// can only come from a cookie, forged or otherwise
|
|
$good_login = 1;
|
|
fpassthru ("/highly/sensitive/data/index.html");
|
|
}
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
By using this wisely, it's even possible to take preventative
|
|
measures to warn when forging is being attempted. If you know
|
|
ahead of time exactly where a variable should be coming from,
|
|
you can check to see if submitted data is coming from an
|
|
inappropriate kind of submission. While it doesn't guarantee
|
|
that data has not been forged, it does require an attacker
|
|
to guess the right kind of forging.
|
|
<example>
|
|
<title>Detecting simple variable poisoning</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
if ($HTTP_COOKIE_VARS['username'] &&
|
|
!$HTTP_POST_VARS['username'] &&
|
|
!$HTTP_GET_VARS['username'] ) {
|
|
// Perform other checks to validate the user name...
|
|
$good_login = 1;
|
|
fpassthru ("/highly/sensitive/data/index.html");
|
|
} else {
|
|
mail("admin@example.com", "Possible breakin attempt", $HTTP_SERVER_VARS['REMOTE_ADDR']);
|
|
echo "Security violation, admin has been alerted.";
|
|
exit;
|
|
}
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
Of course, simply turning on register globals does not mean code
|
|
is secure. For every piece of data that is submitted, it
|
|
should also be checked in other ways.
|
|
</para>
|
|
</sect1>
|
|
|
|
|
|
<sect1 id="security.variables">
|
|
<title>User Submitted Data</title>
|
|
<para>
|
|
The greatest weakness in many PHP programs is not inherent in the
|
|
language itself, but merely an issue of code not being written with
|
|
security in mind. For this reason, you should always take the time
|
|
to consider the implications of a given piece of code, to ascertain
|
|
the possible damage if an unexpected variable is submitted to it.
|
|
<example>
|
|
<title>Dangerous Variable Usage</title>
|
|
<programlisting role="php">
|
|
<?php
|
|
// remove a file from the user's home directory... or maybe
|
|
// somebody else's?
|
|
unlink ($evil_var);
|
|
|
|
// Write logging of their access... or maybe an /etc/password entry?
|
|
fputs ($fp, $evil_var);
|
|
|
|
// Execute something trivial.. or rm -rf *?
|
|
system ($evil_var);
|
|
exec ($evil_var);
|
|
|
|
?>
|
|
</programlisting>
|
|
</example>
|
|
You should always carefully examine your code to make sure that any
|
|
variables being submitted from a web browser are being properly
|
|
checked, and ask yourself the following questions:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
Will this script only affect the intended files?
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Can unusual or undesirable data be acted upon?
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Can this script be used in unintended ways?
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Can this be used in conjunction with other scripts in a negative
|
|
manner?
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Will any transactions be adequately logged?
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
By adequately asking these questions while writing the script,
|
|
rather than later, you prevent an unfortunate re-write when you
|
|
need to increase your security. By starting out with this mindset,
|
|
you won't guarantee the security of your system, but you can help
|
|
improve it.
|
|
</para>
|
|
<para>
|
|
You may also want to consider turning off register_globals,
|
|
magic_quotes, or other convenience settings which may confuse
|
|
you as to the validity, source, or value of a given variable.
|
|
Working with PHP in error_reporting(E_ALL) mode can also help warn
|
|
you about variables being used before they are checked or
|
|
initialized (so you can prevent unusual data from being
|
|
operated upon).
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="security.hiding">
|
|
<title>Hiding PHP</title>
|
|
<para>
|
|
A few simple techniques can help to hide PHP, possibly slowing
|
|
down an attacker who is attempting to disover weaknesses in your
|
|
system. By setting expose_php = off in your php.ini file, you
|
|
reduce the amount of information available to them.
|
|
</para>
|
|
<para>
|
|
Another tactic is to configure web servers such as apache to
|
|
parse different filetypes through PHP, either with an .htaccess
|
|
directive, or in the apache configuration file itself. You can
|
|
then use misleading file extensions:
|
|
<example>
|
|
<title>Hiding PHP as another language</title>
|
|
<programlisting role="php">
|
|
# Make PHP code look like other code types
|
|
AddType application/x-httpd-php .asp .py .pl
|
|
</programlisting>
|
|
</example>
|
|
Or obscure it completely:
|
|
<example>
|
|
<title>Using unknown types for PHP extensions</title>
|
|
<programlisting role="php">
|
|
# Make PHP code look like unknown types
|
|
AddType application/x-httpd-php .bop .foo .133t
|
|
</programlisting>
|
|
</example>
|
|
Or hide it as html code, which has a slight performance hit because
|
|
all html will be parsed through the PHP engine:
|
|
<example>
|
|
<title>Using html types for PHP extensions</title>
|
|
<programlisting role="php">
|
|
# Make all PHP code look like html
|
|
AddType application/x-httpd-php .htm .html
|
|
</programlisting>
|
|
</example>
|
|
For this to work effectively, you must rename your PHP files with
|
|
the above extensions. While it is a form of security through
|
|
obscurity, it's a minor preventative measure with few drawbacks.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="security.current">
|
|
<title>Keeping Current</title>
|
|
<simpara>
|
|
PHP, like any other large system, is under constant scrutiny and
|
|
improvement. Each new version will often include both major and
|
|
minor changes to enhance and repair security flaws, configuration
|
|
mishaps, and other issues that will affect the overall security
|
|
and stability of your system.
|
|
</simpara>
|
|
<simpara>
|
|
Like other system-level scripting languages and programs, the best
|
|
approach is to update often, and maintain awareness of the latest
|
|
versions and their changes.
|
|
</simpara>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"../../manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|