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@121380 c90b9560-bf6c-de11-be94-00142212c4b1
1268 lines
51 KiB
XML
1268 lines
51 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!-- $Revision: 1.52 $ -->
|
|
<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 with some general security advice, explains
|
|
the different configuration option combinations and the situations
|
|
they can be safely used, and describes different considerations in
|
|
coding for different levels of security.
|
|
</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-bin">
|
|
<title>Installed as CGI binary</title>
|
|
|
|
<sect2 id="security.cgi-bin.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-bin.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-bin.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">
|
|
<![CDATA[
|
|
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-bin.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-bin.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>
|
|
<![CDATA[
|
|
#!/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/passwd, 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">
|
|
<![CDATA[
|
|
<?php
|
|
// remove a file from the user's home directory
|
|
$username = $_POST['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">
|
|
<![CDATA[
|
|
<?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">
|
|
<![CDATA[
|
|
<?php
|
|
// removes a file from the hard drive that
|
|
// the PHP user has access to.
|
|
$username = $_SERVER['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">
|
|
<![CDATA[
|
|
<?php
|
|
$username = $_SERVER['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.database">
|
|
<title>Database Security</title>
|
|
|
|
<simpara>
|
|
Nowadays, databases are cardinal components of any web based application by
|
|
enabling websites to provide varying dynamic content. Since very sensitive
|
|
or secret informations can be stored in such database, you should strongly
|
|
consider to protect them somehow.
|
|
</simpara>
|
|
<simpara>
|
|
To retrieve or to store any information you need to connect to the database,
|
|
send a legitimate query, fetch the result, and close the connecion.
|
|
Nowadays, the commonly used query language in this interaction is the
|
|
Structured Query Language (SQL). See how an attacker can <link
|
|
linkend="security.database.sql-injection">tamper with an SQL query</link>.
|
|
</simpara>
|
|
<simpara>
|
|
As you can realize, PHP cannot protect your database by itself. The
|
|
following sections aim to be an introduction into the very basics of how to
|
|
access and manipulate databases within PHP scripts.
|
|
</simpara>
|
|
<simpara>
|
|
Keep in mind this simple rule: defence in depth. In the more place you
|
|
take the more action to increase the protection of your database, the less
|
|
probability of that an attacker succeeds, and exposes or abuse any stored
|
|
secret information. Good design of the database schema and the application
|
|
deals with your greatest fears.
|
|
</simpara>
|
|
|
|
<sect2 id="security.database.design">
|
|
<title>Designing Databases</title>
|
|
<simpara>
|
|
The first step is always to create the database, unless you want to use
|
|
an existing third party's one. When a database is created, it is
|
|
assigned to an owner, who executed the creation statement. Usually, only
|
|
the owner (or a superuser) can do anything with the objects in that
|
|
database, and in order to allow other users to use it, privileges must be
|
|
granted.
|
|
</simpara>
|
|
<simpara>
|
|
Applications should never connect to the database as its owner or a
|
|
superuser, because these users can execute any query at will, for
|
|
example, modifying the schema (e.g. dropping tables) or deleting its
|
|
entire content.
|
|
</simpara>
|
|
<simpara>
|
|
You may create different database users for every aspect of your
|
|
application with very limited rights to database objects. The most
|
|
required privileges should be granted only, and avoid that the same user
|
|
can interact with the database in different use cases. This means that if
|
|
intruders gain access to your database using one of these credentials,
|
|
they can only effect as many changes as your application can.
|
|
</simpara>
|
|
<simpara>
|
|
You are encouraged not to implement all the business logic in the web
|
|
application (i.e. your script), instead to do it in the database schema
|
|
using views, triggers or rules. If the system evolves, new ports will be
|
|
intended to open to the database, and you have to reimplement the logic
|
|
in each separate database client. Over and above, triggers can be used
|
|
to transparently and automatically handle fields, which often provides
|
|
insight when debugging problems with your application or tracing back
|
|
transactions.
|
|
</simpara>
|
|
</sect2>
|
|
|
|
<sect2 id="security.database.connection">
|
|
<title>Connecting to Database</title>
|
|
<simpara>
|
|
You may want to estabilish the connections over SSL to encrypt
|
|
client/server communications for increased security, or you can use ssh
|
|
to encrypt the network connection between clients and the database server.
|
|
If either of them is done, then monitoring your traffic and gaining
|
|
informations in this way will be a hard work.
|
|
</simpara>
|
|
<!--simpara>
|
|
If your database server has native SSL support, consider to use <link
|
|
linkend="ref.openssl">OpenSSL functions</link> in communication between
|
|
PHP and database via SSL.
|
|
</simpara-->
|
|
</sect2>
|
|
|
|
<sect2 id="security.database.storage">
|
|
<title>Encrypted Storage Model</title>
|
|
<simpara>
|
|
SSL/SSH protects data travelling from the client to the server, SSL/SSH
|
|
does not protect the persistent data stored in a database. SSL is an
|
|
on-the-wire protocol.
|
|
</simpara>
|
|
<simpara>
|
|
Once an attacker gains access to your database directly (bypassing the
|
|
webserver), the stored sensitive data may be exposed or misused, unless
|
|
the information is protected by the database itself. Encrypting the data
|
|
is a good way to mitigate this threat, but very few databases offer this
|
|
type of data encryption.
|
|
</simpara>
|
|
<simpara>
|
|
The easiest way to work around this problem is to first create your own
|
|
encryption package, and then use it from within your PHP scripts. PHP
|
|
can assist you in this case with its several extensions, such as <link
|
|
linkend="ref.mcrypt">Mcrypt</link> and <link
|
|
linkend="ref.mhash">Mhash</link>, covering a wide variety of encryption
|
|
algorithms. The script encrypts the data be stored first, and decrypts
|
|
it when retrieving. See the references for further examples how
|
|
encryption works.
|
|
</simpara>
|
|
<simpara>
|
|
In case of truly hidden data, if its raw representation is not needed
|
|
(i.e. not be displayed), hashing may be also taken into consideration.
|
|
The well-known example for the hashing is storing the MD5 hash of a
|
|
password in a database, instead of the password itself. See also
|
|
<function>crypt</function> and <function>md5</function>.
|
|
</simpara>
|
|
<example>
|
|
<title>Using hashed password field</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
// storing password hash
|
|
$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
|
|
addslashes($username), md5($password));
|
|
$result = pg_exec($connection, $query);
|
|
|
|
// querying if user submitted the right password
|
|
$query = sprintf("SELECT 1 FROM users WHERE name='%s' AND pwd='%s';",
|
|
addslashes($username), md5($password));
|
|
$result = pg_exec($connection, $query);
|
|
|
|
if (pg_numrows($result) > 0) {
|
|
echo "Welcome, $username!";
|
|
}
|
|
else {
|
|
echo "Authentication failed for $username.";
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</sect2>
|
|
|
|
<sect2 id="security.database.sql-injection">
|
|
<title>SQL Injection</title>
|
|
<simpara>
|
|
Many web developers are unaware of how SQL queries can be tampered with,
|
|
and assume that an SQL query is a trusted command. It means that SQL
|
|
queries are able to circumvent access controls, thereby bypassing standard
|
|
authentication and authorization checks, and sometimes SQL queries even
|
|
may allow access to host operating system level commands.
|
|
</simpara>
|
|
<simpara>
|
|
Direct SQL Command Injection is a technique where an attacker creates or
|
|
alters existing SQL commands to expose hidden data, or to override valuable
|
|
ones, or even to execute dangerous system level commands on the database
|
|
host. This is accomplished by the application taking user input and
|
|
combining it with static parameters to build a SQL query. The following
|
|
examples are based on true stories, unfortunately.
|
|
</simpara>
|
|
<para>
|
|
Owing to the lack of input validation and connecting to the database on
|
|
behalf of a superuser or the one who can create users, the attacker
|
|
may create a superuser in your database.
|
|
<example>
|
|
<title>
|
|
Splitting the result set into pages ... and making superusers
|
|
(PostgreSQL and MySQL)
|
|
</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
$offset = argv[0]; // beware, no input validation!
|
|
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
|
|
// with PostgreSQL
|
|
$result = pg_exec($conn, $query);
|
|
// with MySQL
|
|
$result = mysql_query($query);
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
Normal users click on the 'next', 'prev' links where the <varname>$offset</varname>
|
|
is encoded into the URL. The script expects that the incoming
|
|
<varname>$offset</varname> is decimal number. However, someone tries to
|
|
break in with appending <function>urlencode</function>'d form of the
|
|
following to the URL
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
// in case of PostgreSQL
|
|
0;
|
|
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
|
|
select 'crack', usesysid, 't','t','crack'
|
|
from pg_shadow where usename='postgres';
|
|
--
|
|
|
|
// in case of MySQL
|
|
0;
|
|
UPDATE user SET Password=PASSWORD('crack') WHERE user='root';
|
|
FLUSH PRIVILEGES;
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
If it happened, then the script would present a superuser access to him.
|
|
Note that <literal>0;</literal> is to supply a valid offset to the
|
|
original query and to terminate it.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
It is common technique to force the SQL parser to ignore the rest of the
|
|
query written by the developer with <literal>--</literal> which is the
|
|
comment sign in SQL.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
A feasible way to gain passwords is to circumvent your search result pages.
|
|
What the attacker needs only is to try if there is any submitted variable
|
|
used in SQL statement which is not handled properly. These filters can be set
|
|
commonly in a preceding form to customize <literal>WHERE, ORDER BY,
|
|
LIMIT</literal> and <literal>OFFSET</literal> clauses in <literal>SELECT</literal>
|
|
statements. If your database supports the <literal>UNION</literal> construct,
|
|
the attacker may try to append an entire query to the original one to list
|
|
passwords from an arbitrary table. Using encrypted password fields is
|
|
strongly encouraged.
|
|
<example>
|
|
<title>
|
|
Listing out articles ... and some passwords (any database server)
|
|
</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
$query = "SELECT id, name, inserted, size FROM products
|
|
WHERE size = '$size'
|
|
ORDER BY $order LIMIT $limit, $offset;";
|
|
$result = odbc_exec($conn, $query);
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
The static part of the query can be combined with another
|
|
<literal>SELECT</literal> statement which reveals all passwords:
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
'
|
|
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
|
|
--
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
If this query (playing with the <literal>'</literal> and
|
|
<literal>--</literal>) were assigned to one of the variables used in
|
|
<varname>$query</varname>, the query beast awakened.
|
|
</para>
|
|
<para>
|
|
SQL UPDATEs are also subject to attacking your database. These queries are
|
|
also threatened by chopping and appending an entirely new query to it. But
|
|
the attacker might fiddle with the <literal>SET</literal> clause. In this
|
|
case some schema information must be possessed to manipulate the query
|
|
successfully. This can be acquired by examing the form variable names, or
|
|
just simply brute forcing. There are not so many naming convention for
|
|
fields storing passwords or usernames.
|
|
<example>
|
|
<title>
|
|
From resetting a password ... to gaining more privileges (any database server)
|
|
</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
But a malicious user sumbits the value
|
|
<literal>' or uid like'%admin%'; --</literal> to <varname>$uid</varname> to
|
|
change the admin's password, or simply sets <varname>$pwd</varname> to
|
|
<literal>"hehehe', admin='yes', trusted=100 "</literal> (with a trailing
|
|
space) to gain more privileges. Then, the query will be twisted:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
// $uid == ' or uid like'%admin%'; --
|
|
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
|
|
|
|
// $pwd == "hehehe', admin='yes', trusted=100 "
|
|
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;"
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
A frightening example how operating system level commands can be accessed
|
|
on some database hosts.
|
|
<example>
|
|
<title>Attacking the database host's operating system (MSSQL Server)</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
|
|
$result = mssql_query($query);
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
If attacker submits the value
|
|
<literal>a%' exec master..xp_cmdshell 'net user test testpass /ADD' --</literal>
|
|
to <varname>$prod</varname>, then the <varname>$query</varname> will be:
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
$query = "SELECT * FROM products
|
|
WHERE id LIKE '%a%'
|
|
exec master..xp_cmdshell 'net user test testpass /ADD'--";
|
|
$result = mssql_query($query);
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
MSSQL Server executes the SQL statements in the batch including a command
|
|
to add a new user to the local accounts database. If this application
|
|
were running as <literal>sa</literal> and the MSSQLSERVER service is
|
|
running with sufficient privileges, the attacker would now have an
|
|
account with which to access this machine.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Some of the examples above is tied to a specific database server. This
|
|
does not mean that a similar attack is impossible against other products.
|
|
Your database server may be so vulnerable in other manner.
|
|
</para>
|
|
</note>
|
|
|
|
<sect3 id="security.database.avoiding">
|
|
<title>Avoiding techniques</title>
|
|
<simpara>
|
|
You may plead that the attacker must possess a piece of information
|
|
about the database schema in most examples. You are right, but you
|
|
never know when and how it can be taken out, and if it happens,
|
|
your database may be exposed. If you are using an open source, or
|
|
publicly available database handling package, which may belong to a
|
|
content management system or forum, the intruders easily produce
|
|
a copy of a piece of your code. It may be also a security risk if it
|
|
is a poorly designed one.
|
|
</simpara>
|
|
<simpara>
|
|
These attacks are mainly based on exploiting the code not being written
|
|
with security in mind. Never trust on any kind of input, especially
|
|
which comes from the client side, even though it comes from a select box,
|
|
a hidden input field or a cookie. The first example shows that such a
|
|
blameless query can cause disasters.
|
|
</simpara>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>
|
|
Never connect to the database as a superuser or as the database owner.
|
|
Use always customized users with very limited privileges.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Check if the given input has the expected data type. PHP has
|
|
a wide range of input validating functions, from the simplest ones
|
|
found in <link linkend="ref.variables">Variable Functions</link> and
|
|
in <link linkend="ref.ctype">Character Type Functions</link>
|
|
(e.g. <function>is_numeric</function>, <function>ctype_digit</function>
|
|
respectively) onwards the
|
|
<link linkend="ref.pcre">Perl compatible Regular Expressions</link>
|
|
support.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If the application waits for numerical input, consider to verify data
|
|
with <function>is_numeric</function>, or silently change its type
|
|
using <function>settype</function>, or use its numeric representation
|
|
by <function>sprintf</function>.
|
|
<example>
|
|
<title>A more secure way to compose a query for paging</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
settype($offset, 'integer');
|
|
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
|
|
|
|
// please note %d in the format string, using %s would be meaningless
|
|
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
|
|
$offset);
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Quote each non numeric user input which is passed to the database with
|
|
<function>addslashes</function> or <function>addcslashes</function>.
|
|
See <link linkend="security.database.storage">the first example</link>.
|
|
As the examples shows, quotes burnt into the static part of the query
|
|
is not enough, and can be easily hacked.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
Do not print out any database specific information, especially
|
|
about the schema, by fair means or foul. See also <link
|
|
linkend="security.errors">Error Reporting</link> and <link
|
|
linkend="ref.errorfunc">Error Handling and Logging Functions</link>.
|
|
</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>
|
|
You may use stored procedures and previously defined cursors to abstract
|
|
data access so that users do not directly access tables or views, but
|
|
this solution has another impacts.
|
|
</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<simpara>
|
|
Besides these, you benefit from logging queries either within your script
|
|
or by the database itself, if it supports. Obviously, the logging is unable
|
|
to prevent any harmful attempt, but it can be helpful to trace back which
|
|
application has been circumvented. The log is not useful by itself, but
|
|
through the information it contains. The more detail is generally better.
|
|
</simpara>
|
|
</sect3>
|
|
</sect2>
|
|
</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">
|
|
<![CDATA[
|
|
<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">
|
|
<![CDATA[
|
|
<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">
|
|
<![CDATA[
|
|
<?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
|
|
readfile ("/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 with register_globals=on</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?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,
|
|
readfile ("/highly/sensitive/data/index.html");
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<example>
|
|
<title>Working with register_globals = off</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
if($_COOKIE['username']){
|
|
// can only come from a cookie, forged or otherwise
|
|
$good_login = 1;
|
|
readfile ("/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">
|
|
<![CDATA[
|
|
<?php
|
|
if ($_COOKIE['username'] &&
|
|
!$_POST['username'] &&
|
|
!$_GET['username'] ) {
|
|
// Perform other checks to validate the user name...
|
|
$good_login = 1;
|
|
readfile ("/highly/sensitive/data/index.html");
|
|
} else {
|
|
mail("admin@example.com", "Possible breakin attempt", $_SERVER['REMOTE_ADDR']);
|
|
echo "Security violation, admin has been alerted.";
|
|
exit;
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
Of course, simply turning off 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">
|
|
<![CDATA[
|
|
<?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/passwd 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>
|
|
In general, security by obscurity is one of the weakest forms of security.
|
|
But in some cases, every little bit of extra security is desirable.
|
|
</para>
|
|
<para>
|
|
A few simple techniques can help to hide PHP, possibly slowing
|
|
down an attacker who is attempting to discover 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="apache-conf">
|
|
<![CDATA[
|
|
# 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="apache-conf">
|
|
<![CDATA[
|
|
# 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="apache-conf">
|
|
<![CDATA[
|
|
# 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
|
|
indent-tabs-mode:nil
|
|
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
|
|
-->
|