Set PHP cookie name with custom ids "attached" to it - php

I'm trying to set a cookie for each profile which was seen by someone so that the custom welcome popup is not showing up everytime on return.
Now this happens with a specific profile and there the custom welcome popup is not showing, but if I'm going to another profile the custom welcome popup will not be showed too, which is something I don't want to happen.
That is why I need to set custom cookies in the users browser like : seen(here goes the id of the seller of smth else).
Doing this using PHP is not working:
When the user is closing the popup , I send an AJAX request with an ID payload to a specific file which sets the seen cookie. My AJAX request works all fine, but the cookie does not accept a specific id near its name. Should I work with the value of the cookie instead?
This is how my set cookie file looks like:
<?php
session_start();
$id = $_POST['id'];
setcookie("seen$id",true, time() + (86400 * 30), "/");
//seen$id is the custom cookie name
?>
Is it possible to set these type of cookies?
Chrome is showing up the name of the cookie (seen) without the ID near it.

This is not wise.
Unless you know that the set is bounded, then you have an undefined number of cookies, and hence an undefined amount of data which needs to be sent back to the server with each HTTP request. In practice, most browsers and web servers will limit either or both of the number of cookies and size of the data. While there is a case for using browser-sode data storage to address issues of scalability, that clearly does not apply here given that you are also using server-side sessions.
Going back to the problem you describe - your description is vague. It would have been helpful if you had shown us the actual Set-Cookie headers returned by the server.
The logic of your code is bad. While you might expect this URL to only ever see POST requests, and specifically POST requests with 'id' set, it is good practice to write robust code that does not rely on side effects elsewhere. While it is ALSO good practice to only provide the minimum code necessary to reproduce the issue when posting on StackOverflow, in this case the the effects you are reporting will only arise if the URL is invoked without 'id' or with a verb other than POST.
Consider:
<?php
session_start();
if (isset($_POST['id'])) {
$id = $_POST['id'];
setcookie("seen$id",true, time() + (86400 * 30), "/");
}

Related

Check if cookies are enabled without setting GET parameter or sessions in PHP

Much like the question asked in Detect if cookies are enabled in PHP and Check if cookies are enabled I'd like to know if cookies are enabled.
I am, however, trying to make this as transparent as possible for the user and as such I'm not interested in having some "cookietest=1" parameter appended to my URL.
I know I can just redirect back to the page the user originally entered, unset "cookietest=1" GET parameter and just tell the original page if cookies are disabled or not through sessions, but...
I'm currently using CodeIgniter and don't want to mess up CodeIgniter sessions, hence not using PHP sessions to store the cookie enabled/disabled state.
I'm actually not sure if using PHP sessions will mess up CodeIgniter sessions, but even if it doesn't I'm still interested in knowing if there is some ingenious solution out there, that can do the cookie check without setting a GET parameter or using sessions (redirect are fine, however)?
Update
Seems I need to clarify a little bit:
I want to know if cookies are enabled client side. I've already tried the method described in the questions I linked to, i.e.:
Set cookie.
Redirect to either a check cookie PHP page or the same page with a "cookietest=1" GET parameter.
See if the cookie is still set: If yes => Hooray, cookies are working!, otherwise => Boo, cookies are disabled.
The thing I'm asking is whether or not it's possible to do this without setting the GET parameter (because this becomes visible in the URL). The answer to that question is "Yes, if you use PHP sessions".
My next question is then: Is it possible to do without setting the GET parameter AND without using PHP sessions?
Basics: You can't know if a user has or not enabled cookies until you send one cookie to the client and you recive the same from him.
So the flow:
Client Request
Server Response (+ cookie)
Client Request (+ cookie)
can't be avoided from any way
You can track if cookies are enable using some test request (ajax, image, etc)
For example you can use a simple 1px image or any logo image served from your php script and you can track if cookies are enabled or not.
So the flow is now:
Client Request
Server Response HTML (+ cookie)
Client Request remote page resources (js, img, css) (+ cookie)
Server Response with page resource requested
Something like
<?php
// domain.com/some.js
if (isset($_COOKIE['test']))
$_SESSION['cookies_enabled'] = true;
echo <<JS
<someJS code or nothing>
JS;
?>
I looked into this a LOT a while ago and it seemed every way had its flaws. One thing I took into account as well was how the cookie check would work if the user were to update the page or go back to the page via the back button.
Apparently, for the server to see whether the client accepts cookies or not the client has to send an additional HTTP request after the server has attempted to set a cookie, in which the server looks for a cookie header indicating that the client accepts cookies (no header = cookies not accepted). This additional request can be a redirect to another page (see the usual method with a $_GET parameter acting as a flag saying if an attempt to set the cookie has taken place or not) but the important thing is really that it's just another HTTP request. What I ended up doing was wrapping my entire page in a HTML FRAMESET:
<?php
setcookie('test', 1, time() + 3600);
echo '<HTML>
<HEAD>
<TITLE>
</TITLE>
</HEAD>
<frameset rows="100%" cols="100%">
<frame src="next.php">
</frameset>
</HTML>';
?>
...then in the additional HTTP request for next.php I know that there will be a cookie header included in the request if the client has accepted cookies and therefore I don't have to use a $_GET parameter as a flag indicating this. Next.php thus looks like:
<?php
if(count($_COOKIE) > 0){
//Set some variable that indicates to the rest of the script that cookies
//are enabled.
}
else {
//Set some variable indicating that cookies are disabled
}
//Output the rest of the script and HTML code to be displayed
?>
I thought about doing the same thing but sending the additional HTTP request from an IMG tag instead of a FRAMESET but I ran into trouble as to how I would indicate to the parent script via an image whether cookies were set or not and therefore I ended up doing it this way. The ONLY flaw I see in this method is that if the user right-clicks inside the frame and choose to update only the frame (not the entire page) then the frame will falsely claim that cookies are disabled but compared to the downsides of all the other ways, I thought that was acceptable.
EDIT: I should also add that I made a point out of doing this without Javascript as well.
I would use php.ini settings to find such things out.
Maybe like this:
if (ini_get("session.use_cookies") == 1) {
print "cookies enabled";
}
While you could just check if php has cookies enabled a very simple test would be to just set a cookie and then try to read it.
If you successful read it, it worked.
This would also inform you if the client disallows cookies.

How to determine from which url a PHP header was called

I've got a page under http://www.example.com/abc/def/a/ where a user can buy products.
For a marketing activity (printed paper) the customer should type in a shorter url
http://www.example.com/order/
When this url is called, the server executes this script:
<?php
header("Location: http://www.example.de/abc/def/a/");
exit;
?>
The page under http://www.example.com/abc/def/a/ contains some
informations (rebate-code etc.) which should only be visible to users
coming from http://www.example.com/order/
$_SERVER['HTTP_REFERER'] seems to be not reliable from what I've read.
I checked with phpinfo(); if there is any info variable which contains "order" but I haven't found one.
Is it possible or do you recommend an alternative approach?
HTTP is in it's pure form a stateless-protocol, so you won't find anything in the protocol itself that will help you with your current problem.
Using $_SESSION to store data in-between requests is the easiest route to walk, and what I recommend.
As said; since the protocol used to transfer information is stateless you have no choice but to create a method for your web-application to recognize which request is done by which user.. this is a perfect problem solved by php-sessions.
php.net - PHP: Sessions - Manual
As you have discovered, the HTTP Referer, along with all of the other headers, can easily be faked. The only reliable way I see of accomplishing this is logging users as they visit the orders page and when they visit the /abc/def/a/ page, verify that the log entry exists. This kind of log could be stored in $_SESSION, however be sure that when using multiple servers you have the proper setup to ensure all servers share the same session information (you can use a redis server to store session data).
On the order page:
session_start();
$_SESSION['order_visited'] = true;
On the rebate code page:
session_start();
if(!isset($_SESSION['order_visited']) || !$_SESSION['order_visited']) {
header('Location: /order'); // Must visit order first
die();
}

How to protect against cross domain http requests? (server side)

I've read some questions on SO about denying cross domain requests but all just state to rely on the client side protection ( same origin policy ) . Are there any layers of protection that can be done server side ? Should i rely on header- origin , header - referer ? Some say header referer get's modified by some anti-spyware programs . Some say ff doesint include origin header option (but it does) , some say chrome doesnt and so on :) .
I know headers can be modified (referer can be modified even with setrequestheader method) , but , if you ever done any protection server side for this matter please share any ideeas .
P.S. : A possibility would be to tokenise each request (all type of requests , requests that only get data , requests that change data on server etc ) but that would be a pain in the ass ...
P.P.S. : omg don't spam about synchroniser token pattern ... as i said in the firs P.S. yea that would be a solution , any other ideeas?
Mayor question is against which kind of attacks you want protect?
If you want protect against CSRF, then you need process form with random security token.
Like
<input type="hidden" name="token" value="random value generated on server side for each request" />
After form will submitted you need compare token from request and token stored in session on server side.
If you want deny load some kind of resources from other domains (like loading images or scripts on evil.com from you server), then you can add to each resource similar token.
Like
<img src="/images/mysuperimg.png?token=<token>" />
etc.
I suppose you have heard of CSRF?
here's an overview CSRF works and how it's prevented:
anyone can request a page from your site, the same way anyone can also POST on your site. let's say you have a registration form. one can copy your form, and put in any HTML page, remove the JS validations, and spam you infinitely. sounds like a threat right?
however, you can prevent this by using a session id. this is a unique string (usually MD5 or SHA-1), that is stored on a session variable in PHP before rendering the page. this session id is also rendered in a hidden input form on your form. now when the form is submitted, PHP checks if that session id sent with the form is a match with a the session id stored in the session variable. if it's valid, you proceed, and the one stored in the server is nullified so that it wont be reused.
also, if a certain time has elapsed, that session id should expire. so lets say if a user has lingered on a form for more than your 15 min expiry. using that form will be invalid. you'd have to refresh the page to get a new session id
now you might ask how to use this on page requests rather than forms?
i know of 2 ways to send over session ids to the server, and that is either by cookie or via appending your sessionid in the url.
for cookie, it works the same way. if your page is generated by your server, the page creates the session id on your server and sends a copy as a cookie. the next page request, you read the cookie of the request, get it's session id, compare with the one on the server, and if equal, request is valid, you proceed. otherwise, it's invalid.
for those who have disabled cookies, you can append the sessionid in the url of every link you have on the page. notice that on some sites, they have a url parameter of sid, or sessid and so on? that's how they pass it. every link in your page will be appended this id. and upon clicking the link, all the server does is get that session id from the url, and compare it with the server.
quite long answer :D

Jquery $.post and PHP - Prevent the ability to use script outside of main website

I have a PHP script setup using Jquery $.post which would return a response or do an action within the targeted .php file within $.post.
Eg. My page has a form where you type in your Name. Once you hit the submit form button, $.post is called and sends the entered Name field value into "mywebsite.xyz/folder/ajaxscript.php"
If a user was to visit "mywebsite.xyz/folder/ajaxscript.php" directly and somehow POST the data to the script, the script would return a response / do an action, based on the submitted POST data.
The problem is, I don't want others to be able to periodically "call" an action or request a response from my website without using the website directly. Theoretically, right now you could determine what Name values my website allows without even visiting it, or you could call an action without going through the website, by simply visiting "mywebsite.xyz/folder/ajaxscript.php"
So, what measures can I take to prevent this from happening? So far my idea is to ensure that it is a $_POST and not a $_GET - so they cannot manually enter it into the browser, but they could still post data to the script...
Another measure is to apply a session key that expires, and is only valid for X amount of visits until they revisit the website. ~ Or, just have a daily "code" that changes and they'd need to grab this code from the website each day to keep their direct access to the script working (eg. I pass the daily "code" into each post request. I then check that code matches in the ajax php script.)
However, even with these meaures, they will STILL have access to the scripts so long as they know how to POST the data, and also get the new code each day. Also, having a daily code requirement will cause issues when visiting the site at midnight (12:00am) as the code will change and the script will break for someone who is on the website trying to call the script, with the invalid code being passed still.
I have attempted using .htaccess however using:
order allow,deny
deny from all
Prevents legitimate access, and I'd have to add an exception so the website's IP is allowed to access it.. which is a hassle to update I think. Although, if it's the only legitimate solution I guess I'll have to.
If I need to be more clear please let me know.
The problem you describe is similar to Cross-Site Request Forgery (CSRF or XSRF). To protect you against this you could put a cookie into the browser and have the cookie value sent in the post form too (by hidden field or just add it to $.post). On server side check both those fields, if they match the request probably came from your site.
However the problem you describe will be quite hard to protect against. Since you could easily make a script (or use Crul) to forge all kinds of requests and send to your server. I don't know how to "only allow a browser and nothing else".
Use the Session variable as you say plus...
As MyGGAN said use a value set in a cookie (CVAL1) before rendering the submit forms. If this cookie is available (JS Code Check will verify) then submit.
On the server side:
If this cookie value exists and the session variable exist then the HTTP Request came from your website.
Note: If the script (form) is to presented under another domain DO NOT allow the cookie value (CVAL1) to be set.
Do not allow HTTP Requests on the Server Side Scripts if extra Http Headers Are not available (like x-requested-with: jquery). JQuery sends a request with an X-* header to the server.
Read more on Croos-Site Request Forgery as MyGGAN suggests.
I am not really sure REMOTE_ADDR would work. Isnt that supposed to be the end users IP addr?
Firstly, you could make use of
$_SERVER['HTTP_REFERER'], though not always trust-able.
The only bet that a valid post came from your page would be use a captcha.
try to use HTTP_SEC
// SECURITER
if ($_SERVER[HTTP_SEC_FETCH_SITE] != "same-origin")
die();
if ($_SERVER[HTTP_SEC_FETCH_MODE] != "cors")
die();
if ($_SERVER[HTTP_SEC_FETCH_DEST] != "empty")
die();

How to know where a form came from?

I was wondering is there a way in PHP that you could tell where a form was submitted without using hidden fields or anything of the like where the user would only need to tamper with the html a little?
For example i am trying to work out if a form that was submitted was actually on my website or whether the form was saved offline and submitted that way.
An hidden field is not easily spoofed if it contains a UID (if you encrypt a time stamp you will be able to tell how long the user has been on the page)
Of course the user can enter whatever he wants in the field, but unless he can generate a valid UID, he can't make your php script believe it came from somewhere else.
You can also track a user's visited pages through $_SESSION and use that instead of the HTTP referrer (store each visited page in an array inside $_SESSION, and when your script is called, you simply check whether the last page was yours? Variation of that are possible depending on what you need).
You can attempt to use the referral header set in HTTP requests, do note however that not all browsers set these correctly, or users have them turned off, or that they are very easily spoofed.
Without a hidden field containing an unique identifier that is used to identify the form for that one single submission there is no good way of identifying whether the form is being forged or not.
I could be wrong but wouldn't the referrer header tell you this?
This gets you what you are after:
$referer = ($SERVER["HTTP REFERER"] == null);
This actually fetches it from the HTTP Header where it looks like this:
...
Referer: http://foobar.com/page.php
...
It is easy for anyone to spoof this but for most purposes it is reasonable.
Trivia: Referer should actually be spelt referrer which is the correct spelling but the spelling mistake made its way into the HTTP specification and has stuck since.
You can't really tell. Why would it matter? If you're trying to detect if someone has forged a request, you can't.
Amended: The green solution above does help some issues, but it doesn't address the question of if it came from your site, or if it was modified.

Categories