1. Banned (not really)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 1999
    Location
    Brussels, Belgium
    Posts
    14,642
    Rep Power
    4492
    Originally Posted by buggedcom
    To protect your includes from being accessed via the browser why not just put them in a .htaccess protected directory. that way the scripts can still include them and the browser can't see them.
    I'm sure that was mentioned, but it's not an option for everyone. It's hard to require that if you're the designer of a program, too. Not everyone runs Apache, either. But yes, that is one good method.

    ---John Holmes...
    -- Cigars, whiskey and wild, wild women. --
  2. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2007
    Posts
    17
    Rep Power
    0
    Tip: use "mysql_real_escape_string()" for SQL statement and not "addslashes()".

    Secure GET & POST values:

    PHP Code:
    <?php

    $_GETS 
    array_map('mysql_real_escape_string'$_GET);
    $_POSTS array_map('mysql_real_escape_string'$_POST);

    mysql_query("SELECT * FROM `table` WHERE ".
    "`get1` = '".$_GETS['key1']."' AND ".
    "`get2` = '".$_GETS['key2']."' AND ".
    "`post1` = '".$_POSTS['key1']."' AND ".
    "`post2` = '".$_POSTS['key2']."'");

    // ... etc ...

    ?>
    and then you dont have to worry about forgetting to do this.
  3. Banned (not really)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 1999
    Location
    Brussels, Belgium
    Posts
    14,642
    Rep Power
    4492
    array_map('stripslashes', $_GET)
    array_map('mysql_real_escape_string', $_GET)
    Personal preference here, but I don't think applying functions blindly to the entire $_GET and $_POST arrays is good for efficiency and scalability.

    IF I've already validated a string and I KNOW the value is going into a query, then I apply mysql_real_escape_string() to that value only.

    Also, I only need to run stripslashes on a value if it's already validated to a string and I KNOW I'm going to turn around and use that value elsewhere.

    ---John Holmes...
    -- Cigars, whiskey and wild, wild women. --
  4. Web Developer/Musician
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Nov 2004
    Location
    Tennessee Mountains
    Posts
    2,408
    Rep Power
    1031
    I don't mind doing that with the entire array, if the majority of values are destined for the database. If only 2 or 3 values out of say 20 in a form are not destined for the db it seems to make sense to me to do that. Better to use the pre-written function for that than typing out 17 calls to mysql_real_escape_string, just because not all request varaibles (get or post) are meant for the database.

    My db abstraction has it's own escaping method to use with db values and prepared statements, so for inserts and updates I rarely escape out side of the db abstraction, but I have the option to do so If need be.
    Last edited by Hammer65; March 12th, 2007 at 08:40 AM.
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2007
    Location
    Ontario, Canada
    Posts
    16
    Rep Power
    0

    PHP Session Hijacking


    Greetings,

    Great information and and resources for the newbie PHP developer. I have noticed one security issue that has not been addressed. PHP Session Hijacking.

    Session ID hijacking can be a problem with PHP Websites. The PHP session tracking component uses a unique ID for each user's session, but if this ID is known to another user, that person can hijack the user's session and see information that should be confidential. Session ID hijacking cannot completely be prevented; you should know the risks so you can mitigate them.

    For instance, even after a user has been validated and assigned a session ID, you should revalidate that user when he or she performs any highly sensitive actions, such as resetting passwords. Never allow a session-validated user to enter a new password without also entering their old password, for example. You should also avoid displaying truly sensitive data, such as credit card numbers, to a user who has only been validated by session ID.

    A user who creates a new session by logging in should be assigned a fresh session ID using the session_regenerate_id function. A hijacking user will try to set his session ID prior to login; this can be prevented if you regenerate the ID at login.

    If your site is handling critical information such as credit card numbers, always use an SSL secured connection. This will help reduce session hijacking vulnerabilities since the session ID cannot be sniffed and easily hijacked.

    If your site is run on a shared Web server, be aware that any session variables can easily be viewed by any other users on the same server. Mitigate this vulnerability by storing all sensitive data in a database record that's keyed to the session ID rather than as a session variable. If you must store a password in a session variable (and I stress again that it's best just to avoid this), do not store the password in clear text; use the sha1() (PHP 4.3+) or md5() function to store the hash of the password instead.

    PHP Code:
    if ($_SESSION['password'] == $userpass) {
     
    // do sensitive things here

    The above code is not secure, since the password is stored in plain text in a session variable. Instead, use code more like this:

    PHP Code:
    if ($_SESSION['sha1password'] == sha1($userpass)) {
     
    // do sensitive things here

    The SHA-1 algorithm is not without its flaws, and further advances in computing power are making it possible to generate what are known as collisions (different strings with the same SHA-1 sum). Yet the above technique is still vastly superior to storing passwords in clear text. Use MD5 if you must -- since it's superior to a clear text-saved password -- but keep in mind that recent developments have made it possible to generate MD5 collisions in less than an hour on standard PC hardware. Ideally, one should use a function that implements SHA-256; such a function does not currently ship with PHP and must be found separately.

    Another solution to help prevent Session Hijacking is to handle sessions with custom handlers. This allows you to store the session information in a database (encrypted form of course). A little trick to help validate sessions is to assign the user agent to the session entry in the database. When you verify a users session id, you should also compare the user agent.

    In conclusion, you cannot prevent session hijacking completely, but you can take measure to minimize the damage and information that can be stolen.

    Smart programming and proper security implementations.

    Cheers!

    Comments on this post

    • SimonGreenhill agrees : good post.
    • J_Tree agrees : ++ See example code below!
    • ryon420 agrees
    • b3n agrees
  6. Rocking my php-ness
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Dec 2004
    Location
    Boston, MA
    Posts
    1,968
    Rep Power
    151
    I have some code I use as part of a session class to create / use 1 time session IDs that regenerate on each request. Here is the code put together into one easy to use function:

    PHP Code:
    /*
     Starts a session, regenerates an id and destroys the old session to 
     help prevent session hijacking
    */
    function safer_session_start()
    {
        
    // Start the session
        
    session_start();

        
    // Assign current contents to a temp var
        
    $s $_SESSION;

        
    // Get rid of $_SESSION
        
    $_SESSION null;
        unset(
    $_SESSION);

        
    // Get current session id
        
    $old_id session_id();

        
    // Make a new session id
        
    session_regenerate_id();

        
    // Get the new session id
        
    $new_id session_id();

        
    // Tell php we want to use the old session
        
    session_id($old_id);

        
    // Buh bye old session!!! Ohh NOES!!
        
    session_destroy();

        
    // Tell php it's back to the new session!
        
    session_id($new_id);

        
    // Start it up proper!
        
    session_start();

        
    // Put back our session var(s)
        
    $_SESSION $s;

    Last edited by J_Tree; March 28th, 2007 at 09:47 AM. Reason: funny spacing
    My new WebComic http://www.jjsunshines.com/
    The Geek Shall Inherit the Earth

    It is NOT ok to IM me with questions unless I told you it was ok via PM
  7. Banned (not really)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 1999
    Location
    Brussels, Belgium
    Posts
    14,642
    Rep Power
    4492
    Originally Posted by J_Tree
    I have some code I use as part of a session class to create / use 1 time session IDs that regenerate on each request. Here is the code put together into one easy to use function
    WTH would you go through all of that instead of just calling session_regenerate_id() by itself? Kind of seems like a waste. :shrug:

    Comments on this post

    • J_Tree agrees : I understand your skepicism but see my next post
    -- Cigars, whiskey and wild, wild women. --
  8. Rocking my php-ness
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Dec 2004
    Location
    Boston, MA
    Posts
    1,968
    Rep Power
    151
    Well . . .

    In my testing using php 4, session_regenerate_id() doesn't seem to remove old session data, it just starts a new session with a new id. This means that if someone were to capture my previous ID they could have access to my session data even though I was using a new copy. Who cares who is using which copy if my credit card or social security number is stored in there. The method I posted above explicitly clears my old session data assigned with my previous ID and moves it to my new session. For all intents and purposes, it creates a 1 time 1 use Session ID.

    The manual for this function makes it seem as if all that is needed is session_regenerate_id(), but real life testing shows differently.

    EDIT: Reading the manual now shows an optional argument for this function as of php 5.1 that seems to address the issue my function solves. So I guess if you have php < 5.1, My function would be a replacement.
    Last edited by J_Tree; March 28th, 2007 at 02:06 PM.
    My new WebComic http://www.jjsunshines.com/
    The Geek Shall Inherit the Earth

    It is NOT ok to IM me with questions unless I told you it was ok via PM
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2007
    Location
    Ontario, Canada
    Posts
    16
    Rep Power
    0
    J_Tree,

    I see where you are coming from, and I agree with you. I have not developed with PHP 4 in some time now, but I do remember having to write a similar function as your safer_session_start( ).

    They have come a long way with PHP 5, but in reality, PHP 4 is still widely used - so its good to know the issues and security vulnerabilities.

    Good post.
  10. PHP is my Love!
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Kafr Sakr, Egypt
    Posts
    87
    Rep Power
    12
    Don't allow user to upload php files

    I think it is important, in the case of having file upload related to user, to check the file type that is going to be uploaded to prevent any upload php file .i.e with .php extension.
    Best Regards,
    Said Bakr.
  11. Web Developer/Musician
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Nov 2004
    Location
    Tennessee Mountains
    Posts
    2,408
    Rep Power
    1031
    Originally Posted by saidbakr
    Don't allow user to upload php files

    I think it is important, in the case of having file upload related to user, to check the file type that is going to be uploaded to prevent any upload php file .i.e with .php extension.
    Always a good idea, however you should also ensure that you are correctly detecting the file extension.

    Some upload scripts detect any instance of "gif" or "jpg" in a file name after A dot, not the correct dot but any dot. This is vulnerable to attacks through file names like

    nasty.gif.php

    It looks like a gif to the code but it's ACTUAL file extension is php. It may even be a gif file, but by embedding PHP code in an area of the file that is reserved for metadata or comments, once in a publicly available upload directory, it can be executed just as any PHP file can be. The binary gif code is simply interpreted the same way anything out side of <?php ?> is interpreted.

    Don't rely on the mime type as reported by the browser, as this may be subject to spoofing.
  12. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2008
    Posts
    3
    Rep Power
    0
    Originally Posted by JeffCT
    Ok, thanks. I am glad you brought that up and clarified, I was worried you were posting a "this topic sucks because it doesn't cover what I wanted".. kind of thing.

    I'll have to look more into that, I admit I know very little (if anything) about "internal" PHP security. I don't know how exploitable it is but I did want to cover the common programming mistakes that leave your site so wide open that any 12 year old "hacker" could exploit it.

    Hey - since you know more about that sort of thing than I do, maybe you could post the next topic? What do you say
    I think it's a good posting. Security in PHP is very often disregarded...
  13. Web Developer/Musician
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Nov 2004
    Location
    Tennessee Mountains
    Posts
    2,408
    Rep Power
    1031
    If you have been on this board for a while, you know that you see the same insecure code over and over. Some of this stuff comes from out of date books. A lot of it comes from online tutorials. The sad thing is, those tutorials aren't necessarily old ones. I see new scripts posted every day that come from tutorial sites, that are vulnerable to all manner of things we hit over and over here.

    In addition to you yourself coding securely, if someone posts what looks like, or they have told you is, a pre-written script that is insecure, find out what site it's on, and raise hell with the author.

    We are almost at PHP v 6.x and yet we still see 98% use of the OLD MySQL extension, mail forms that are major spammer bait and more XSS vulnerabilities then you shake 100 sticks at. It's bad for the language, bad for the livelihood of those that code it for a living, and it puts the security of anybody that uses the internet, including us at risk.
  14. Wiser? Not exactly.
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    5,947
    Rep Power
    4033
    A lot of scripts handle access by including a 'secure.php' file which validates the user by session/posted username/passwords, and in the case of a login failure redirects to the login page.

    Remember to always do this redirect in such a way that the rest of the script is not executed after the redirect. The easiest way to do this is using exit; after the redirect.

    Example:
    I've been recently looking over code for a company to identify security holes and they were doing this for their authentication. they had code which boils down to something like this:

    [code=secure.php]
    <?php

    if (isset($_COOKIE['username']) && isset($_COOKIE['userpass'])){
    $rs = mysql_query('SELECT password FROM users WHERE username="'.$_COOKIE['username'].'"');
    if (mysql_num_rows($rs) == 0){
    header('Location: login.php');
    }
    else {
    $securepass=mysql_result($rs, 0, 0);
    if (base64_decode($_COOKIE['userpass']) != $securepass){
    header('location: login.php');
    }
    }
    }
    [/code]

    That file is used in an admin file as so:
    [code=edit.php]
    <?php

    //Validate login, redirect to login page if incorrect.
    include('secure.php');


    $action = $_GET['action'];
    if ($action == 'delete'){
    mysql_query('DELETE FROM entries WHERE entry_id='.$_GET['id']);
    echo 'Entry deleted';
    }
    ?>
    [/code]

    Now. Aside from the glaring SQL Injection problems, it is also possible for a completely unauthenticated user to delete stuff because they do not prevent the rest of the script from running.

    A request to the URL http://www.site.com/admin/edit.php?action=delete&id=1

    will generate a response like so:
    Code:
    HTTP/1.1 200 Ok
    Location: login.php
    
    Entry Deleted
    The browser will happily redirect you to login.php and it looks like your code works, but if you look at the DB you'll be quick to notice entry_id #1 is no longer there because the delete was executed when the script finished up. The fix? Just exit after a redirect.

    Code:
    header('Location: login.php');
    exit;
    Recycle your old CD's, don't just trash them



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  15. hanibal hector
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2007
    Posts
    701
    Rep Power
    114
    Great tips, just found a small mistake on top of your post:
    PHP Code:
     $pages = array('index.html''page2.html''page3.html'); 
    if( 
    in_array($page$pages) ) 

        include(
    $page); 

    else 

       die(
    "Nice Try."); 

    The if bracket should be other direction
    Cheers

IMN logo majestic logo threadwatch logo seochat tools logo