Final steps for authenticating private/secure areas

Discussion in 'PHP' started by MichaelJohannes, Feb 26, 2008.

  1. #1
    Hello,

    I have an issue with an if statement that needs correcting. I can't quite figure it out.

    I have a registration page where users can choose between three options. These three options take the users to a different "private" page. This is the relevant login code:
    
    $qry="SELECT member_id, location FROM members WHERE login='$login' AND passwd='".md5($_POST['password'])."'";
        $result=mysql_query($qry);
        //Check whether the query was successful or not
        if($result) {
            if(mysql_num_rows($result)>0) {
                //Login Successful
                session_regenerate_id();
                $member=mysql_fetch_assoc($result);
                $_SESSION['SESS_MEMBER_ID']=$member['member_id'];
                session_write_close();
                switch ($member['location'])
                {
                    case "private1":
                        header("location: private1.php");
                        break;
                    case "private2":
                        header("location: private2.php");
                        break;
                    case "private3":
                        header("location: private3.php");
                        break;  
                    case default:
                        //ERROR
                        break;
                       
                }
                //end new code
                exit();
               
            }else {
                //Login failed
                header("location: failed.php");
                exit();
            }
        }else {
            die("Query failed");
        }
    PHP:

    As is, this code works.

    The way it works is such that the case system decides which "location" the user picked when they registered, and takes them there after they login.

    On each of the private pages, there is a require once function:
    
    <?php
        require_once('authorization.php');
    ?>
    PHP:
    and that script does:
    
    <?php
     
    //Starts session for private page browsing
     
        session_start();
           
    //Check if the session variable (called SESS_MEMBER_ID is there)
     
        if(!isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID'])=='')) {
            header("location: denied.php");
            exit();
        }
    ?>
    PHP:
    The only problem I'm having is that even if somebody logs in as private1, they can still see the other two private areas (by typing them in the URL bar). Thus making each of the private areas NOT really private.

    Back to the case statement, I have since added this:
    
    <?php
    switch ($member['location'])
                {
                    case "private1":
                        header("location: private1.php");
                        $_SESSION['page_allowed']="private1.php";
                        break;
                    case "private2":
                        header("location: private2.php");
                        $_SESSION['page_allowed']="private2.php";
                        break;
                    case "private3":
                        header("location: private3.php");
                        $_SESSION['page_allowed']="private3.php";
                        break;  
                    default:
                        //ERROR
                        break;
                       
                }
    ?>
    PHP:


    Note the added $_SESSION['page_allowed']="private1.php";

    And then consequently added the $_SESSION['page_allowed']!="private2.php"; string to the authorization.php script (changing the private'n' number for the corresponding pages).
    
    if(!isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID'])=='')) || $_SESSION['page_allowed']!="private1.php";{
            header("location: denied.php");
            exit();
        }
    PHP:


    This means I have used a different authorization script for each of the three private pages (because I have to explicitly specify whether their allowed page is private1,2 or 3).

    But it doesn't work. What happens is the user goes straight to the denied.php page. Have I defined my [page_allowed] variable incorrectly in my case statement?

    Although the authorization script seems to work (and redirect) properly before I added this new [page_allowed] variable, how can I add that 'or' clause to the authorization script so only those users can see their respective allowed areas. I have a feeling I'm missing something basic and I have a feeling it is the $_SESSION['page_allowed'] definition in the case statement. Should this be declared somewhere else?

    I've really tried hard to figure this out and I'm completely stuck. If you can help me fix this, I would be most grateful. :)


    Mike
     
    MichaelJohannes, Feb 26, 2008 IP
  2. decepti0n

    decepti0n Peon

    Messages:
    519
    Likes Received:
    16
    Best Answers:
    0
    Trophy Points:
    0
    #2
    On each private page you could always re-query the database and get their allowed page, and compare it
     
    decepti0n, Feb 26, 2008 IP
  3. blogo

    blogo Peon

    Messages:
    113
    Likes Received:
    2
    Best Answers:
    0
    Trophy Points:
    0
    #3
    yes ... check the session on each private page ....
     
    blogo, Feb 27, 2008 IP
  4. bpasc95

    bpasc95 Active Member

    Messages:
    196
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    70
    #4
    Another option is to store what page they are allowed to see in the DB and set that as a session parameter after a successful login.

    Instead of using header redirects, you could look at including the file. This way, the end user will never see the page name, just the same page with different content each time. If you look at our ad server demo (publisher section) and view the various screens, you will see what I mean. The page file name is the same throughout the entire process, yet content is always changing based on what they are doing.

    -Bing
     
    bpasc95, Feb 27, 2008 IP
  5. MichaelJohannes

    MichaelJohannes Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #5
    If I am to re-query the database to get their 'page_allowed', should I not include it in the original query?

    The 'location' field in my database stores the exact page the user is allowed to see. So my MySQL query already included it:
    
    $qry="SELECT member_id, location FROM members WHERE login='$login' AND passwd='".md5($_POST['password'])."'";
        $result=mysql_query($qry);
        //Check whether the query was successful or not
        if($result) {
            if(mysql_num_rows($result)>0) {
    PHP:
    etc...

    I guess I'm a bit confused because I think I already queried the location from the database. I should point out that I'm a bit new to PHP and don't quite understand the stored session parameters.

    So based on my code already, is there a way that I can simply store their location (already queried) as a session variable? In my case statement, I do not think I've done it properly (but I'm not sure):
    
    <?php
    switch ($member['location'])
                {
                    case "private1":
                        header("location: private1.php");
                        $_SESSION['page_allowed']="private1.php";
                        break;
                    case "private2":
                        header("location: private2.php");
                        $_SESSION['page_allowed']="private2.php";
                        break;
                    case "private3":
                        header("location: private3.php");
                        $_SESSION['page_allowed']="private3.php";
                        break; 
                    default:
                        //ERROR
                        break;
                       
                }
    ?>
    
    PHP:

    If I do need to re-query the database because that's a better option, what would that query look like based on the above query? The authorization.php script on each page is called using a Require_once function and it looks like:


    if(!isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID'])=='')) || $_SESSION['page_allowed']!="private1.php";{
            header("location: denied.php");
            exit();
        }
    
    PHP:
    But as I said, this doesn't work because it redirects the user straight to the denied area.


    Thanks again for your speedy responses and input.

    Mike
     
    MichaelJohannes, Feb 27, 2008 IP
  6. jnestor

    jnestor Peon

    Messages:
    133
    Likes Received:
    7
    Best Answers:
    0
    Trophy Points:
    0
    #6
    Did you move the session_write_close call? Actually I'd just remove it. If you left it in place you're preventing yourself from writing more info to the session.

    Also I wouldn't use a different authorization script for each page. Turn the authorization into a function and pass in the current page as a parameter.
     
    jnestor, Feb 27, 2008 IP
  7. MichaelJohannes

    MichaelJohannes Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #7
    jnestor!!

    Thank you so much... That was the issue: I had closed the session_write php function before my case statement!! You don't know how happy this makes me...

    I ended up creating three different authorization scripts (one for each private area)

    each of them looks like this:

    <?php
    	//Start session
    	session_start();
    	//Check whether the session variable
    	//SESS_MEMBER_ID is present or not
    	if(!isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID'])=='') ) 
    	{
    		header("location: denied.php");
    		exit();
    	}
    
    //if the page_allowed variable does not equal the variable stored in
    //the database, the user is directed to a denied area
    if($_SESSION['page_allowed']!= "private1.php")
    		{
    		header("location: denied.php");
    		exit();
    	}
    ?>
    PHP:

    Now, even though there are three authorization scripts, all three areas are private / 'secure' specific to they way they registered.

    If it's a bad idea to have three authorization scripts, how can I modify the $_SESSION['page_allowed'] if statement?

    I tried this but it didn't work:

    if($_SESSION['page_allowed']!= $member['location'])
    		{
    		header("location: denied.php");
    		exit();
    	}
    ?>
    PHP:
    Do I have to declare a $_SESSION variable for what the $location actually is?

    Thanks again for your help! I'm really close to having this all work as expected.

    Best,
    Mike
     
    MichaelJohannes, Feb 27, 2008 IP
  8. jnestor

    jnestor Peon

    Messages:
    133
    Likes Received:
    7
    Best Answers:
    0
    Trophy Points:
    0
    #8
    You'd need to set the location at the top of each file before you do the include. As far as I can tell the $member['location'] is only set in your login script.

    What I'd personally do is change it to a function:
    
    function authorize($location) {
      if ($_SESSION['page_allowed'] != $location) {
         header("location: denied.php");
      }
    }
    
    Code (markup):
    And the include you the file and call the function as authorize('private1') or whatever.

    It's not a huge deal though.
     
    jnestor, Feb 27, 2008 IP
  9. MichaelJohannes

    MichaelJohannes Peon

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #9
    Okay, that's great advice. Thanks again for your help :)
     
    MichaelJohannes, Feb 27, 2008 IP
  10. bpasc95

    bpasc95 Active Member

    Messages:
    196
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    70
    #10
    What I was suggesting was more along the lines of this:

    <?php
    switch ($member['location'])
    {
    	case "private1":
    		$_SESSION['page_allowed']="private1.php";
    		break;
    	case "private2":
    		$_SESSION['page_allowed']="private2.php";
    		break;
    	case "private3":
    		$_SESSION['page_allowed']="private3.php";
    		break;
    	default:
    		//ERROR
    		break;
    
    }
    include_once($_SESSION['page_allowed']);
    ?>
    PHP:
    This method will require a bit of retooling, but will eliminate the chance of a user changing what page they are on by simply changing the URL.

    -Bing
     
    bpasc95, Feb 28, 2008 IP