So my question is very basic.
When checking if a user is still logged in on any page, I'll use
if (isset($_SESSION['user']) && $_SESSION['user'] == true) { CODE }
But, shouldn't I use a hashed value instead of a boolean value for the $_SESSION['user']?
All the guides I find are using boolean values, but from my point of view that is a security leak, isn't it? People are talking about Session-Hjacking and Session-Fixation all the time, and that would be very easy if I just used boolean values for the user-session, woulnd't it? Or am I just mixing things up here?
Thank you
I read two questions here. The first question, 'What is the best practice to determine if a user is logged in?" and the second question 'Is there a concern of Session-Hjacking and Session-Fixation?'
First question:
Most web apps/cms I have worked with have a user object. There is nothing particular special about this object from a code perspective, its just an object representing the user. The currently logged in user has their user object stored in the session. $_SESSION['user']
In Drupal (and other platforms) the a function is used to return the currently logged in user, or False if the user is not logged in.
Example:
function user(){
if( isset($_SESSION['user') and
is_object($_SESSION['user'] and
get_class($_SESSION['user']=='myUserClass')) ){
return $_SESSION['user'];
}else{
return False;
}
}
So in your example we see if ( user() ) { CODE } works because all object evaluate as True in an if clause.
Second Question: Session-Hjacking and Session-Fixation are not really concerns here. The client (a web browser) does not have access to the server's $_SESSION array. So in short, yes you are mixing things up here.
Related
I received some pen tests results.
The results say that anybody can update any record by just changing a certain id.
How could I ensure that the user can only update his own record in this function?
public function actionUpdateProfile()
{
$postdata = file_get_contents("php://input");
$response = array("status" => "1", "message" => "Profile update successful.");
$data = json_decode($postdata);
$model = HosDoctors::model()->findByPk($data->doctor_id);
foreach ($data->fields1 as $field) {
$_POST[$field->name] = $field->value;
}
$enc = NEW bCrypt();
$model->attributes = $_POST;
if ($model->save()) {
$response = array("status" => "1", "message" => "Profil erfolgreich aktualisiert");
} else {
pr($model->getErrors());
}
echo json_encode($response);
die;
}
Would it be sufficient to simply check for
if (cookie == $data->doctor_id)
{
//ok
}
else
{
//we are not logged as the user id that we want to update, so deny updating
die;
}
I am assuming the person has "logged in" in some way so that you know "who they are". While security is complex and is definitely not a one-answer topic; at its simplest level, once you have identified the user, use PHP session handling to persist their identity across one or many http/s requests, then internally access any related information using the session cookie id for the duration of the session.
There are several potential issues in this function (unless you posted a heavily edited version). I'll note them as comments.
public function actionUpdateProfile()
{
$postdata = file_get_contents("php://input");
$response = array("status" => "1", "message" => "Profile update successful.");
// Never initialize responses until you really *must*. Chances that a partially prepared response might be output are slight, but why run risks?
// And actually you **do** reinitialize $response later on!
$data = json_decode($postdata);
// You are not verifying that $data *exists* (i.e. the JSON data was, indeed, JSON). You should check that $data is not NULL and that it does have **all** the required fields and that they are valid.
// This is the point where you validate $data->doctor_id, by the way. Or you check that patient_data matches with whatever you have in your $_SESSION or Session app object.
$model = HosDoctors::model()->findByPk($data->doctor_id);
// This is a bad practice. Yes, you have some code that relies on
// _POST. If necessary, wrap it in another code that will set up
// _POST from an input and then delete it. Otherwise you're leaking
// data into a superglobal. You don't want to do that.
foreach ($data->fields1 as $field) {
$_POST[$field->name] = $field->value;
}
// Why are you initialising $enc?
$enc = NEW bCrypt();
// This is not very good. $_POST could contain *other* information
// unless it's been sanitized outside the function.
// I would prepare a setter function, $model->setArray($data), that
// would verify the validity of the attributes before setting them.
$model->attributes = $_POST;
if ($model->save()) {
$response = array("status" => "1", "message" => "Profil erfolgreich aktualisiert");
} else {
pr($model->getErrors());
}
// This works in 90% of the browsers and scenarios. But I'd
// set up a function that would also send the appropriate
// Content-Type headers to satisfy the remaining 10%.
echo json_encode($response);
die;
// e.g. Utilities::jsonResponse($response);
}
Would it be sufficient to simply check for
if (cookie == $data->doctor_id) {
//ok } else {
//we are not logged as the user id that we want to update, so deny updating
die; }
try checking by user token instead of user-id because user-id can be found within some page url or body but the token is hard to get unless using network sniffing technics.
you can generate user token by any token generation method and then store it as a column in the user table in your database.
token generation method e.g
$token = bin2hex(openssl_random_pseudo_bytes(16));
# or in php7
$token = bin2hex(random_bytes(16));
Would it be sufficient to simply check for
if (cookie == $data->doctor_id)
{
//ok
}
else
{
//we are not logged as the user id that we want to update, so deny updating
die;
}
No, in principle this is actually the same as you already have: the ID is still part of the request and can be changed like you got it reported.
Instead ensure the request is first of all authorized, then fetch the related data from the identity and access management system.
If you do not have anything to manage identity and access, choose a system and integrate it first.
From the code you've posted so far it is not visible (to me) whether or not such a system exists. Therefore I can not specifically answer on that detail.
Authentication/Authorization of requests is part of the HTTP protocol and is supported at a basic level in PHP out of the box. See:
HTTP authentication with PHP Docs
If you want to roll your own completely you can consider HTTP state management with PHP sessions, but as you ask the question the way you ask it (with all due respect), my suggestion is to take something that already exists, is proven and easy for you to understand and integrate (less complexity = better software and less flaws/holes).
Take the event of the pen test and its result to address the design issues first and find a high level solution not that you need to patch multiple endpoints individually only to address the same basic flaw.
Let the system work for you.
After the pen-test I would also suggest the code is reviewed with dedication towards the found issues and the code writers are trained based on the results of both.
Would it be sufficient to simply check for ...
Yes, given the cookie is from a safe source and all its properties are secure. E.g. only the identity and access management system can add it to the HTTP request that hits the PHP SAPI.
I would rate this event very unlikely as you needed to ask the question.
And it would be very unorthodox if it would contain a concrete id. There should always be a HTTP state management and it should be rolling to protect against replay attacks with credentials or at least limit the time-frame in which they are valid.
But purely technically, with the right design and implementation I can imagine there can be systems that work this way (HTTP request with cookie as secure token).
Take care.
This is more of a concept question. I would like to get an advice from very experienced members on how to better arrange my code. Often when handling user's requests we need to check their privileges in order to determine their rights to execute some function or method. The question is whether it is better to verify access rights prior to executing a function like so:
//handling some POST data from AJAX
//lets assume we have some function check_some_rights() which takes user id as argument and returns 1 if user has some right or 0 if he/she doesnt
if (check_some_rights($user)){ //the privileges are verified
some_function_that_does_some_stuff()
} else {//nope, this user got no right to do this
echo "Like hell you do!";//denying access to this user
}
Or is it better to check access rights as soon as execution of function is initiated like so:
//alternative solution with embedded privilege check
function some_function_that_does_some_stuff($user){
if (check_some_rights($user)){//the privileges are verified
//go on with the procedure
// ...
} else {
echo "Like hell you do!";//denying access to this user
}
}
I personally believe that the second approach would be better, because we wouldn't have to worry remembering to check privileges each time, but opinions of people with more experience are needed and would be highly appreciated. Thank you.
i am new to PHP so don't know how this would turn out. Lets say i have a add friend page. And in the database lets say i have a table called "friends" and the following rows: my_id and friend_id and id_request.
And now i have a php page that will look something like: addfriend.php?id=friendid
And then i use the id from that link to insert in to the database my id and that friendid.
The question is what will happen if someone enters "kdjfkldjlfk" in the link in the address bar?
you need to prevent those cases and validate
ex:
test that the $_GET['id'] isset and that the friendid is real , you could query the database to see that the id exists ...
If you mean "What will happen if someone visits the URI for an id that does not exist?", then it depends on what your PHP says should happen.
If your PHP doesn't check how many results it got from its SQL query, then it is quite possible that the page will spit out a 500 Internal Server Error.
If you've designed it properly, then it would return a document that explains that you cannot add a user that does not exist as a friend.
Actually, if you've designed it properly then the data should be sent via POST not GET since adding a friend is not an idempotent event. (See the HTTP specification — GET should be free of side effects)
You need to validate your user input. First, cast the $_GET value to an int type, and if it's equal to 0, tell them they've mistyped it.
$var = (int)$_GET['id'];
if($var == 0)
{
// Error
}
else
{
// The rest of your code
}
It turns out that PHP has some pretty cool filter functionality built-in. You should learn them and use them:
if (filter_var($_GET['id'], FILTER_VALIDATE_INT) === false) {
// error
}
if (filter_var($_GET['email'], FILTER_VALIDATE_EMAIL) === false) {
// error
}
if (filter_var($_GET['ip_address'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
// error
}
http://us.php.net/manual/en/function.filter-var.php
I am trying to setup drupal 7 so that was when users signs-in for the first time they are presented with a terms of use (I have tried the terms of use module but it doesn't suit my needs as it only seems to work when the user creates the account and in our instance all accounts are created by the admin), and as is standard the user has to agree to these terms inorder to use there account.
For the second part of this once the user logs and agrees with the terms they have to be presented with the edit profile form to make necessarily updates.
Does anyone know of anyway to set this up (preferably without alot of development as this project is short on time)??? Any help is greatly appreciated.
You know that user has not logged in yet if their "access" and "login" values are 0. So it should be enough to check them and if they are 0, redirect user to your T&Cs. In theory at least.
The easiest solution (that comes to my mind right now anyway) would be something like this:
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'user_login') {
$form['#submit'][] = 'MYMODULE_user_login_submit';
}
}
function MYMODULE_user_login_submit($form, &$form_state) {
$user = user_load($form_state['uid']);
if ($user->access == 0) {
$form_state['redirect'] = 'your-terms-and-conditions-form-url';
}
}
hook into "user_login" form and add own submit function
in own submit function check both mentioned values, and if they equal 0, redirect user to your T&Cs
The thing is that our submit gets called after main user_login_submit(), where (well, not exactly there) "login" value already gets updated - therefore we can check "access" field.
The rest sounds easy enough - page with T&Cs and agree form, redirecting to user profile edit afterwards, easy-peasy...
I need a login to let 10 students to view educational material. Simple is good.
Perhaps it just redirects to a page if student logs in correctly. Can you send me a link or example, or best tutorial?
I was told JavaScript alone doesn't work, so the next simplest thing is preferred.
If there's an example where I don't have to rename all of my pages 'php', that would be better.
Thanks,
I used this when I was learning to do secure logon using PHP.
http://www.devshed.com/c/a/PHP/Creating-a-Secure-PHP-Login-Script/1/
Found it quite helpful.
Simple...
Create a file called functions and insert the following:
session_start();
$_GLOBALS['users'] = array(
//'username' => 'password'
'robert' => 'my_pass'
);
function isAuthed()
{
if(empty($_SESSION['logged_in']))
{
if(!empty($_REQUEST['username']) || !empty($_REQUEST['password']))
{
if(isset($_GLOBALS['users']) && is_array($_GLOBALS['users']))
{
if(isset($_GLOBALS['users'][$_REQUEST['username']]) && $_GLOBALS['users'][$_REQUEST['username']] === $_REQUEST['password'])
{
$_SESSION['logged_in'] = true;
return true;
}
}
}
}else
{
return true;
}
return false;
}
and then in your secured pages just do:
if(!isAuthed())
{
die("You're not authorized to see this page");
}
and on your login page just create a form that sends the username, password to the an area of your site that your authorizing
Note: This is not copy and past'able code, this is for example purposes only.
You could possibly "do" it with JavaScript if you did some kind of AJAX function which called a php page, and then returned your value. This could work, and it's how a lot of sites do their logins actually. So, your client wouldn't have to rename their site, and you could just set up an array of logins on the php page.
This would NOT be secure at all, but it would work just fine.
I guess you would do something like this (I'm going to use jQuery because it's easier to do Ajax with it. It's really easy to use, and if you're going to learn Javascript, it's probably better nowadays to know the basics and then use a framework library like jQuery)
$(document).ready(function(){
$("#NAME-OF-SUBMIT-BUTTON").submit(function(){
var username = $(this).find("#username");
var password = $(this).find("#password");
$("NAME-OF-DIV-FOR-RETURN").load('login.php', {['parameters']:,[username,password]},function(responseText){
if(responseText == 'SUCCESSFUL-RESPONSE-TEXT'){
$("#NAME-OF-FORM").html("Login Successful");
}
});
});
});
and of course you're going to want to set a session variable or cookie or something on your php page to indicate the user has logged in. Again, this is not very secure, but it's what I would do if it were like a homework assignment or just SUPER temporary. Of course, I would suggest making hard-coded usernames and passwords in an array on your original page in PHP with a postback to itself if you were going to go that temporary. Using Javascript and Ajax for this just seems like a bit much.
But, you requested it!
It depends on exactly what you're trying to do. If you want a pure-JS login system, you could do something fairly simple like XOR'ing a redirect page with a password, storing that in the page and then XOR'ing it again when they type in a password.
If you want an actual login-system, you need a back-end running some server (perhaps Node.js if you're trying to learn JavaScript), some type of database (e.g. MySQL), users stored in that database.
The front-end javascript might be responsible for validating the login via ajax. Using jQuery, something like:
function validateLogin(user, pass, successCallback, errorCallback){
$.get('/login', {user: user, pass:pass}, function(data){
if(data.status == 'success'){
successCallback();
}else{
errorCallback();
}
}
}