Trying to read someone's code re cookies - php

I am trying to read some code here (not my own) and make changes. So far what I can get from reading it is that if a variable named $cuid is NOT set, it sends a user to a splash page. If it IS set, it sets the cookie to the $cuid variable (which is actually not happening, the cookie isn't updated when you come with a new CUID in GET)
Here's the code:
if (!$cuid || $reset)
{
$cuid="";
if( $cuid_demo!="samplecu" && $cuid!="75541953" )
setcookie("cuid","",time() - 31536000); //DELETES COOKIE
$query="UPDATE cusucceed SET kkc_visits=kkc_visits+1 WHERE id = '$cuid'";
$result=dbquery($link, $query) or die("error: ".dberror() );
include("splash.php");
}
else
{
setcookie("cuid","",time() - 31536000); //DELETES COOKIE
setcookie("cuid",$cuid,time()+604800); //1 week.
select_db($link) or die("error: ".dberror() );
if($admin_id)
{
$cuid=$cuid;
$id=$cuid;
}
$query="UPDATE cusucceed SET kkc_visits=kkc_visits+1 WHERE id = '$cuid'";
$result=dbquery($link, $query)or die("Database Server Error 2");
include("index_main.php");
Am I reading that correctly? The else part of the if statement should be setting the cuid cookie to $cuid, if $cuid is set, yes?

If $cuid is unassigned (more explicity, has a false result [albeit 0, false, empty]) or it should be $reset,
- Force-empty the cookie (assuming it's not [what appears to be] a test account)
- Display the splash page.
If $cuid is set (and it's not a $reset),
- Re-declare the cuid cookie, and make it last for a week. Then also display the main page.
In both instances,
- Increment the number of times the found $cuid has visited the page.
Although to be honest, it looks like the author wasn't really sure what they were doing based on duplicated code and that they feel the need to empty a cookie before re-declaring it.

Related

PHP session security - canary session

I am learning PHP after using Classic ASP since 2001.
I've come to the point of working out how to secure the admin section of a site I'm working on, and have been reading here:
https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions
I've seen that it appears to be bad practice to bind a session to an IP address - e.g.
Check if the $_SERVER['REMOTE_ADDR'] matches $_SESSION['ip']
As taken from the link above:
Some systems like to bind a session to a particular IP address. This is not generally recommended; Tor users, in particular, will have difficulty staying authenticated. You can enforce this restriction here too.
session_start();
// Make sure we have a canary set
if (!isset($_SESSION['canary'])) {
session_regenerate_id(true);
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
if ($_SESSION['canary']['IP'] !== $_SERVER['REMOTE_ADDR'])) {
session_regenerate_id(true);
// Delete everything:
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// Regenerate session ID every five minutes:
if ($_SESSION['canary']['birth'] < time() - 300) {
session_regenerate_id(true);
$_SESSION['canary']['birth'] = time();
}
I can't work this one out - is the blog post saying that it is wrong to bind a session to an IP address, and then posting code showing how you can do that?
Or is the "canary" session code they use not actually binding a session to an IP address?
Assuming the code isn't binding a session to an IP address and that it would be good practice to use it, then I'm a bit confused about how I would use this canary session - would I put this bit on my login page, once a user has successfully logged in:
// Make sure we have a canary set
if (!isset($_SESSION['canary'])) {
session_regenerate_id(true);
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// set my own session variable as well
if (!isset($_SESSION['name'])) {
$_SESSION['name'] = $name; // $name = value from database
header('Location:admin-home.php');
exit;
}
And then put these bits at the top of any pages which are user protected:
session_start();
// ####################################################################################################
// Is User Logged In?
// ####################################################################################################
$name = $_SESSION['name'];
if (!isset($name)) {
header('Location:login.php');
exit;
}
// ####################################################################################################
// Canary Session?
// https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions
// ####################################################################################################
if ($_SESSION['canary']['IP'] !== $_SERVER['REMOTE_ADDR']) {
session_regenerate_id(true);
// Delete everything:
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// Regenerate session ID every five minutes:
if ($_SESSION['canary']['birth'] < time() - 300) {
session_regenerate_id(true);
$_SESSION['canary']['birth'] = time();
}
I will also be using HTTPS for the login and admin pages.
The way PHP handles sessions, is to generate a unique session id for each user, and store it in a cookie (default name PHPSESSID). This works well across IP changes, and gives different session on different browsers on the same machine.
To give more security, you can also save user ip and user agent in session, and check that on every request. I'm not sure whether PHP does this by default or not, but it would be rather simple to implement it.
You can also look for session implementation on famous frameworks (Laravel, Symfony, ...) to see how they do it. I leave it to you to further investigate topic, as it should be a bit of googling and reading source code.

Cookie Not Grabbing All Codes

On Page Variable =
$lgc_code = '1,2,3,15,23,30';
Cookie = 'lgc_cntl'
My cookie is housing logic codes for each user to determine what banners or icons should show based on previous web pages visited. I have written the following function:
$lgc=$lgc_code;
// check for variable for multiple codes
$expEncArr = explode(",", $lgc);
$results = count($expEncArr);
if(isset($_COOKIE['lgc_cntl'])) {
// read cookie
$cookie_codes = $_COOKIE['lgc_cntl'];
// Build Array of cookie codes
$expEncArr2 = explode(",", $cookie_codes);
foreach($expEncArr as $l_code) {
if(in_array($l_code, $expEncArr2)) {
$lgc_codes=$_COOKIE['lgc_cntl'];
} else {
$lgc_codes=$_COOKIE['lgc_cntl'].','.$l_code;
} // end array search statement
// add campaign to cookie
setcookie('lgc_cntl',$lgc_codes,time() + (86400 * 365), "/", ".oru.edu"); // 86400 = 1 day
} // end foreach statement
} else {
$lgc_codes = $lgc;
// add campaign to cookie
setcookie('lgc_cntl',$lgc_codes,time() + (86400 * 365), "/", ".oru.edu"); // 86400 = 1 day
} // end isset(cookie) if / else statement
If there is no cookie set, the function works perfectly but if there is a cookie found it only adds the last variable in the array versus any codes not found in the cookie already.
The function should work as follows:
Separate on-page variable into an array
Check for the cookie
Separate Cookie values into an array
Compare the variables on page to values in cookie
Add any on page variables not found in the cookie
It is working all the way through but when the cookie is set, it is only adding the last variable in the string even if none of the others are not located in the cookie array. What am I doing wrong or how can I solve this?
This is a common mistake - $_COOKIE is not affected by calling setcookie. This is because $_COOKIE is created at the beginning of the PHP script execution based on data sent from the browser, and setcookie sends data to the browser.
Consequently, each time you run this line:
$lgc_codes=$_COOKIE['lgc_cntl'].','.$l_code;
Your value of $lgc_codes is the cookie string originally sent by the browser plus exactly one extra code.
The solution is to instead use a local variable, such as $new_cookie_value, to build up the full string, and then call setcookie once:
$new_cookie_value = $_COOKIE['lgc_cntl'];
foreach($expEncArr as $l_code) {
// if statement removed to keep example brief
// Add extra code to list
$new_cookie_value = $new_cookie_value .','.$l_code;
}
// Now call setcookie once with the desired value
setcookie('lgc_cntl',$new_cookie_value,time() + (86400 * 365), "/", ".oru.edu");
[Aside: Do not underestimate the value of good variable names. Your code would be much clearer if $expEncArr and $expEncArr2 had longer names which described what the difference was between them. Similarly, $lgc, $lgc_code, $lgc_codes, etc.]
Your logic is very muddled. This is what should be in the first portion of your if block
// read cookie
$cookie_codes = $_COOKIE['lgc_cntl'];
// Build Array of cookie codes
$expEncArr2 = explode(",", $cookie_codes);
$lgc_codes = $_COOKIE['lgc_cntl'];
foreach ($expEncArr as $l_code)
{
if (!in_array($l_code, $expEncArr2))
{
$lgc_codes .= ',' . $l_code;
}
}
setcookie('lgc_cntl', $lgc_codes, time() + (86400 * 365), "/", ".oru.edu");

Change Session ID Once Started

I am using Zend framework 1 and I need to change the session id at runtime with a predefined prefix, however I am getting the following error "The session has already been started. The session id must be set first." The issue is that the session state still remains started even after calling the destroy and writeclose. I also tried using the php methods unset & destroy but still same issue.
$oldSession = new Zend_Session_Namespace();
Zend_Session::destroy();
Zend_Session::writeClose();
$sessId = "dskjfghdsjfhsdkf"; //Random hash
Zend_Session::setId("myprefix".$sessId);
$newSession = new Zend_Session_Namespace();
foreach($oldSession as $idx => $data){
$newSession->$idx = $data;
}
Looks like it is not possible,
Snippet from Zend_Session.php:
if (!self::$_unitTestEnabled && defined('SID')) {
/** #see Zend_Session_Exception */
require_once 'Zend/Session/Exception.php';
throw new Zend_Session_Exception('The session has already been started. The session id must be set first.');
}

Set cookie fails for first time but works on refresh

Though after reading explanations about setting cookie and not working for first time i find it difficult to resolve the below problem as am new to php and cookies.
I have a webpage with for (e.g) cp.php, login.php, header.php, maindata.php , bottom.php. Whenever i login to the webpage cp.php will be processed from there 1.header.php will be called first 2.maindata.php will be called and 3.bottom.php will be called.
So am setting my cookie at maindata.php and the code is like,
<?php
$cid = $_GET["id"];
$XmlPath = $_GET["path"];
$numpath = $_GET["numpath"];
$finepath =$_GET["finepath"];
$Tech =$_GET["tech"];
$read_str="";
function read($Path)
{
$temp="";
if(file_exists($Path))
{
$library = new SimpleXMLElement($Path,null,true);
foreach($library->children("SAS") as $info){
foreach($info->children("SAS") as $attributes){
$nameVal = $attributes->Name."=".$attributes->Value;
$str_temp .=$nameVal."#";
}
}
}else
{
$str_temp ="NA";
}
return $str_temp;
}
$arrpath =explode(",",$XmlPath);
/*Reading and storing arrpath[0] has the path of xml to be parsed*/
$strG=read($arrpath[0]);
$strC=read($arrpath[1]);
$strB =read($arrpath[2]);
setcookie($cid.'strE',$strG);
setcookie($cid.'comstr',$strC);
setcookie($cid.'basstr',$strB);
(....)
in the same file am reading the cookie using the below code,
$read_str =$_COOKIE[$cid.'strE'].$_COOKIE[$cid.'comstr'].$_COOKIE[$cid.'basstr'];
after this process is done bottom.php will be called and for the first time loading is completed.As i said for the first time am not getting any value in $read_str, but if i refresh the page and do all the process again i am getting the value.
As SETCOOKIE will return TRUE incase of successfully setting cookie i tried putting it in an if-loop and it returned false even for the first time.
kindly assist me in finding where the problem exists!
Make use of isset to check if a cookie exists and then try setting one.
Something like this.
if(!isset($_COOKIE['yourcookie'])) {
setcookie('yourcookie', 'Some data !');
$_COOKIE['yourcookie'] = 'Some data !';
}
echo $_COOKIE['yourcookie'];
I arrived here looking for an answer as well. Here's the deal.
When you set a cookie it can only be accessed on the next page load, that is why you can't access it after you set it. If you really need to work with the cookie data right away, you could set the value directly in global cookie such as:
$_COOKIE['my_cookie'] = 'i am a cookie';
Use setcookie()just the same so you can set expiration, domain, etc..

How to get cookie's expire time

When I create a cookie, how to get cookie's expire time?
Putting an encoded json inside the cookie is my favorite method, to get properly formated data out of a cookie.
Try that:
$expiry = time() + 12345;
$data = (object) array( "value1" => "just for fun", "value2" => "i'll save whatever I want here" );
$cookieData = (object) array( "data" => $data, "expiry" => $expiry );
setcookie( "cookiename", json_encode( $cookieData ), $expiry );
then when you get your cookie next time:
$cookie = json_decode( $_COOKIE[ "cookiename" ] );
you can simply extract the expiry time, which was inserted as data inside the cookie itself..
$expiry = $cookie->expiry;
and additionally the data which will come out as a usable object :)
$data = $cookie->data;
$value1 = $cookie->data->value1;
etc. I find that to be a much neater way to use cookies, because you can nest as many small objects within other objects as you wish!
This is difficult to achieve, but the cookie expiration date can be set in another cookie. This cookie can then be read later to get the expiration date. Maybe there is a better way, but this is one of the methods to solve your problem.
You can set your cookie value containing expiry and get your expiry from cookie value.
// set
$expiry = time()+3600;
setcookie("mycookie", "mycookievalue|$expiry", $expiry);
// get
if (isset($_COOKIE["mycookie"])) {
list($value, $expiry) = explode("|", $_COOKIE["mycookie"]);
}
// Remember, some two-way encryption would be more secure in this case. See: https://github.com/qeremy/Cryptee
When you create a cookie via PHP die Default Value is 0, from the manual:
If set to 0, or omitted, the cookie
will expire at the end of the session
(when the browser closes)
Otherwise you can set the cookies lifetime in seconds as the third parameter:
http://www.php.net/manual/en/function.setcookie.php
But if you mean to get the remaining lifetime of an already existing cookie, i fear that, is not possible (at least not in a direct way).
It seems there's a list of all cookies sent to browser in array returned by php's headers_list() which among other data returns "Set-Cookie" elements as follows:
Set-Cookie: cooke_name=cookie_value; expires=expiration_time; Max-Age=age; path=path; domain=domain
This way you can also get deleted ones since their value is deleted:
Set-Cookie: cooke_name=deleted; expires=expiration_time; Max-Age=age; path=path; domain=domain
From there on it's easy to retrieve expiration time or age for particular cookie. Keep in mind though that this array is probably available only AFTER actual call to setcookie() has been made so it's valid for script that has already finished it's job. I haven't tested this in some other way(s) since this worked just fine for me.
This is rather old topic and I'm not sure if this is valid for all php builds but I thought it might be helpfull.
For more info see:
https://www.php.net/manual/en/function.headers-list.php
https://www.php.net/manual/en/function.headers-sent.php
To get cookies expire time, use this simple method.
<?php
//#############PART 1#############
//expiration time (a*b*c*d) <- change D corresponding to number of days for cookie expiration
$time = time()+(60*60*24*365);
$timeMemo = (string)$time;
//sets cookie with expiration time defined above
setcookie("testCookie", "" . $timeMemo . "", $time);
//#############PART 2#############
//this function will convert seconds to days.
function secToDays($sec){
return ($sec / 60 / 60 / 24);
}
//checks if cookie is set and prints out expiration time in days
if(isset($_COOKIE['testCookie'])){
echo "Cookie is set<br />";
if(round(secToDays((intval($_COOKIE['testCookie']) - time())),1) < 1){
echo "Cookie will expire today.";
}else{
echo "Cookie will expire in " . round(secToDays((intval($_COOKIE['testCookie']) - time())),1) . " day(s)";
}
}else{
echo "not set...";
}
?>
You need to keep Part 1 and Part 2 in different files, otherwise you will get the same expire date everytime.

Categories