PHP security question - php

If I want people only accessing a certain page on my webpage by using a link within my website, and not typing it in the address box then would this do...
Please note that the user would first have to login to their account and all member pages have been set so that the user must login into their account before accessing member pages.
if (isset($_SERVER['HTTP_REFERER'])) {
// show page content
}
else {
header('Location:http://');
exit();
}
Am I correct in saying, that if a link is clicked then the page will show, but if the link is not clicked and the address of where the link points to is typed in the address bar it will do a redirect.
I am asking as the link will direct people to a form, and I don't want that form being accessed without first having some variables set on the previous page, or being accessed without logging in (as people could create their own link on another website which points to the same location)
Thanks

It is not secure in any way. From here:
The address of the page (if any) which referred the user agent to the
current page. This is set by the user agent. Not all user agents will
set this, and some provide the ability to modify HTTP_REFERER as a
feature. In short, it cannot really be trusted.

Users can set the referrer to whatever they want, so no, checking that that's set is not a secure way of checking that they came to your second page via the first.

HTTP_REFERRER can be spoofed pretty easily. When you want forms to be secure, implement some sort of CSRF protection by adding a hidden token to the field and ensuring it matches when you submit the form. Your best bet is to make sure their credentials are actually valid.

This seems very buggy to me; if you want certain variables to be set and / or a user to be logged in, just check for all these conditions at the top of the form-page and redirect the visitor somewhere else if the conditions are not met.

I'm unsure what you mean about having variables set from the previous page, or how you are achieving this. Its possible of course, but I would be interested how you are going about it.
You are correct in your question however, that when coming from another page the referrer will be set to that page. In terms of security however, its not a good idea to rely on it as it is easily spoofed. The only sure way is to ask for credentials (a username and password etc) which it sounds like you are already doing.
Could you not test to see if the variables are set, and if they aren't then redirect?

Related

Block access of a PHP page if visitor doesn't come from a certain page (on same domain)

As title says, I'd like to block visitors from viewing content of a page if they don't come from a specific URL. How can I achieve this? I have PHP over Nginx. Would it be better to use PHP or Nginx?
I read that using HTTP_REFERER is not the best idea because it's not mandatory for the browsers... what would you do (code examples)?
The most bullet-proof solution is to pass a _GET parameter that is not trivial to guess from one page to the next, a-la unique tokens.
It, however, takes a hell of a lot of effort to implement correctly, as it's not the simplest solution, and by far not the simplest to implement either.
In order of complexity, with the simplest at the top, your alternatives are:
Referer
Using a fixed GET parameter
Cookie placed on the user on the first page. Doesn't work for visitors not accepting cookies, and you'll need a cookie policy if you work in the EU.
Using nonces as GET parameters
The last solution in detail
your initial page generates a one-off string, and appends it to every link. You then check if this string is matched with an entry in a database/flat file, and if so, allow access. If not, you deny access. You then invalidate the token so users have to go through the page again.
Probably not perfect, but I would set a $_SESSION on the initial page and then check and remove it on the linked page.
$_SESSION['allow'] = 'yes';
then on the next page
if(isset($_SESSION['allow']) && $_SESSION['allow'] == 'yes') {
$_SESSION['allow'] = 'now viewing';
}
Or something like that....
The only way to restrict access to pages is by using someone's credentials, there's no reliable way to detect where the user came from since that can be spoofed.
Therefore there is no way to allow access to a page B only if the user just came from page A (unless you do it unreliably through HTTP_REFERER
You could also set a cookie (or session variable) on page A and not display page B unless the user had the cookie (session variable) set, but that would not require that the user be going straight from page A to page B
A simple way would be to set a one-time session variable on the first page, and read that variable on the second page.
For example, page 1:
$_SESSION['viewed_page1'] = true;
Page 2:
if(!$_SESSION['viewed_page1']){
echo 'You need to visit page 1 first!';
}
.
you can use a session variable and pass a particular 'key' from one page, and require it on the following page in order to display it.
you can find info on sessions here

PHP Beginner Security Fear

I'm a tech writer who has done a lot of HTML/CSS but have been thrown into a pressure cooker to rewrite a web app in PHP and have done fairly well, but I'm a bit concerned re the security.
Specifically, the main page is INDEX.PHP, where the user logs in. Once they are logged in, the page rewrites portions of itself and shows menu options not available to users who aren't logged in. About 50% of the users will never need to login since they'll be viewing public documents for which no security is needed. The other 50% of users will have restricted viewing access to certain documents/pages and be able to write to a database.
I got all of this working fine, but am concerned about two things I'm doing and whether they're proper:
A logged-in user might get redirected to another page, say PAGE1.PHP. I don't want them to be able to save the URL for PAGE1.PHP and just go directly there, bypassing security, so on PAGE1.PHP I have a check for a log-in cookie I created on INDEX.PHP. If the cookie exists they can go to the page, if not they can't. Is this the right way to do this type of thing?
How do I stop a malicious user from inserting a redirect into one of the many text boxes on my various forms? I need to allow HTML, such as strong, font, background, etc. I've been running all the text box values through a function that checks for possible malicious things, one at a time, such as "meta http" or "anchors" or "java script" but I'm not sure this is the best solution.
Thanks for your help!
$_SESSION will be your friend. In a normal shared-hosting environment, $_SESSION may not last any longer than, uh, the current session so plan accordingly. (IE, don't rely on it for anything more than logging in.)
You'll need to read up on session_start and friends.
In addition, check out this discussion: PHP HTML sanitizer for sanitizing HTML input. (Just as an FYI, there is a reason why bbcode and markdown are so popular.)
No - every client can manipulate his cookies and send everything they want - even a invalid "login" Cookie. You have to store those Information serverside in sessions
You could use strip_tags to only allow some Special tags or use a html sanitizer
1 . Upon successful login, store a new $_SESSION variable, say, the user ID (since that seems to be needed often)
Example:
if(login is successful)
{
$_SESSION['userId'] = $userId;
}
Create a php auth page that checks to make sure the session var is populated. If not, redirect to access denied or login page.
Example:
if(! isset($_SESSION['userId']) || $_SESSION['userId'] == '')
{
header("Location: accessDenied.php?msg=Not logged in");
}
On each secure page, require('auth.php');
2 . You can use strip_tags on the textbox, and mysqli_real_escape_string on user-input that ends up going to the database. (Or use prepared statements, see Best way to prevent SQL Injection in PHP)

PHP sessions and security

I'm trying to decide on the level of security with regards to session management on my php site. at the top of every page is a php tag where I run
if (!isset($_SESSION["user"])) {header('Location: login.php');}
The User session is created on login, do you guys think this is secure enough? The whole site runs in SSL.
Well, being secure has 100's of different topics... But in terms of what you are trying to achieve, yes I think that's fine
I would add some additional validation to checking that $_SESSION['user'] is definately a correct user, and try to compare the session user's IP Address, USER AGENT and other things to detect Session Hi-Jacking
You should also EXIT; after header("Location: X"):
header("Location: xyz.php");
exit;
Yes that will work. To make it less error prone put that snippet in a file and include it at the top of each page. That way you just edit one place to make changes to the logic.
Also, your Location header is supposed to contain the entire URL starting with https: according to the RFC specifications. It may still work for some browsers but should not be depended on.
I think it's better to create a random token string when your user wants to login to your website. Then check it in every page beside your previous code. I used $_SERVER['REMOTE_ADDR'] , $_SERVER['HTTP_USER_AGENT'] and a random string to make it.
Well, at least once per load you will need also validate the user, otherwise you are just checking if the session exists.

How to go about implementing a "confirm password" page, when the user is already logged in?

On my website that I'm developing I've already got all my login sorted, and it works correctly, including session saving.
To improve the user's security and privacy I'd like to implement some kind of "confirm your password" page whenever the user requests to view a sensitive page (such has an activity log, or changing some settings) to further prevent against session hi-jacking. I am, however, not sure how to go about doing this.
I'm unsure of the security best practises for this, and as this project site is a learning curve for me, I'd appreciate being taught.
The structure that I think I'm aiming to achieve may be like this: current page --(user goes onto history log)-> Please confirm your password --(user gets the correct password)-> history log page 1 --(user wants the next page of the history log)-> history log page 2 --(user goes to the home page)-> home page --(user goes onto history log)-> Please confirm your password --(user gets the correct password)-> history log page 1
From what I understand about doing this correctly I need to make it so that once the user navigates away from the History Log they're no longer authorized to view it.
If someone could provide some tips on how to do this I'd be greatly appreciated. I've tried to search for some tutorials, but couldn't find any (it's completely possible I chose bad search terms), if someone could even just offer a link to a tutorial then that would be greatly appreciated too.
Thanks, Jordan.
I would simply add a $_SESSION variable for this user that gets reset when he navigates on any page that is not the history log.
Further more, i'd use a general mechanism like this:
On all your pages, set a
$page_section = 'something';
And then, include a small snippet that does:
if(isset($_SESSION['last_visited_section']) && $_SESSION['last_visited_section'] != $page_section){
//New section visited, you could reset $_SESSION['last_visited_section'] or anything relative to your security mechanism here
}
Is that of any help?
If you are concerned about session hijacking, use https and set the session cookie https only.
For confirming a password, ask them to enter it the same way you do for login and check to make sure the hash matches what it is your user table the same way you do for login.
I create an object called $scookie which I use to define how I want my sessions.
session_set_cookie_params(
$scookie->lifetime,
$scookie->path,
$scookie->rootDomain,
$scookie->secure,
$scookie->httponly);
session_start();
In above, when I am concerned with hijacking (anything that has a user login), I make sure $scookie->secure is set to true.

Client Side Data saving with PHP/Javascript

I want to make a website that would be like craiglist.org. If you go the site and click on any of the city it will redirects you to the city subdomain. And after that anytime you go to the craiglist.org it will redirect you to the city subdomain. So I need to keep the city/country name to my client's machine.
At first I thought I can do it by Cookie with setting expire time. I tried that but the expire time is not working as when i close the browser that means when session ends it is not getting the cookie anymore.
But if it was ok with cookie then also it may not be ok for the destination as if I browse the site from Mozilla and closed and open the site with IE it should redirects me to the visited site that is not possible with cookie i think?
Can you please give me some suggestion ? How can I do the thing. I am going to do the application with Codeigniter/Php.
Thanks
Sumon
cookie is the right approach.
you cant achieve something cross-browser ... well you could use flash cookies or re detect the ip adress etc but thats stupid...
well craiglist.org seems to redirect me according to where my ip adress comes from.
to do this you should check out this site: http://www.maxmind.com/app/geolitecity
generally speaking you should always give the user the possibility to switch by hand.
from a usability optimizing point of view i would suggest the following scenario:
user hits welcome page
welcome page detects city of the user using geoip
3.1 if city has been detected successfully user gets bounced directly to the subsite, cookie is saved
3.2 if city is not successfully detected, welcome page shows a selection list. once the user clicks a selection list the cookie is set and the user gets the specified subsite
on every subsite there is a well visible button on the top "switch city" or something.
if the user clicks it he gets to the welcome page, but with a parameter "userelection=true" ro something, so that the automatic ip detection and redirection doesng kick in.
the user selects the desired subsite, gets a cookie and gets redirected.
5.
if the user hits the welcome page again and a cookie is found he is redirected to the subsite, cookie can be overriden, thats no problem...
the easiest and bset solution would be setting the cookie using php and then do a header redirect!
this way you eliminate javascript, which can be turned off or something.
just use this php command:
setcookie("city", $value, time()+(86400*365));
or something similar. heres the manpage:
http://php.net/manual/en/function.setcookie.php
you can check for cookie values using
if($_COOKIE['city'] != '')
edit:
well as of the confusion i have an working example for you here now, just paste it into a php file and save it to your webserver :) the check for subsite won't be necessary as you said you are redirecting to external sites (subdomains) anways.
keep in mind that you cannot access a cookie from a subdomain if you set it on another subdomain! maby this was your problem, therefore the checking and redirecting int he bootstrap file.
well here you go. any questions? comment!
<?
/* this is if we are at a subsite. you wont need that as it will be external subdomains anway just for the purpose of a working example here.*/
if($_GET['subsite']!="") {
/* the change link has the paramenter userselection which overrides any autoamtic detection by cookie or ip or whatever, this is important if the user wants to change or the automatic change fails or is wrong*/
?>
you are now at the subsite of <?=$_GET['subsite'];?><br/>
click here to change
<?
}
else {
/* only try to automatically redirect if we have either cookie or user specified data, but dont if the flag userselectino is true. because the user wants to change.
you could ip-detect the city at this point.
*/
if(($_GET['go']!=''||$_COOKIE['city']!='')&&$_GET['userselection']!='true') {
/* if we had ip detection the priority of it would probably go here */
$target=$_COOKIE['city'];
/* the get varaible overrides the cookie value as its user supplied and more important*/
if($_GET['go']!='') {
$target=$_GET['go'];
}
/* set the cookie, don't care if it already has been set*/
setcookie('city',$target,time()+(86400*365));
/* redirect the user */
header('Location: ?subsite='.$target);
}
else {
/* well we either have neither cookie nor user specified city or the user wanted to change teh city, lets display the selection dialog!*/
?>
hello! select your city:<br/>
vienna
new york
<?
}
}
?>
The cookie is the best way to do this; if the web browser's cookie is not being reloaded after closing the browser, you must have something wrong when creating the cookie.
Have a look at the PHP docs for setcookie(): http://us3.php.net/set_cookie, make sure you are providing an expire time far in advance, such as strtotime("+300 days"). On the server, to read the cookie back, simply use the $_COOKIE super global. Link: http://us3.php.net/manual/en/reserved.variables.cookies.php
Also, be sure to check your browser settings for the handling of cookies... maybe it is set to delete cookies after closing the browser.
Finally, you could also use the user's IP address -- but be warned that users can share the same IP address if they are on the same local area network, such as a university or corporation. You could even auto-choose the location by using an IP location lookup service such as http://ipinfodb.com/
You can inspect your website's cookies in Firefox by going to
Tools -> Page Info -> Security -> View Cookies
It seems illogical to try to save browser state across browsers. If a user switch browser, they are usually not guaranteed to have the same browser settings, unless they have an account on that site.
If they are registrered users, you should store whatever state you need in your database, and retrieve it on login. Then you can always cache the data in a client-side cookie, so you don't need to fetch it everytime.
In my opinion, storing browser events across different browsers for anonymous users would not be worth the efford.

Categories