Session variable disappears after Redirect - php

I have been fighting with this problem all day. I have read numerous SO and forum posts where so many others had this same problem, and the posts spanned years.
My problem was part of a back end system I wrote to allow very basic alterations to database data, New entries could be added, updated or deleted. Pretty standard issue stuff. For simplicity, each function, insert, update, delete and an overall view of the database contents were on separate pages (insert.php, update.php, depete.php).
When adding a new entry, editing or deleting an existing entry, a redirect followed that would take the user back to the view,php page to show the updated data list. Problem is, the redirect wasn't working. The session variable was somehow discarded during the redirect which, due to my code, tossed the user back to the login page.
Here was my code:
if ($done || !isset($_GET['client_id'])) {
header('Location: http://website.com/admin/view.php');
exit;
}
Many thanks to all of you!
It checked to make sure the updated data was posted and if all was well, redirected to view.php.
But it wouldn't, and yes, my pages all started with the necessary <?php session_start(); ?>. So after hours of scouring the web, I came across a nine-year old entry in the PHP manual that I felt was worthy of sharing:
http://www.php.net/manual/en/ref.session.php#37555
In it, the poster mentions, "Be aware of the fact that absolute URLs are NOT automatically rewritten to contain the SID. "
He suggested, "Skipping the 'http:' did the job." so I removed it from my code as such:
if ($done || !isset($_GET['client_id'])) {
header('Location: view.php');
exit;
}
And it WORKED. This topic has been a headbanger for many of us and I wanted to share it for what it's worth.
HOWEVER, I also do have a question, and that is, what would the proper procedure be to allow an absolute URL to be written that did contain the SID?

DO NOT pass the session ID in from the URL.
http://en.wikipedia.org/wiki/Session_fixation
Use cookies. You can perform a best-effort same-origin check on the session ID given to you by storing the creator's IP address for example. Cookies are harder to tamper with than a simple URL. If they "disappear" then that means your user cleared their cookies and does not want you to track their session anymore.

Related

Login sytem with PHP

Good day.
I have questions about the login system , that disturbed me quite a long time. For this i want you to imagine that i have 2 pages login.php and userpage.php. The login page contains fields for input of user name and password. While userpage contains all the information about the logined user. When user inputs his data, some class Connection checks him in the database and if user exists, creates a session.
When I'm creating a redirection from login.php to userpage.php, how should i redirect users data? (Should I use global arrays (like $_SESSION) to transfer the info or I should connect the db again from the user page?)
Should I create some multi-threading (Do not judge strictly, I'm a newbie) for userpage.php, to be created for multiple users, which are trying to login at the same time?
How should I protect the information (code side), for being hard to read? (For example Facebook pages source-code. because i don't want some "bad guys" to view my sources) and other things.
How can I make some users to see what the others can't ? For example userpage.php shows different links and information for different users and all the information for me .
How can i prevent membership.php from being viewed?(Is there some other way than using header?)
How can i prevent my require and require_once from being viewd at the login.php and userpage.php ?
1.) When I'm creating a redirection from login.php to userpage.php, how should i redirect users data? (Should I use global arrays (like $_SESSION) to transfer the info or I should connect the db again from the user page?)
You need to have a connection to the db everytime you want to get the user's data. You can create a session to store a unique attribute for the user, like $_SESSION['id'], when the user is successfully logged in, and you can use that value on any page to query the db and get the necessary user data.
2.) Should I create some multi-threading (Do not judge strictly, I'm a newbie) for userpage.php, to be created for multiple users, which are trying to login at the same time?
No, you don't need to worry about users connecting at the same time. The server can handle this. When you have a million users or so, you can start considering this. (Although, even then I'm not too sure. Unfortunately I've never had that problem ;) )
3.) How should I protect the information (code side), for being hard to read? (For example Facebook pages source-code. because i don't want some "bad guys" to view my sources) and other things.
You cannot prevent anyone from seeing your markup and styles, that is, your html and css, or any client side scripting, like javascript. However, your php is server side and not displayed in the source. The 'bad guys' will not be able to view source to see your db connections, php logic, etc.
4.) How can I make some users to see what the others can't ? For example userpage.php shows different links and information for different users and all the information for me .
There are different approaches to take. The simplest is probably to store the user's 'permission level' in the db, and then check that every time you load content. For example,
if ($user['permission']==1)
// Show something
elseif ($user['permission']==2)
// show something else
5.) How can i prevent membership.php from being viewed?(Is there some other way than using header?)
The easiest way to do this is by checking to see if there is an active session, and if not, redirect:
if (!isset($_SESSION['id']))
header("Location: login.php");
6.) How can i prevent my require and require_once from being viewed at the login.php and userpage.php ?
Not too sure what you mean by this, but consider this: require and require_once are the exact same as including the code directly in the file. If you are referring to them being viewed directly by the client by hitting 'view source', don't worry - see answer to question 3.
Note:
These answers are simplified, and there are plenty of other complications to consider. Some of this stuff may not make sense, but I wouldn't sweat it too much. I would recommend starting small - find a decent tutorial or two on how to create a simple user database, a registration, and login page, and start there. No answers you get here will substitute research, practice, and trial and error. Start small, and things will quickly become clearer as you progress.
Save the users state in a cookie or in a session. Note that you need the session_start() the userpage.php page as well as the rest of the page were the user is connected.
More info on http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL
See the above link.
No one can read PHP code because it is server side and not client side. So your code is secure already from its own structure.
Let users have different level from the swl-database. If a user got auth 1 they see some links, if they got user auth 2 they see other things.
See page from answer 1
See page from answer 1
Considering your stated fact that you are newbie,I will also assume that the login system is more of practice thing and not a real world app.
Now to answer your queries point-wise.
Storing data in SESSION variables is alright.However,do not store too many data in SESSIONS.I would suggest just store the userid for the user and use that to gather and display info in the userpage.php. As the app gets bigger,you will definitely need to make connections in each individual page.
Use SESSION and COOKIE combination to create multiple user logins. However,Refrain from trying to implement/allow same browser multiple logging-in.SECURITY ISSUE.
PHP source code is anyways not readable from client-side.Regarding javascript & css-u can maybe minify it.But that would still not make it client-safe.
There are many ways to implement this.Maybe have a $_SESSION['admin'] =true when a admin logs-in and use it to display/hide info on userpage.php.
Same as NEXT
What it is that u want to hide?If its HTML/JS ,u dont't have much choice. One solution may be to use if-else in ur php code and restrict display of code present in header.php and the pages included via require and require_once.
This is a very basic guide.Your strategies may vary depending on the complexity of your application and also if/when you start using framweorks . Happy logging-in !!
ADDITIONS wrt to application structure.
Considering that your end product would be a system that allows a user to register and login/logout,i would suggest a following structure to begin with.
Structure-
index.php
|--action
|---register.php
|---logged_in_user_landing.php
index.php-- This is main page and used to redirect to individual pages based on actions.
check if SESSION is set.
If yes,include action/logged_in_user_landing.php else include action/register.php.
As actions increase,you can add if-else and include more pages accordingly.
In register.php,u have the form for login. On submit, redirect to index.php (via form action).
establish db connection in index page and check username-password combination.If correct,set the SESSION for that user and include the 'action/logged_in_user_landing.php'.
Have a unique identifier sent along when redirecting from each individual page,So that u can identify what to do in index.php.
This is a very simple architecture that should get u started.Its kind of a controller based architecture and will help you in the future when u go into MVC architectures.

HTTP_REFERER initiated HTML visible throughout website not just on the initial landing page

I have been looking for ever for a solution to my problem - I’m not a PHP newbie but am not overly experienced in it.
My problem is this:
I have a set of sites - one being the parent site. I want to have it so that if I hit any of my child sites from the parent site only, a back to parent button appears (wrapped in a div). If I hit any of the child sites directly or from another referrer then the button doesn't appear.
I have this working using HTTP_REFERER but I would like the button to remain visible when you click the through the site (obviously the referrer changes once I start clicking through the site).
This works for the button appearing on first hitting the site:
<?php if (preg_match("~^http://www.mysite.com~i", $_SERVER['HTTP_REFERER'])) { ?>
<div>Back</div>
<?php } ?>
But as I say I would like it to remain whilst I am navigating the site - I have looked at setting up a session but I can't get this to work either - the referrer always changes once I start navigating.
I appreciate this is a little vague but I have tried so many code samples and they all seem to have the same issues.
Any help would be much appreciated.
Thanks
Well the HTTP_REFERRER is indeed the last referer of the current page, so you have to store and start a session the first time you enter the site.
Sessions are usually a very simple subject that should work out of the box:
session_start();
session_regenerate_id();
if (preg_match("~^http://www.mysite.com~i", $_SERVER['HTTP_REFERER'])) {
$_SESSION['parentsite'] = true;
}
And later in your code do:
<?php if(isset($_SESSION['parentsite']) && $_SESSION['parentsite'] == true){ ?>
<div>Back</div>
<?php } ?>
Now if your sessions still don't work with that, it could be a COOKIE problem or a server configuration problem...
<?php
session_start();
if (!isset($_SESSION["ref"])){
$_SESSION["ref"] = $_SERVER["HTTP_REFERER"]; //record first instance
} else if (isset($_SERVER["HTTP_REFERER"])){
$ref = $_SERVER["HTTP_REFERER"];
if ($ref != $_SESSION["ref"]){
$_SESSION["ref"] = $ref; // record new ref
}
}
if ($ref = $_SESSION["ref"]){
echo "Back
}
BUT I agree with Pekka, that you should use custom site_id which is passed along whilst you navigate your site. Relaying on HTTP_REFERER is generally unsafe. And using session would run you into problem if you come to your master site from two child sites, as session would hold only latest ref.
In other solution of ours, we use get param "current_ref", which contains encoded referer url, created by the source site. This param is "sticky", and is passed all along the way, so at any point of time you can return to the originating site. Probably it would be better for you to implement such approach as well.
Edit: On closer look, a session based approach might be just enough for this specific situation, if there is only one parent site and multiple children, but no multiple parents! In a more complex situation however, sessions will send you to hell, so I'll leave this answer in place.
This is not trivial -
you could use sessions to store the referrer target across pages, but that would get confused if the user opens multiple instances of the same page from different referrers, which is horrible for usability
or send a unique key along with each request that points to the correct "back" target. (It could also be the base64 or URL encoded URL itself, but that would make the URLs look long and ugly...)
The latter is a very clean approach, but a pain to implement consistently.
One other (crazy and untested) idea that comes to mind is storing a base64 encoded representation of the referrer URL using JavaScript in the window.name property. The nice thing about that is that unlike a cookie, it stores the "back" target for the current window only. I can't guarantee this will work, but it might be worth following up on if you really want to do this.
As soon as I saw your question I thought that a SESSION would be the key.
You could set a session cookie and then test to see if the cookie already exists.
session_start();
if (preg_match("~^http://www.mysite.com~i", $_SERVER['HTTP_REFERER']) ||
isset($_SESSION['show_back_button']))
{
// Set the session value
$_SESSION['show_back_button'] = true;
echo '<div>Back</div>';
}

Go back to calling website

after searching (and testing) a way to offer a kind of go-back button I am asking that question here (maybe there is an easy solution).
I have a description about orienteering on my website (5 pages): http://www.uhebeisen.net/o-def/o-definition_ge.php
There are many websites from abroad having a link to this pages. Now I'd like to get their URL if a websurfer is entering my pages. Then I can place a button go-back to my navigation list that brings him back to his page from where he clicked the link to my description-pages.
I've seen solutions using javascript:history.go(-1) or $_SERVER['HTTP_REFERER'] with PHP but problem is that a websurfer can move around my pages and if finishing his reading from any page should be provided with his (calling) URL, e.g. the one of his University.
So I need to catch his URL and store it in a safe place until he decides to leave. And if he returns to the starting page while surfing on my pages his URL shouldn't be overwritten.
Since I do not program - just copy&paste and try to understand what happens. Any suggestion on how this can be done is welcome.
thank you George, that one worked
I wasn't aware to place the session_start at the very beginning of the file that's why I get the two warnings.
While testing this function I found that the session variables were not always cleared by the browser. Especially with Firefox, it keeps the calling URL almost forever (WinXP, FF 5.x) whereas Firefox 5 on the Mac, Safari (Mac) and Camino (Mac) work as expected: after restarting the program I can test successfully with another website.
Does Firefox have different setting possibilities in regard of sessions than other browsers?
You should store $_SERVER['HTTP_REFERER'] in the user's session upon arrival. Using this method, the value won't be overritten when the user browses within your site.
session_start();
if ( !isset( $_SESSION['referrer'] ) ) {
if ( !empty( $_SERVER['HTTP_REFERER'] ) ) { // Because not all browsers set this
$_SESSION['referrer'] = $_SERVER['HTTP_REFERER'];
}
}
One way to do it would be to store somewhere (perhaps in a cookie or session, which easy to do with your PHP page) the page they're coming from, but only if that page is not on your website's domain. This would require some if-statements to set the cookie/session value appropriately, but it can be done relatively easily using particular parts of the referrer variable. There is probably a more efficient way to store this, but this is one that jumps to mind right away.
EDIT: I highly recommend George's solution, much better way to do this.
Have you tried using a session?
session_start();
if( !isset($_SESSION['refer']) )
{
$_SESSION['refer'] = $_SERVER['HTTP_REFERER'];
}
then, once your ready to make the button, set the link to $_SESSION['refer'].
In my past projects I usually stores the redirect url following this process:
search for a query string parameter url (www.yoursite.com/?redirect_url=my_encoded_url)
If search at point 1 doesn't return any results, then I checks for the HTTP_REFERER
In both cases, I stores that value in a SESSION variable after verified that the url belongs to my site's domain.

How to Create a One Time Offer for Values Passed in PHP Form?

I have an interesting problem to solve here that may require some creative direction. I have a PHP page which has a variety of different page outcomes depending upon which value is passed through the web browser. For example:
http://examplesite.com/landingpage.php?id=one
http://examplesite.com/landingpage.php?id=two
http://examplesite.com/landingpage.php?id=three
With the current set-up, each of these pages has a different offer for the site visitor. Here is the catch...
I only want the page available to the visitor once per session.
That seems like it would be easy enough, but I cannot make it work right. I have used a one-time offer script to submit a cookie which then re-directs the user to another page if they have already viewed the offer, but that did not work for this situation. It will work fine for one landing page, but it is based on the root PHP page so if any of the other values are passed it will re-route the user even though they have not seen the offer.
For example, if a site visitor goes to:
http://examplesite.com/landingpage.php?id=one
they will see the one-time offer. Then, if they go to:
http://examplesite.com/landingpage.php?id=two
They will be re-routed as if they had seen the offer for 'two' which they had not.
I hope this issue makes sense. If you need further clarification, just ask. Thank you for going through my problem and if you don't have the exact answer, but can point me in the right direction it would be much appreciated.
Without looking at the code for landingpage.php, I can only guess that you are not factoring in the id when you check for the existence of the cookie. You need to set cookies on a per-id basis. Otherwise the behavior you see will occur: viewing id=one will set a cookie and when the user views id=two, landingpage.php sees the cookie exists and redirects the user.
If you want to keep it simple enough, you can just have your cookie be a string of id fields delimited with a character such as a pipe or comma: viewed_ids=one,two,three. Then you could parse this to see if the id of the current page is in the list of viewed ids and redirect the user if it is, or add it if it isn't.
I am sure you realize that maintaining state in the session can be easily worked around by the user, since you mentioned you only need this redirection to occur on a 'per-session' basis.

What's the safest way to remove data from mysql? (PHP/Mysql)

I want to allow users as well as me(the admin) to delete data in mysql.
I used to have remove.php that would get $_GETs from whatever that needed to be deleted such as... remove.php?action=post&posting_id=2. But I learned that anyone can simply abuse it and delete all my data.
So what's the safest way for users and me to delete information without getting all crazy and hard? I am only a beginner :)
I'm not sure if I can use POSTs because there is no forms and the data isn't changing.
Is sessions good? Or would there be too many with postings, user information, comments, etc.
Ex: James wants to delete one of his postings(it is posting_id=5). So he clicks the remove link and that takes him to remove.php?action=post&posting_id=5.
EDIT: Alright, so now I am a little confused. While I can't be 100% secure, how do I do this with $_POSTs?
SOO I should use GETs to get all the data to remove.php, THEN have a confirmation submit button and when users click on it, it put all the data into POSTs and delete from the dbc?
Deleting records is a kind of a scary practice. If you or someone makes a mistake there's no real recourse to resolve the issue. Expunged records are very hard to resurrect.
Instead of deleting records, you could add an "active" bit (e.g. Boolean) column that is toggled off when users "delete" records. Essentially your users would be suspending records by toggling them off and the records would be saved in case mistakes or abuse but appear "deleted" to the user. To make this work with your other queries, just add a where clause of active = 1.
You could then have a utility script that's run at some specific date interval that would clean out deprecated, past dated records. You'd also need some type of timestamp for this type of maintenance.
Just a thought. Take if for what it's worth.
I'll echo gurun8 in preferring to 'mark' records as deleted, instead of actually removing data. And then obviously, you'll need to check that the authenticated user has permission to delete the post.
However, it seems very important to mention that $_GET is not safe even with authentication because of cross-site request forgery.
Imagine if Amazon adding things to your cart based on a GET request. All I'd have to do is put an image on my page with that URL, and everyone who visited that page and logged into Amazon will have products added automatically.
To match your example, I don't like Jame's post, so i put an image on my site like this:
<img src='http://example.com/remove.php?action=post&posting_id=5'>
And I send him a link to my page, and ask him to check it out, hoping that at the time he's logged in to your site. Because, of course, he clicked that little 'keep me logged in' button.
So you are right to be concerned about using GET. If you don't want to litter pages with forms, then confirm the action by POST.
Well you have to start by authenticating the users with a login script.
If you want the simplest solution possible, then I'd suggest protecting the directory in which you have remove.php with a simple .htaccess username and password.
If different users have different rights for deleting database entries, then you probably should create a PHP login script and use PHP session.
Bonk me if I'm stupid, but I searched for quite some time for a simple PHP login tutorial that could be placed on a real site (doesn't use session_register(), uses mysql_real_escape_string(), htmlspecialchars() etc) and I simply couldn't find one!
Probably this one comes the closest, you just have to replace session_register() variables with $_SESSION ones for it to work without register_globals (default in PHP5).

Categories