We have 2 web servers, one secure and one normal.
Is it possible to set a cookie like this
setcookie("basket[id]", $newID, time()+60*60*24, "/", SITE_URL, 0, true);
setcookie("basket[id]", $newID, time()+60*60*24, "/", SECURE_SITE_URL, 1, false);
Where
SITE_URL = www.sitename.com
SECURE_SITE_URL = xxxxx.securesitename.com
Kyle
Set Cookie
With setcookie you can set the domain parameter to indicate where the cookie is available. To make the cookie available on all subdomains of example.com then you'd set it to '.example.com'. The . is not required but makes it compatible with more browsers.
As long as your servers are referred to with different sub-domains, you can set your cookies accordingly.
Secure parameter
Secure, indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.
Setting a Cookie on a different domain
A server cannot set a cookie for a domain that it isn't a member of.
The server issuing the cookie must be a member of the domain that it tries to set in the cookie. That is, a server called www.myserver.com cannot set a cookie for the domain www.yourserver.com.
How Double Click do it
One exception to the rule is ad agency Double click. Who manage to add cookies to your PC without you visiting the specific web site by packaging cookies with image requests when they are loaded from their servers onto other peoples web sites.
You cannot set a cookie for a domain other than the current or a superset of it (like example.com is a superset of foo.example.com and bar.example.com). That means the second Set-Cookie will get rejected by the browser.
One solution is to use a subdomain of your main domain for your secure domain, like secure.example.com. Then a cookie set for .example.com would be available at www.example.com as well as at secure.example.com.
Related
If I start a session like below for a server and a localhost client try to request the server via HTTP, does it response with the session cookie?
or must it go through HTTPS?
I read the doc and it did say only through HTTPS, but I wonder if localhost is an exception.
session_start([
'cookie_secure' => true
]);
Yes, it does:
If you try this in a browser, you'll also see a warning saying that the cookie was rejected.
This makes sense because PHP has no control on the entire communication channel and it's possible that the end-user is connecting to a secure proxy that redirects internally to a non-encrypted HTTP server.
I have a local testing application mimicking the host test.mywebsite.com on port 4200.
It makes a call to api.test.mywebsite.com (also locally hosted) to /login
The request passes, the server returns 200 and some information, and along with it it sets this header which I see in the response headers:
Set-Cookie: refreshToken={JWT here}; expires=Sun, 23-May-2021 20:38:32 GMT; Max-Age=1296000; path=/; domain=.test.mywebsite.com; HttpOnly
This doesn't get stored in my browser (either Chrome or Firefox) and I'm trying to figure out why.
Here's some more information about my setup if needed:
Angular server using ng serve --host=test.mywebsite.com to get the test frontend up on http://test.mywebsite.com:4200
Kubernetes backend running on localhost (with my hosts file redirecting api.test.mywebsite.com to 127.0.0.1) which directs the request to a PHP pod that creates the cookie using this code:
setcookie(
"refreshToken", // name
$refreshJWT->token, // token
$refreshJWT->expiration, // expires in 15 days
'/', // path
".".$refreshJWT->domain, // domain
($refreshJWT->environmentType === "test") ? false : true, // security
true // httponly
);
I fear it's something painfully simple or an oversight somewhere, but can't for the life of me find out what. The only thing I can think of would be the port not matching with the cookie host, but as far as I know cookie domains are port-agnostic. I've tried adding :4200 to the end of the cookie domain anyway and still have the same problem.
Update: setcookie() returns true, so there's no output previous to setting the header.
Update2: I deployed it to a staging server and the problem still occurs despite no DNS trickery or proxies going on.
Update3: I've narrowed it down to a combination of my api server's Access-Control-Allow-Origin header, and my JS' use of withCredentials
My Access-Control-Allow-Origin is set to *. If I send the request withCredentials as false, it returns the body to the JS but refuses the cookie. If I set withCredentials to true, it sets the cookie but refuses to allow the JS to read the body.
I found out the reason, for anyone who may be stumbling on this:
The first problems was while my requests were going through and returning 200, the cookie was not being set because I didn't agree to receive a cookie on the frontend. To agree to cookies on the frontend, I had to use withCredentials.
The second problem was on the backend, I didn't explicitly send the header Access-Control-Allow-Credentials This would allow both front and backend to agree to a cookie exchange.
The third problem was my backend had a wildcard set for Access-Control-Allow-Origin, which my browser requires to match the current host exactly if withCredentials is used.
It makes a call to api.test.mywebsite.com
...
domain=.test.mywebsite.com
These need to be the same hostname
The same PHP script I'm using works fine with sessions on a domain website like example.com but not so when it's uploaded and accessed on a bare IP address website with an arbitrary HTTP port number like this:
111.222.333.444:5566
Variables can be set in $_SESSION which is accessible in the same PHP request but they are gone with the next page load.
Tried this:
session_set_cookie_params(
0,
'/',
'111.222.333.444:5566'
);
session_start();
But it's not working. Also checked phpinfo() and the bare IP site's session is enabled. My browser does support cookie when both of the tests are run.
This is weird. What could be wrong here? Is PHP session meant to not persist on bare IP site with exotic HTTP port?
One of the requirements for cookies is:
The string is a host name (i.e., not an IP address).
You can't associate a cookie with an IP address, only with a hostname.
PHP sessions depend on session cookies to work.
I am trying to set a cookie to view private content from AWS Cloudfront
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html
They give an example cookie header:
Set-Cookie: Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly; CloudFront-Key-Pair-Id=APKA9ONS7QCOWEXAMPLE
I created the following php code
setcookie (
'CloudFront-Key-Pair Id',
'MYID',
0,
'/',
'mycloudfrontsub.cloudfront.net',
true,
true
);
But the cookie is not set. The cookie is only set if I take out the domain name.
I think this is due to calling the setcookie in a script after session_start. I tried adding this, but it's required before session_start()
session_set_cookie_params(0, '/', 'duvoxso6rm38g.cloudfront.net);
Do I need to do something like this?
//close local session, then open new one for aws
$id=SID;
session_write_close();
session_set_cookie_params(0, '/', 'mysub.cloudfront.net');
session_start();
setcookie(...);
session_write_close();
session_set_cookie_params(0, '/', 'originaldomain.com');
session_start();
The cookies do not show up in the browser because you send a cookie for a domain A from domain B. That is silently ignored by the browsers for security reasons. This is a browser feature not a PHP thing.
If you want to use signed cookies with CloudFront you need to use a CNAME for the CloudFront distribution that is a subdomain of you PHP server domain. A more detailed answer can be found under: https://mnm.at/markus/2015/04/05/serving-private-content-through-cloudfront-using-signed-cookies/
In short: assume you want to use the domain example.com. You serve the PHP files under www.example.com. Then you can use the CNAME media.example.com for the d111111abcdef8.cloudfront.net. To send the cookies from the PHP side to the CloudFront Server you need to use the domain example.com in the Cookie.
The referenced site does also notice that you should use the PHP function header() to send the cookie, not setcookie(). This is because the setcookie function does some encoding that ruins the singing parameter created with the functions mentioned on the site.
I have a load balanced dev site that I'm working out bugs for SSL on and I have ran into one last very annoying issue. On some pages I need to force it to SSL so easy enough, I just wanted to create a
header ("Location: https://www.example.com/mypage.php");
I thought that was easy enough and no worries. However, every time I do this it transforms it back to http. Well as you can figure it creates an endless loop that can't be resolved. I can't figure out how to keep that https in there so that it will pull the secure version of the page. If I navigate directly to the secure page with https it works just fine. The only issue is on this redirect.
Any help would be awesome! I'm using POUND as a load balance proxy. Apache on the web-server nodes. The SSL cert is setup at the Load Balancer.
When loadbalancing, 'internal' SSL usually goes out the door: Clients connect through a load-balancer with which you can do SSL encryption, but behind that in most loadbalancers I've seen is plain 'HTTP'. Try to get your loadbalancer to set a custom header to you indicating that there is a HTTPS connection between loadbalancer & client.
From http://www.apsis.ch/pound/index_html
WHAT POUND IS:
...
an SSL wrapper: Pound will decrypt HTTPS requests from client browsers and pass them as plain HTTP to the back-end servers.
And from more manual pages:
HTTP Listener
RewriteLocation 0|1|2
If 1 force Pound to change the Location: and Content-location:
headers in responses. If they point to the back-end itself or to
the listener (but with the wrong protocol) the response will be
changed to show the virtual host in the request. Default: 1
(active). If the value is set to 2 only the back-end address is
compared; this is useful for redirecting a request to an HTTPS
listener on the same server as the HTTP listener.
redirecting to https pages is no problem.
you can check for the port, scheme or server variable (probably server variable is the best) to see if https is on, and have it as a condition for redirecting
$_SERVER['SERVER_PORT'] == 443
parse_url($_SERVER['REQUEST_URI'],PHP_URL_SCHEME) == 'https'
$_SERVER['HTTPS'] == 'on'
but as you have an infinite loop there must be something else wrong!
try using the load blancer "balance" instead. it only takes about 5 minutes to set up, and instead of proxying, will do "real" load balancing. I would guess your proxy is currently redirecting https requests to the http address. Try making a request without using the balancer. you can do this by setting up the host name in your /etc/hosts file to point directly to a server instead of to the load balancer's IP