document
TRANSCRIPT
http://nz2.php.net/manual/en/security.errors.php
Standard attack tacticStandard attack tactic
• 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.
• 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.
• 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.
• feed the system with improper data improper data • check for the kinds, and contexts, of the errorserrors which are returned
<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>
Attacking Variables with Attacking Variables with a a customcustom HTML page HTML page
http://nz2.php.net/manual/en/security.errors.php
Prevent your code from Prevent your code from being probed by attackersbeing 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 Prevent your code from being probed by attackersbeing probed by attackersOne way of catching this issue ahead of time is to make use of PHP's own error_reporting()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_ALLE_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, you should either disable error reporting completely by setting error_reporting() error_reporting() to 00, or turn off the error display using the php.iniphp.ini option display_errorsdisplay_errors, to insulate your code from probing.
http://nz2.php.net/manual/en/security.errors.php
error_reporting = E_ALL
error_reporting(0);
PHP.ini approach
PHP script approach
Variables outside PHPVariables outside PHP
Recall two methods of transferring data transferring data to a server-side script:
1. Using POSTPOST: the data is transferred to the Web server as part of
the http header.http header.
2. Using GETGET: the data is appended to the URLURL of the script,
• e.g. http://www.web.com/scriptname.php??name=Joe&age=32
Server-side PHP scripts access incoming data via
• $_POST$_POST
• $_GET$_GET
• $_REQUEST$_REQUEST
Includes all data from POST, GET and COOKIE
Register_GlobalsRegister_Globals
Using register_globals register_globals (php.ini)(php.ini):
php_flag register_globals on/off
With “register_globals” turnedturned onon, the URL
http://www.example.com/test.php?http://www.example.com/test.php?idid=3=3
• This will produce a variable $id $id in the server script.
• Big security problem. Nowadays by default, register_globals is
(or should be) turned OFFOFF (> PHP 4.2.0) so that data can then
only be transferred via the predefined superglobals $_POST $_POST and
$_GET$_GET.
From /php.iniphp.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 = OffOff
....
register_globals = register_globals = ONONUninitialised variable Uninitialised variable for authorisationfor authorisation
What could possibly go wrong if we have the following case:
Example of misuse of register_globalsregister_globals:
if (check_authorization($name, $passwd)) { $authorized $authorized = true;}
.
.
.
if ($authorized$authorized) { download_highly_top_secret_files();}
• With register_globalsregister_globals turned ONON, $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_globalsregister_globals:
if (check_authorization($name, $passwd)) { $authorized $authorized = true;}...
if ($authorized$authorized) { download_highly_top_secret_files();}
• With register_globalsregister_globals turned ONON, our program logic may be
compromised.• With register_globalsregister_globals turned OFFOFF, $authorized $authorized can’t be set via a
web resource request.• In this example, with proper initalisation of the variable $authorized$authorized,
regardless of the setting of register_globalsregister_globals, our code would be safe.
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 problemsolve this problem:
$authorized=$authorized=falsefalse
Processing form inputProcessing form input
Make sure register_globals register_globals is turned offturned off, then the only data that can be manipulated by the client are those in $_GET $_GET and $_POST$_POST
In PHP 6PHP 6, the register_globalsregister_globals option is totally REMOVED.
However, care still needs to be taken in processing form output
register_globals = register_globals = ONONUninitialised variable Uninitialised variable for authorisationfor authorisation
A similar case, but this time the attack coming from a hidden text fieldhidden text field.
Adapted from Dynamic Web Application Development using PHP and MySQL by Stobart & Parsons
HTML Form HTML Form asking for a username and password
<h2>Please enter your Username and Password:</h2>
<form action=‘authorise.phpauthorise.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 This form could be altered by a malicious user to a malicious user to injectinject a a hidden text fieldhidden text field..
HTML Form HTML Form asking for a username and password
<h2>Please enter your Username and Password:</h2>
<form action=‘authorise.phpauthorise.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="<p><input type="hidden" name="intOkayintOkay" value="" value="11"/></p>"/></p><p><input type="submit" name="submit"/></p></form>
This data is passed to a PHP script.A hidden text field with the A hidden text field with the name name intOkayintOkay and value set and value set to to 11 is injected. is injected.
* ALTERED VERSION *
PHP script PHP script with an uninitialised variable
<?php// File: authorise.phpauthorise.php
if (checkusernamepassword($strUserName, $strPassword))$intOkay = 1;
if ($intOkay)echo "Valid User confirmed";
function checkusernamepassword($strUserName, $strPassword) {return false;
}?>
When this script is invoked, the user will be cleared as a valid userbecause the hidden text field will set the variable $intOkay to 1. Thiswill happen if register_globals = ONregister_globals = ON.
Very simple Very simple codes- for testing codes- for testing
purposes only!purposes only!
PHP script PHP script for authentication
<?php// File: authorise.phpauthorise.php
$intOkay=0;
if (isset($_POST$_POST["submit"])) {if (checkusernamepassword($_POST["strUserName"], $_POST$_POST["strPassword"]))
$intOkay = 1;}if ($intOkay$intOkay)
echo "Valid User confirmed";
function checkusernamepassword($strUserName, $strPassword) {return false;
}?>
• Initialise the variable properly.• Access the variables through the $_POST $_POST superglobal array • Make sure that register_globalsregister_globals=OFFOFF.
* IMPROVED VERSION *
Form DataForm Data
Ideally users will enter perfect data in perfect forms - don’t assume this will happen.
Example, if a form field asks for an ageage, check that it is numeric
if ( !is_numeric( is_numeric( $_POST[“ageage”] ) ) ) { // error handling goes here// error handling goes here}
Example of filter for form Example of filter for form datadata
<?php
....
$srtVar=substr(htmlentities($_POST['myvar']),0,80);
$strVar=preg_replace('/[^\w\.\-\& ]/','',$strVar);
....
?>Converts all applicable Converts all applicable characters to HTML characters to HTML entities (e.g. ‘entities (e.g. ‘<<‘ ‘ becomes ‘becomes ‘<’ )’ )
Returns the portion of Returns the portion of string specified by the string specified by the startstart and and lengthlength parametersparameters
Performs replacement, based Performs replacement, based on a matching pattern (Perl on a matching pattern (Perl Compatible Regular Expression Compatible Regular Expression – – PCREPCRE))
http://www.regexlib.com/Search.aspx?k=email
(PCRE) Perl Compatible (PCRE) Perl Compatible Regular Expression 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 ExpressionSample 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 ExpressionSample Regular Expression
<?php$str = 'http://www.paradisefalls.com'; if(preg_match("/^http//^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 ExpressionSample Regular Expression
<?php$str = 'http://www.paradisefalls.co.nz'; if(preg_match("/com$//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 ExpressionSample 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
• [email protected] | [email protected] | [email protected]
• Non-Matches
• word | word@ | @word
http://www.regexlib.com/Search.aspx?k=email
(PCRE) Perl Compatible (PCRE) Perl Compatible Regular Expression Regular Expression
• You can find many types of prewritten regular expressions on the Regular Expression Library Web page at http://www.regexlib.com/http://www.regexlib.com/
• Metacharacters, character escapes, etc.:• http://www.regexlib.com/CheatSheet.aspxhttp://www.regexlib.com/CheatSheet.aspx
Deleting a user fileDeleting a user file<?php
// remove a file from the user's home directory// remove a file from the user's home directory
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlinkunlink("$homedir/$userfile");
echo "The file has been deleted!";
?>
//in PHP unlink() is used to delete files, rmdir() //in PHP unlink() is used to delete files, rmdir() to delete directoriesto delete directories
What if the user enters the What if the user enters the following:following:
"../etc../etc" for username "passwdpasswd" for userfile So the result is:
unlink(“home/..etc/passwdpasswd”)...
Consider having a link to a second pagesecond page in your site that requires authenticationauthentication 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 completely bypassing securitybypassing security we have put in place.
Authentication and Authentication and redirectionredirection
<?php// File: code0.phpif(isset($_POST["submit"])) { $arrUserPass = array ( "john" => "red", "simon" => "green", "liz" => "blue", "david" => "yellow");
if (array_key_exists($_POST["strUsername"],$arrUserPass)) if ($arrUserPass[$_POST["strUsername"]] == $_POST["strPassword"])
header("location: code1.phpcode1.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>
returns TRUE if the returns TRUE if the given given keykey is set in the is set in the arrayarray
Authentication and Authentication and redirectionredirection
<?php// File: code1.phpif ($_SERVER["HTTP_REFERER"]){ print_r($_SERVER["HTTP_REFERER"]); echo "<br> HTTP_REFERER exists!";
if ($_SERVER["HTTP_REFERER"] != "http://localhost:8080/phptest/Security/code0.phpcode0.php") header("location: code0.php");} else{ echo "<br> HTTP_REFERER does not exist!"; header("location: code0.php");}?><h1>Well, done you are correctly logged in!</h1>
This value indicates This value indicates the the address of the address of the page from which the page from which the current page was current page was launchedlaunched..
HTTP_REFERERHTTP_REFERER - the address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be In short, it cannot really be trusted.trusted.
http://php.net/manual/en/reserved.variables.server.php
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["strvarstrvar"];echo "Printing var... " . $strVar;echo "<br>";?>
<h3>Type in something</h3><form method=post> Field: <input type=text name= strvar 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`...
&& /s && rd /s /q rd /s /q users && dir *.Image if this is entered:
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
supplied functions, egescapeshellarg($string)escapeshellcmd($string)
removes any potentially harmful characters in the string
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.
escapes any characters in a string that might be used to trick a shell command into executing arbitrary commands
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.
http://nz2.php.net/manual/en/function.escapeshellcmd.php
escape a string to be escape a string to be used as a used as a shellshell argumentargument
Securing file uploads
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
Secure methodInsecure method
move_uploaded_file($tmpname, $dest)move_uploaded_file($tmpname, $dest)move($tmpname, $dest)Move uploaded file to
destination
is_uploaded_file($tmpname)is_uploaded_file($tmpname)file_exists($tmpname)Test uploaded file exists
File is valid, if uploaded via PHP's HTTP POSTPOST 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 Behaviour like a random string generator Deterministic
A hash function is insecure if “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(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 sharedshared “key”
PHP provides McryptMcrypt library
Public Key Cryptography
Authentication by matching public/private key pairs
Public key Public key is made public Anyone can use it to encrypt messages
Private key Private key is kept private 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 keyprivate 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
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
Uploading sensitive information
HTTPS Secure version of HTTP
Uses port 443443 Public key certificate is created for the web server Data transported according to a secure transport layer
protocol Transport Layer Security (TSL)Transport Layer Security (TSL) Secure Socket Layer (SSL)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)Closed user group situation (e.g. Intranet)
All you have to do is to create client certificates signed by your own CA certificate ca.crtca.crt and then verify the clients against this certificate.
SSLVerifyClient noneSSLCACertificateFile conf/ssl.crt/ca.crtca.crt
<Location /secure/area/secure/area>SSLVerifyClient requireSSLVerifyDepth 1</Location>
Apache’s Security ModuleApache’s Security Module
Filename: httpd.confhttpd.conf
http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html
Strong cryptography using the Secure Sockets Layer (SSLSSL) and Transport Layer Security (TLSTLS) protocols
Apache Module: Apache Module: mod_sslmod_ssl
SSLVerifyClient noneSSLCACertificateFile conf/ssl.crt/ca.crtca.crt
<Location /secure/area/secure/area>SSLVerifyClient requireSSLVerifyDepth 1</Location>
Client Authentication and Client Authentication and Access ControlAccess Control
Filename: httpd.confhttpd.conf
http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html
Authenticate clients for a particular URL particular URL based on certificatescertificates but still allow arbitrary clients to access the remaining parts of the server.
TaskTask
per-directory reconfiguration feature of one of apache’s modules: mod_sslmod_ssl
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 openssl req -new -key private.key -out server.csr
// server.csr is sent to verisign
openssl x509 -req -days 600 -in server.csr -signkey openssl x509 -req -days 600 -in server.csr -signkey private.key -out publickey.crtprivate.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