PHP

advertisement
http://nz2.php.net/manual/en/security.errors.php
Standard attack tactic
• One of the initial steps any attacker would do would be to
try and get some information on what programming
language you’re using in your website.
• feed the system with improper data
• check for the kinds, and contexts, of the errors
which are returned
• Moreover, they would try to investigate the structure and
organisation of your files in the webserver, bugs and
weaknesses, permissions the webserver has, order of
authentication, etc.
• By feeding it with the wrong data and looking at the
response of your web application, they may be able to
determine that a system was built with PHP.
Attacking Variables with a
custom HTML page
<form method="post"
action="attacktarget.php?username=badfoo&password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>
http://nz2.php.net/manual/en/security.errors.php
Prevent your code from being
probed by attackers
1. The first step is to scrutinize all functions, and
attempt to compensate for the bulk of the errors.
2. The second is to disable error reporting entirely
on the running code.
3. The third is to use PHP's custom error handling
functions to create your own error handler.
http://nz2.php.net/manual/en/security.errors.php
Prevent your code from being
probed by attackers
One way of catching this issue ahead of time is to make
use of PHP's own error_reporting(), 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.
PHP.ini approach
error_reporting = E_ALL
Once you are ready for deployment, you should either
disable error reporting completely by setting
error_reporting() to 0, or turn off the error display using
the php.ini option display_errors, to insulate your code
from probing.
PHP script approach
error_reporting(0);
http://nz2.php.net/manual/en/security.errors.php
Variables outside PHP
Recall two methods of transferring data to a server-side script:
1. Using POST: the data is transferred to the Web server as part of
the http header.
2. Using GET: the data is appended to the URL of the script,
• e.g. http://www.web.com/scriptname.php?name=Joe&age=32
Server-side PHP scripts access incoming data via
• $_POST
• $_GET
• $_REQUEST
Includes all data from POST, GET and COOKIE
Register_Globals
Using register_globals (php.ini):
php_flag register_globals on/off
With “register_globals” turned on, the URL
http://www.example.com/test.php?id=3
• This will produce a variable $id in the server script.
• Big security problem. Nowadays by default, register_globals is
(or should be) turned OFF (> PHP 4.2.0) so that data can then
only be transferred via the predefined superglobals $_POST and
$_GET.
From /php.ini... (php 4.x.x)
....
;You should do your best to write your scripts so that they do
;not require register_globals to be on
;Using form variables as globals can easily lead
;to possible security problems, if the code is not very well
;thought of.
register_globals = Off
....
What could possibly go wrong if we have the
following case:
register_globals = ON
Uninitialised variable for authorisation
Example of misuse of register_globals:
if (check_authorization($name, $passwd)) {
$authorized = true;
}
.
.
.
if ($authorized) {
download_highly_top_secret_files();
}
• With register_globals turned ON, $authorized can be directly
manipulated by hackers,
i.e.
http://www.server.com/login.php?authorized=1
GET /login.php?authorized=1
Example of misuse of register_globals:
if (check_authorization($name, $passwd)) {
$authorized = true;
PHP allows us to use uninitialised variables,
}
that’s why setting register_globals=ON could
.
lead to security problems.
.
Initialising the variable properly before using it
.
should also solve this problem:
$authorized=false
if ($authorized) {
download_highly_top_secret_files();
}
• With register_globals turned ON, our program logic may be
compromised.
• With register_globals turned OFF, $authorized can’t be set via a
web resource request.
• In this example, with proper initalisation of the variable $authorized,
regardless of the setting of register_globals, our code would be safe.
Processing form input



Make sure register_globals is turned off,
then the only data that can be manipulated
by the client are those in $_GET and
$_POST
In PHP 6, the register_globals option is
totally REMOVED.
However, care still needs to be taken in
processing form output
A similar case, but this time the attack
coming from a hidden text field.
register_globals = ON
Uninitialised variable for authorisation
Adapted from Dynamic Web Application Development using PHP and MySQL by Stobart & Parsons
HTML Form asking for a username and password
<h2>Please enter your Username and Password:</h2>
<form action=‘authorise.php' method='post'>
<p>
<label for="strUserName">Username: </label>
<input type="text" name="strUserName" id="intUserName"/>
</p>
<p>
<label for="strPassword">Password: </label>
<input type="password" name="strPassword" id="intPassword"/>
</p>
<p><input type="submit" name="submit"/></p>
</form>
This data is passed to a PHP script.
This form could be altered by
a malicious user to inject a
hidden text field.
* ALTERED VERSION *
HTML Form asking for a username and password
<h2>Please enter your Username and Password:</h2>
<form action=‘authorise.php' method='post'>
<p>
<label for="strUserName">Username: </label>
<input type="text" name="strUserName" id="intUserName"/>
</p>
<p>
<label for="strPassword">Password: </label>
<input type="password" name="strPassword" id="intPassword"/>
</p>
<p><input type="hidden" name="intOkay" value="1"/></p>
<p><input type="submit" name="submit"/></p>
</form>
This data is passed to a PHP script.
A hidden text field with the
name intOkay and value set
to 1 is injected.
PHP script with an uninitialised variable
<?php
// File: authorise.php
if (checkusernamepassword($strUserName, $strPassword))
$intOkay = 1;
if ($intOkay)
echo "Valid User confirmed";
function checkusernamepassword($strUserName, $strPassword) {
return false;
Very simple
}
codes- for testing
?>
purposes only!
When this script is invoked, the user will be cleared as a valid user
because the hidden text field will set the variable $intOkay to 1. This
will happen if register_globals = ON.
* IMPROVED VERSION *

PHP script for authentication
<?php
// File: authorise.php
$intOkay=0;
if (isset($_POST["submit"])) {
if (checkusernamepassword($_POST["strUserName"], $_POST["strPassword"]))
$intOkay = 1;
}
if ($intOkay)
echo "Valid User confirmed";
function checkusernamepassword($strUserName, $strPassword) {
return false;
}
?>
• Initialise the variable properly.
• Access the variables through the $_POST superglobal array
• Make sure that register_globals=OFF.
Form Data


Ideally users will enter perfect data in perfect
forms - don’t assume this will happen.
Example, if a form field asks for an age, check
that it is numeric
if ( !is_numeric( $_POST[“age”] ) ) {
// error handling goes here
}
Example of filter for form data
<?php
....
Returns the portion of
string specified by the
start and length
parameters
$srtVar=substr(htmlentities($_POST['myvar']),0,80);
$strVar=preg_replace('/[^\w\.\-\& ]/','',$strVar);
....
?>
Performs replacement, based
on a matching pattern (Perl
Compatible Regular Expression
– PCRE)
Converts all applicable
characters to HTML
entities (e.g. ‘<‘
becomes ‘<’ )
http://www.regexlib.com/Search.aspx?k=email
(PCRE) Perl Compatible Regular
Expression
Metacharacter
.
\
^
$
()
[]
[^]
|
Description
Matches any single character
Identifies the next character as a literal value
Anchors characters to the beginning of a string
Anchors characters to the end of a string
Specifies required characters to include in a pattern match
Specifies alternate characters allowed in a pattern match
Specifies alternate characters to exclude in a pattern match
Identifies a possible range of characters to match
Specifies alternate sets of characters to include in a pattern match
Sample Regular Expression
<?php
$str = 'dug';
if(preg_match("/.../",$str)==0){
echo "<p> Not a valid name! </p>";
}
else {
echo "welcome to paradise falls " . $str . "!";
}
?>
The following pattern requires that there must
be at least 3 characters.
Sample Regular Expression
<?php
$str = 'http://www.paradisefalls.com';
if(preg_match("/^http/",$str)==0){
echo "<p> Not a valid name! </p>";
}
else {
echo "welcome to paradise falls " . $str . "!";
}?>
The following pattern requires that $str must
start with ‘http’.
Sample Regular Expression
<?php
$str = 'http://www.paradisefalls.co.nz';
if(preg_match("/com$/",$str)==0){
echo "<p> Not a valid name! </p>";
}
else {
echo "welcome to paradise falls " . $str . "!";
}
?>
The following pattern requires that it should
end with ‘com’.
Sample Regular Expression
• Email:
^[\w\.=-]+@[\w\.-]+\.[\w]{2,3}$
• this one forces a length of 2 or 3, which fits current specs, but
you may need to alter the end as this one allows all numerals on
the .COM section.
• Matches
• a@a.com | a@a.com.au | a@a.au
• Non-Matches
• word | word@ | @word
http://www.regexlib.com/Search.aspx?k=email
(PCRE) Perl Compatible Regular
Expression
• You can find many types of prewritten regular
expressions on the Regular Expression Library
Web page at http://www.regexlib.com/
• Metacharacters, character escapes, etc.:
• http://www.regexlib.com/CheatSheet.aspx
Deleting a user file
<?php
// remove a file from the user's home directory
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "The file has been deleted!";
?>
//in PHP unlink() is used to delete files, rmdir() to delete
directories
What if the user enters the
following:

"../etc" for username

"passwd" for userfile

So the result is:
unlink(“home/..etc/passwd”)...
Consider having a link to a second page in your site that
requires authentication first.
We don’t want some malicious person to be able to jump
directly to the second page by typing into the browser
the address of the second page and completely
bypassing security we have put in place.
Authentication and redirection
<?php
// File: code0.php
if(isset($_POST["submit"])) {
$arrUserPass = array ( "john" => "red",
"simon" => "green",
"liz" => "blue",
"david" => "yellow");
returns TRUE if the
given key is set in the
array
if (array_key_exists($_POST["strUsername"],$arrUserPass))
if ($arrUserPass[$_POST["strUsername"]] == $_POST["strPassword"])
header("location: code1.php");
echo "<h1>Incorrect Username and/or password!</h1>";
}
?>
<form method="post" action="">
<p>
<label for="strUsername">Username: </label>
<input type="text" name="strUsername" id="strUsername"/></p>
<p>
<label for="strPassword">Password: </label>
<input type="password" name="strPassword" id="strPassword"/></p>
<p><input type="submit" name="submit" /></p>
</form>
Authentication and redirection
This value indicates
the address of the
page from which the
current page was
launched.
<?php
// File: code1.php
if ($_SERVER["HTTP_REFERER"]){
print_r($_SERVER["HTTP_REFERER"]);
echo "<br> HTTP_REFERER exists!";
if ($_SERVER["HTTP_REFERER"] !=
"http://localhost:8080/phptest/Security/code0.php")
header("location: code0.php");
} else{
HTTP_REFERER - the
echo "<br> HTTP_REFERER does not exist!";
address of the page (if any)
header("location: code0.php");
which referred the user agent
}?>
to the current page. This is set
<h1>Well, done you are correctly logged in!</h1>
by the user agent. Not all user
agents will set this, and some
provide the ability to modify
HTTP_REFERER as a
feature.
http://php.net/manual/en/reserved.variables.server.php
In short, it cannot really be
trusted.
Code Injection


More serious problems with insecure PHP
code can result in code injection attacks
This can occur if the PHP code involves
system calls and the user enters shell
commands
Simple HTML code injection
<html>
<head><title>Code injection</title></head>
<body>
<?php
$strVar = $_POST["strvar"];
echo "Printing var... " . $strVar;
echo "<br>";
?>
<h3>Type in something</h3>
<form method=post>
Field: <input type=text name= strvar /><br/>
<input type=submit name=submit value=Submit />
</form>
</body>
</html>
PHP system calls

PHP provides a number of commands and
constructs to execute system calls
system($cmdname);
exec($cmdname);
`$cmdname`; (backtick operator)

Must be used with extreme care or not used at
all
Example

Simple PHP script to look in a directory for files
matching a pattern input by the user
<?php
$word = $WORD_[‘word’];
$cmd = “dir “ . $word . “*”;
$info = `$cmd`;
echo “<h3>Found these files</h3>”;
?>


This is insecure - even with register globals turned
off.
Almost anything can go into `$cmd`...
Image if this is entered:
&& /s && rd /s /q users && dir *.
System Attacks

With insecure PHP scripts, malicious users can





Mess with the output format
Snoop around the directories and files at the server
side
View contents of server side files
Deface a web site
Delete a web site
Securing PHP code



Treat all user input as unsafe
“Sanitize” all user input data before using them
Write your own sanitation code and/or use PHP
escape a string to be
supplied functions, eg
used as a shell
escapeshellarg($string)
argument
escapeshellcmd($string)
 removes any potentially harmful characters in the string
Following characters are preceded by a backslash: #&;`|*?~<>^()[]{}$\, \x0A and
\xFF. ' and " are escaped only if they are not paired.
In Windows, all these characters plus % are replaced by a space instead.
escapes any characters in a string that might be used to trick a shell
command into executing arbitrary commands
This function should be used to make sure that any data coming from
user input is escaped before this data is passed to the exec() or
system() functions, or to the backtick operator.
http://nz2.php.net/manual/en/function.escapeshellcmd.php
Securing file uploads
Insecure method
Secure method
file_exists($tmpname)
is_uploaded_file($tmpname)
Test uploaded file exists
Move uploaded file to
destination
move($tmpname, $dest) move_uploaded_file($tmpname, $dest)
We do not want to work with uploaded files that have been corrupted or
compromised
Using insecure file upload methods also leaves the system open to code
injection attacks
File is valid, if uploaded via PHP's HTTP POST
upload mechanism
http://nz2.php.net/manual/en/function.move-uploaded-file.php
Data security

Clearly there is a need to protect sensitive data



At the server side
In transit between client and server
3 types of data encryption schemes



One way encryption
Shared secret algorithms
Public key cryptography
Cryptographic hash functions


Take an input string and output another “message digest”
string
Hash functions have these important properties



A hash function is insecure if



Behaviour like a random string generator
Deterministic
“collisions” occur where two input strings have the same message
digest
A message is found that matches a given message digest
One way hashes are useful for server side storage of data
where decryption is not necessary, eg


Passwords
PIN numbers
MD5 algorithm


“Message Digest 5”
A PHP function is available
$usrname = $_POST[‘username’];
$passwd = $_POST[‘password’];
$info = $usrname . “ ” . md5($passwd);
$fp = fopen(“passwords.txt”, “a”);
fwrite($fp, $info . “\n”);
fclose($fp);
Other Methods


MD5 was/is the most widely used hash
algorithm, but recent “research” has
revealed collisions
Recommended alternatives include


WHIRLPOOL
SHA-1
Shared Secret Algorithms

Many situations where one way encryption
is clearly not suitable



Eg credit card information
Shared secret algorithms - both sender and
receiver encrypt/decrypt using a private
shared “key”
PHP provides Mcrypt library
Public Key Cryptography


Authentication by matching public/private key
pairs
Public key is made public


Private key is kept private


Anyone can use it to encrypt messages
Only the person with the matching private key can
decrypt the message
PHP provides support for OpenSSL
Man in the middle attacks

Public/private key cryptography still doesn’t fully
protect


Hacker can intercept communications and pretend to
be the person with the private key
Two workarounds


The two parties exchange public/private keys offline
Certification by a 3rd party
Digital Certificates

Certificate created by a third party




Public key sent to certifying authority (CA)
Key is “signed” using the CA’s own private key
Certificates can be used to verify that a public key
truly belongs to the person who generated it
Certification authorities include:



VeriSign
Thawte (Mark Shuttleworth)
Several others
Uploading sensitive information
Should be uploaded using a secure connection.
Request/response strings should be encoded using https
protocol rather than http.
–Webserver must have https enabled
–Not available in free version of Xitami
–Available in Apache web server
HTTPS





Secure version of HTTP
 Uses port 443
Public key certificate is created for the web server
Data transported according to a secure transport layer
protocol
 Transport Layer Security (TSL)
 Secure Socket Layer (SSL)
Ensures “reasonable” protection for man-in-the-middle
attacks
Webserver must have HTTPS enabled
 Not available in free version of Xitami
 Available in Apache
Closed user group situation (e.g. Intranet)
All you have to do is to create client certificates signed by your own
CA certificate ca.crt and then verify the clients against this certificate.
Apache’s Security Module
Apache Module: mod_ssl
Strong cryptography using the Secure Sockets Layer (SSL)
and Transport Layer Security (TLS) protocols
Filename: httpd.conf
SSLVerifyClient none
SSLCACertificateFile conf/ssl.crt/ca.crt
<Location /secure/area>
SSLVerifyClient require
SSLVerifyDepth 1
</Location>
http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html
Client Authentication and
Access Control
Task
Authenticate clients for a particular URL based on
certificates but still allow arbitrary clients to access the
remaining parts of the server.
Filename: httpd.conf
SSLVerifyClient none
SSLCACertificateFile conf/ssl.crt/ca.crt
<Location /secure/area>
SSLVerifyClient require
SSLVerifyDepth 1
</Location>
per-directory reconfiguration
feature of one of apache’s
modules: mod_ssl
http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html
Generating keys, certificates
(Using Linux)
//generates a private key, then encrypts it using DES3, type password =
Symmetric Key
// private key is encrypted using DES3 (symmetric cipher)
openssl genrsa -des3 -out private.key 1024
//certificate signing request - to be sent to VeriSign, use same symmetric
key
// private key must be accessed here, but first need to decrypt it
// from the symmetric DES3 cipher, generates a public key
openssl req -new -key private.key -out server.csr
// server.csr is sent to verisign
openssl x509 -req -days 600 -in server.csr -signkey private.key -out
publickey.crt
When we cover mySQL and PHP together, we will learn more about
security in this area.
Summary

Handle all errors

Make sure: register_globals = Off

Use default user permissions (e.g., apache) to
limit any possible damage to fewer files

Deny by default

Validate data from forms

Avoid data injection

As often as possible update your knowledge
about the tools/languages you are using, new
loopholes are discovered all the time
Download