Adding a logger in production - php

I am making some changes on the live site and i constantly need to add loggers (print_r) throughout the page for me to test. The problem is the site is healily populated by staff and I need it so I am for sure the only one to see this logger. I heard I can wrap the logger in an if with my Ip address but i thought I while back i tried that and the client still viewed it. Anybody have an ideas or the syntax needed to make this happen. By the way I think the PHP version is an older on

You could always pass yourself a variable in get and switch on that
http://mysite.com?debug=secret
then:
if($_GET['debug'] === "secret"){
print_r($stuff);
}
Before I used frameworks I used to set a cookie when debug="secret" so that I do not have to put it all the time. And since only you have the cookie set you are ok.

This restricts //your debug code to IP 12.34.56.78.
if(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] == '12.34.56.78'){
//your debug code
}
You could also store this in a constant:
define('SHOWDEBUG', isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] == '12.34.56.78');
Somewhere else: SHOWDEBUG && print_r($dumped);

Make a page that lets you set or clear a "debug" cookie. Make sure you put a password on that page so the client can't mess with it.

agreed with lznogood.
i would add some secret
<?php
$a=$_GET[];
if($a=xyz){
}
?>
note: it wouldn't hurt to make the get some encrypted value equal to some other large encrypted value. then just bookmark this for yourself and set it in the code.
i have this active on my page for layout//connection reasons.

Related

Blocking GET requests in Apache/PHP

So I have a PHP script that I myself have not designed but has a known security flaw. There's an admin panel where the admin can change various profile settings for every user, including their email address. The security flaw is such that anyone who knows the correct URL can change the email address of any registered user, including the admin, so long as they know the corresponding user's ID, by simply calculating the MD5 hash of the new email address they want to change to and issuing a GET request, without ever having to login as an admin. For example, entering the following URL into your browser:
admin.php?userid=1&md5hash=c59152a77c0bc073fe6f2a3141b99010&email=blah#blah.com
Would successfully update the email address of user with ID of "1" to blah#blah.com.
Now from what research I've done so far it appears that ditching MD5 hashes for a slight more proprietary/secure form of encryption would be the best/most secure way of going about this. But while I feel I have a fairly good understanding of PHP and have written a few basic scripts myself, since I haven't designed the particular script in question I'm not sure if this would actually be possible and/or plausible. Also, people do still use MD5 hashes in practice so there must exist another equally feasible way to protect aganist such exploits which led me to looking in to Apache's mod_rewrite module to block specific types of GET requests:
[redacted for irrelevance because of max link limit of 2 for new users]
So my questions would be:
1) Disregarding whether or not it would actually be feasible, would changing the PHP script to using some other form of encryption besides MD5 hashes be the BEST possible way to go about this? Or is there some simple function that I can add to the PHP script itself to protect from this kind of exploit?
2) If I went the route of using Apache's mod_rewrite as describe in the above URL, what would be the best method (out of THE_REQUEST, HTTP_REFERER, HTTP_COOKIE, REQUEST_URI, HTTP_USER_AGENT, QUERY_STRING, and/or REMOTE_ADDR, where REQUEST_METHOD is "GET")? Or is it even possible to do what I'm trying to do this way?
3) Someone had also suggested it may be possible to do what I am trying to do via a .htaccess file? Is this possible and would this method be anymore more or less secure than the other 2 mentioned?
The only thing to take into consideration is that via whichever method I end up using, obviously the server would have to still be able to issue the request for when the admin wants to legitimately change a user's email address. I just need to update it so that the general public cannot change a user's email address by simply typing the correct URL into their browser, given they know the correct user ID. Thanks in advance.
---> EDIT: Sorry I was neglecting to name the particular script because it is a publicly available one and I wasn't sure if this particular exploit was a known one but turns out it is, so I guess there's no harm in posting it here. The script is TorrentTrade (v2.08)- you can download the entire script at SourceForge (https://sourceforge.net/projects/torrenttrader/).
I've also copied and pasted the entirety of account-ce.php:
<?php
//
// TorrentTrader v2.x
// $LastChangedDate: 2012-09-28 20:35:06 +0100 (Fri, 28 Sep 2012) $
// $LastChangedBy: torrenttrader $
//
// http://www.torrenttrader.org
//
require_once("backend/functions.php");
dbconn();
$id = (int) $_GET["id"];
$md5 = $_GET["secret"];
$email = $_GET["email"];
if (!$id || !$md5 || !$email)
show_error_msg(T_("ERROR"), T_("MISSING_FORM_DATA"), 1);
$res = SQL_Query_exec("SELECT `editsecret` FROM `users` WHERE `enabled` = 'yes' AND `status` = 'confirmed' AND `editsecret` != '' AND `id` = '$id'");
$row = mysql_fetch_assoc($res);
if (!$row)
show_error_msg(T_("ERROR"), T_("NOTHING_FOUND"), 1);
$sec = $row["editsecret"];
if ($md5 != md5($sec . $email . $sec))
show_error_msg(T_("ERROR"), T_("NOTHING_FOUND"), 1);
SQL_Query_exec("UPDATE `users` SET `editsecret` = '', `email` = ".sqlesc($email)." WHERE `id` = '$id' AND `editsecret` = " . sqlesc($row["editsecret"]));
header("Refresh: 0; url=account.php");
header("Location: account.php");
?>
account-ce.php is the .php file referenced in following list of several known exploits (the first exploit is the only one i'm looking at right now):
https://www.exploit-db.com/exploits/21396/
I figured rather than sit around and wait for TorrentTrader to release a new update I would try and be proactive and fix some of the exploits myself.
You need to include in a session handler. I would like to assume that a user is required to login before being allowed to access any admin page, and that some sort of login credential or user id is saved to a session variable. To implement that you would need to have a script like this included on every page:
<?php
session_start();
if(!isset($_SESSION['uid'])){
$redirect_url='login.php';
if(isset($_SERVER['HTTP_REFERER'])){
$redirect_url.='?target='.urlencode($_SERVER['HTTP_REFERER']);
}
header('Location: '.$redirect_url);
}
?>
$_SESSION['uid'] is somewhat arbitrary and could be any session variable you deem sufficient for the security of your application. Note: session variables are connected to the user and are saved from page to page until the session is destroyed by calling session_destroy().
If the above script is executed prior to every page load, then when some evil hacker tries to trigger the script without being logged in, they will be redirected to login.php before the rest of the script/page is executed/loaded.
The current script is very insecure, but the insecurity does not arise from the use of the md5 hash. It would be really difficult to bolt security on top a system like this using just Apache configuration.
You might want to start by reading up on session security and cross site request forgery.
You need to write some code. And since you've not posted any code nor proposed a specific solution, your question is rather off topic here.
Alright guys I feel moderately stupid now, but thank you for the tips on using the session handler as that is what ultimately pointed me in the correct direction and to look in the right place. After digging around it seems as though that particular admin file (account-ce.php), for whatever reason, was just missing this:
loggedinonly();
which is defined in backend/functions.php as:
function loggedinonly() {
global $CURUSER;
if (!$CURUSER) {
header("Refresh: 0; url=account-login.php?returnto=" . urlencode($_SERVER["REQUEST_URI"]));
exit();
}
}
Also, I plan to read up on session security as you suggested so I can better familiarize myself with how sessions are used for this purpose. Thanks again! :)

PHP - $_GET being cached by server

got high hopes seeing how well my first question was answered so I will try to word this as best I can but if you need anymore info just shout.
I have a site that I have built that works fine on all the different test servers we use, but is now on a client's server and a small bug has arisen that after searching around I understand why it is doing it, but not sure of the best way to fix it.
Basically on one of the page I have a php if statement to determine if the querystring is present, this code is below
<?php if (isset($_GET['area'])) { ?>
<script type="text/javascript">
$(function() {
setTimeout(function() {
$('#<?php echo $_GET['area']; ?>-popup').click();
}, 500);
});
</script>
<?php } ?>
All works great on my servers, however on the client's this isset($_GET['area']) always return true. What it is doing is that when you go onto the page using the link that adds the ?area=test, the server is storing this value, and whenever I go back onto this page it thinks that the GET is true and then performs the popup, even though there is no querystring.
Very annoying, I was thinking of clearing the session perhaps but it seems overkill, is there an unset $_GET function that I could perform prior to checking if the query string exists.
Hopefully that made sense I've never had to do something like this before, it seems mad that a server would store $_GETS.
Thanks in advance.
This is impossible. There's no $_GET['parameter'] if 'parameter' is not in the url. If the isset() returns true, it is present in the url.
Either the browser caches the url WITH get parameter or you 'spoof' the parameter somewhere else.
There is no cache for $_GET as long as I know.
Moreover, usually you'll set a random GET value to avoid server cache like ?seed=123131153131
Are you sure about the request you send to Php when displaying the page ?
$_GET does not get cached.
However, I can imagine you do a check somewhere with a single =.
Something like;
if ($_GET['area'] = 'test')
This will set it, and make it true. Thus you will always have it (and this if() will also be true in that case

Distinguish between two sessions in PHP

I tried coding in the following way for one of the website over a localhost. say localhost/abc:
<?php
session_start();
$_SESSION['name']=$row['name']
?>
The output was good. but when the same code was used for another webpage over the same localhost say localhost/xyz. Then there was ambiguity between names. As if I need to distinguish between the sessions for xyz and abc.
So I tried this:
<?php
session_id(226);
session_name(veer);
session_start();
.
.
.//connection with database and all
.
$_SESSION['name']=$row['name'];
echo($_SESSION['name']);
?>
When another machine logged in over the same server then the session I created was accessible by that machine for same webpage.
Is there any solution. Or how to distinguish between two sessions.?
To put it in simple terms... you are accessing same memory area of server when you access two different sites on same web server using the same browser instance. Thus
http://localhost/xyz and http://localhost/abc are referring to the same site localhost and thus you will not start another session by session_start() but instead resume it. You can alternatively create virtual hosts as Jon said but for the sake of testing which I guess you are, just use different browsers.
Also, you cannot share session over different machines normally, so I think that's your logical mistake. Alternatively try
session_start();
echo (session_id());
on the top of the page and see if you are starting or resuming the same session which I think you are not. I think your page is storing same data in different sessions which you are mistaken as same session.
Use session_regenerate_id(); method in the second file(xyz).
this?
<?php
session_start();
if (!isset($_SESSION['xyz'])) { $_SESSION['xyz'] = array(); }
$_SESSION['xyz']['name'] = $row['name'];
?>
sometimes instead of doing the above i just prefix my session keys
example: $_SESSION['xyz_name'];
I did that after i realized that my CPanel has been used some sessions of its own
that caused a conflict to mine.
Requests from the same user agent to the same web server will share the same session, barring explicit configuration that depends on your exact server setup.
Normally this problem is avoided because the "other webpage" would actually be on another domain entirely, so the session cookie (and by extension the session data) would not be shared. This is also what you should do if you want to run separate applications independently on localhost: set up separate virtual hosts on separate internal domains.
You could also solve the problem purely in code by not using $_SESSION directly to store your data but a subkey based on some differentiating factor such as $_SESSION['SCRIPT_NAME']. A very simple example:
$sessionKey = "default";
if (strpos($_SESSION['SCRIPT_NAME'], "dir1/")) {
$sessionKey = "dir1";
}
else if (strpos($_SESSION['SCRIPT_NAME'], "dir2/")) {
$sessionKey = "dir2";
}
$_SESSION[$sessionKey]['mydata'] = 'foo';
However this last one is a really inelegant solution which I would not recommend.

Variables in URL won't work when not testing locally

I've been working on a project on my local server. The time has come to upload it so I did just that. I started to test it out online and my navigation isn't working.
The navigation works by doing this:
Add
The page then checks whether $p exists and if it does, it shows the relevant content. For some reason though my content isn't showing up when I click the links. I turned on error reporting, and I added this (line 39)
echo $p;
to the document. Now I get this error: Notice: Undefined variable: p in /home/silver/public_html/admin/index.php on line 39 but only when testing online and it works fine when I test it locally.
I can post my code if I need to, but there's a lot of it and I'm not sure which bit is the problem.
UPDATE:
Thanks for all the replies, but I'm confused as to how you use your suggestions as I'm used to doing things the way I was.
At the moment, I do this to check what the $p variable is
<?php if(!isset($p)) { // DEFAULT PAGE VIEWED AT INDEX.PHP ?>
And use this to link to the page:
Add New Item
You're relying upon register_globals, an outdated and deprecated feature of PHP. This feature automatically translates GET, POST, COOKIE, SERVER etc. variables and inserts them into the global scope. This means that file.php?p=blah would result in $p == 'blah'. This is a bad idea for lots of different scoping and security reasons outlined in the PHP manual.
Use the superglobals (e.g. $_GET, $_POST, $_SERVER) instead.
In response to your updated question, your code
<?php if(!isset($p)) { // DEFAULT PAGE VIEWED AT INDEX.PHP ?>
should become
<?php if(!isset($_GET['p'])) { // DEFAULT PAGE VIEWED AT INDEX.PHP ?>
You're relying on an old and very bad "feature" of PHP called register_globals that loads variables directly from GET. You need to do $p = $_GET['p'] if you want $p to be set via an HTTP GET.
Probably because 'register_globals' is ON on your dev system and OFF on your live system. Set it to OFF on your dev and use $_GET['p']
$p doesn't automatically get set from the parameter in the URL. You need to attach $p to the value coming from the URL by using the code $p = $_GET['p']; first.
Be weary though, you need to sanitize this GET parameter and/or create a whitelist to make sure it is a valid parameter.

PHP Session data not being saved

I have one of those "I swear I didn't touch the server" situations. I honestly didn't touch any of the php scripts. The problem I am having is that php data is not being saved across different pages or page refreshes. I know a new session is being created correctly because I can set a session variable (e.g. $_SESSION['foo'] = "foo" and print it back out on the same page just fine. But when I try to use that same variable on another page it is not set! Is there any php functions or information I can use on my hosts server to see what is going on?
Here is an example script that does not work on my hosts' server as of right now:
<?php
session_start();
if(isset($_SESSION['views']))
$_SESSION['views'] = $_SESSION['views']+ 1;
else
$_SESSION['views'] = 1;
echo "views = ". $_SESSION['views'];
echo '<p>Refresh</p>';
?>
The 'views' variable never gets incremented after doing a page refresh. I'm thinking this is a problem on their side, but I wanted to make sure I'm not a complete idiot first.
Here is the phpinfo() for my hosts' server (PHP Version 4.4.7):
Thanks for all the helpful info. It turns out that my host changed servers and started using a different session save path other than /var/php_sessions which didn't exist anymore. A solution would have been to declare ini_set(' session.save_path','SOME WRITABLE PATH'); in all my script files but that would have been a pain. I talked with the host and they explicitly set the session path to a real path that did exist. Hope this helps anyone having session path troubles.
Check to make sure you are not mixing https:// with http://. Session variables do not flow between secure and insecure sessions.
Had same problem - what happened to me is our server admin changed the session.cookie_secure boolean to On, which means that cookies will only be sent over a secure connection. Since the cookie was not being found, php was creating a new session every time, thus session variables were not being seen.
Use phpinfo() and check the session.* settings.
Maybe the information is stored in cookies and your browser does not accept cookies, something like that.
Check that first and come back with the results.
You can also do a print_r($_SESSION); to have a dump of this variable and see the content....
Regarding your phpinfo(), is the session.save_path a valid one? Does your web server have write access to this directory?
Hope this helps.
I had following problem
index.php
<?
session_start();
$_SESSION['a'] = 123;
header('location:index2.php');
?>
index2.php
<?
session_start();
echo $_SESSION['a'];
?>
The variable $_SESSION['a'] was not set correctly. Then I have changed the index.php acordingly
<?
session_start();
$_SESSION['a'] = 123;
session_write_close();
header('location:index2.php');
?>
I dont know what this internally means, I just explain it to myself that the session variable change was not quick enough :)
Check to see if the session save path is writable by the web server.
Make sure you have cookies turned on.. (I forget when I turn them off to test something)
Use firefox with the firebug extension to see if the cookie is being set and transmitted back.
And on a unrelated note, start looking at php5, because php 4.4.9 is the last of the php4 series.
Check who the group and owner are of the folder where the script runs. If the group id or user id are wrong, for example, set to root, it will cause sessions to not be saved properly.
Check the value of "views" when before you increment it. If, for some bizarre reason, it's getting set to a string, then when you add 1 to it, it'll always return 1.
if (isset($_SESSION['views'])) {
if (!is_numeric($_SESSION['views'])) {
echo "CRAP!";
}
++$_SESSION['views'];
} else {
$_SESSION['views'] = 1;
}
Well, we can eliminate code error because I tested the code on my own server (PHP 5).
Here's what to check for:
Are you calling session_unset() or session_destroy() anywhere? These functions will delete the session data immediately. If I put these at the end of my script, it begins behaving exactly like you describe.
Does it act the same in all browsers? If it works on one browser and not another, you may have a configuration problem on the nonfunctioning browser (i.e. you turned off cookies and forgot to turn them on, or are blocking cookies by mistake).
Is the session folder writable? You can't test this with is_writable(), so you'll need to go to the folder (from phpinfo() it looks like /var/php_sessions) and make sure sessions are actually getting created.
If you set a session in php5, then try to read it on a php4 page, it might not look in the correct place! Make the pages the same php version or set the session_path.
I spent ages looking for the answer for a similar problem. It wasn't an issue with the code or the setup, as a very similar code worked perfectly in another .php on the same server. Turned out the problem was caused by a very large amount of data being saved into the session in this page. In one place we had a line like this:$_SESSION['full_list'] = $full_list where $full_list was an array of data loaded from the database; each row was an array of about 150 elements. When the code was initially written a couple of years ago, the DB only contained about 1000 rows, so the $full_list contained about 100 elements, each being an array of about 20 elements. With time, the 20 elements turned into 150 and 1000 rows turned into 17000, so the code was storing close to 64 meg of data into the session. Apparently, with this amount of data being stored, it refused to store anything else. Once we changed the code to deal with data locally without saving it into the session, everything worked perfectly.
I know one solution I found (OSX with Apache 1 and just switched to PHP5) when I had a similar problem was that unsetting 1 specific key (ie unset($_SESSION['key']);) was causing it not to save. As soon as I didn't unset that key any more it saved. I have never seen this again, except on that server on another site, but then it was a different variable. Neither were anything special.
Thanks for this one Darryl. This helped me out. I was deleting a session variable, and for some reason it was keeping the session from committing. now i'm just setting it to null instead (which is fine for my app), and it works.
I know one solution I found (OSX with Apache 1 and just switched to PHP5) when I had a similar problem was that unsetting 1 specific key (ie unset($_SESSION['key']);) was causing it not to save. As soon as I didn't unset that key any more it saved. I have never seen this again, except on that server on another site, but then it was a different variable. Neither were anything special.
Here is one common problem I haven't seen addressed in the other comments: is your host running a cache of some sort? If they are automatically caching results in some fashion you would get this sort of behavior.
Just wanted to add a little note that this can also occur if you accidentally miss the session_start() statement on your pages.
Check if you are using session_write_close(); anywhere, I was using this right after another session and then trying to write to the session again and it wasn't working.. so just comment that sh*t out
I had session cookie path set to "//" instead of "/". Firebug is awesome.
Hope it helps somebody.
I had this problem when using secure pages where I was coming from www.domain.com/auth.php that redirected to domain.com/destpage.php. I removed the www from the auth.php link and it worked. This threw me because everything worked otherwise; the session was not set when I arrived at the destination though.
A common issue often overlooked is also that there must be NO other code or extra spacing before the session_start() command.
I've had this issue before where I had a blank line before session_start() which caused it not to work properly.
Adding my solution:
Check if you access the correct domain. I was using www.mysite.com to start the session, and tried to receive it from mysite.com (without the www).
I have solved this by adding a htaccess rewrite of all domains to www to be on the safe side/site.
Also check if you use http or https.
Edit your php.ini.
I think the value of session.gc_probability is 1, so set it to 0.
session.gc_probability=0
Another few things I had to do (I had same problem: no sesson retention after PHP upgrade to 5.4). You many not need these, depending on what your server's php.ini contains (check phpinfio());
session.use_trans_sid=0 ; Do not add session id to URI (osc does this)
session.use_cookies=0; ; ensure cookies are not used
session.use_only_cookies=0 ; ensure sessions are OK to use IMPORTANT
session.save_path=~/tmp/osc; ; Set to same as admin setting
session.auto_start = off; Tell PHP not to start sessions, osc code will do this
Basically, your php.ini should be set to no cookies, and session parameters must be consistent with what osc wants.
You may also need to change a few session code snippets in application_top.php - creating objects where none exist in the tep_session_is_registered(...) calls (e eg. navigation object), set $HTTP_ variables to the newer $_SERVER ones and a few other isset tests for empty objects (google for info). I ended up being able to use the original sessions.php files (includes/classes and includes/functions) with a slightly modified application_top.php to get things going again. The php.ini settings were the main problem, but this of course depends on what your server company has installed as the defaults.

Categories