I have my Ionic/angular 2 app that is running on localhost:8000 The app will run eventually on browser platform. The app is calling a RESTFull api hosted on my local machine on https://adawy/api, where adawy is my hostname and defined in both hosts file and in apache virtual hosts. The server side is Slim 3.
The API upon authentication is returning a JWT to be used with all requests.
My goal is to protect the token from cross site request forgery and cross site scripting. Saving the token in a javascript variable or in any form of local storage would make the JWT accessible from javascript.
I found that the best way is to return the JWT to as an HTTPOnly cookie. So it won't be accessible from javascript and would be sent only by the browser with any upcoming requests to adawy domain.
I had returned the token successfully as a cookie but the problem is that the cookie is not sent with any next XHR requests.
Also, I cannot see the cookie in the Cookies section in Devtools.
I know that angular can support in such matter by looking for XSRF-TOKEN cookie.
It is not working either, as you can see I set the name of the cookie to XSRF-TOKEN but yet, with any other request, this cookie is not sent.
I wonder how this would be secured as if angular has access to this cookie, so would any other script?
Here is the next request, with no cookie sent. Please ignore the header Authorization as my angular code is setting it directly.
In my angular app, I am setting the withCredentials: true option while making the last get request.
Update
I had used adawy.com and I still have the same issue.
The first response attempts to set the cookie explicitly on a top level domain Domain=.adawy; (see the Set-Cookie header) which is not allowed. Try setting it without the domain if you can and see if that works. Alternatively, try using a hostname that has a tld on it.
Related
I am working on a project in Laravel 8 which I am now testing the deployment on production servers. I have set up 2 Digital Ocean Droplets that are behind a load balancer with Sticky Sessions enabled. I am attempting to login via a SPA app with a separate Laravel API so the middleware is configured for the api routes to be stateful API and perform CSRF validation. This works perfectly fine when I just hit a single droplet and bypass the load balancer but as soon as the load balancer is in use, I always receive a 419 CSRF Token mismatch.
Everything I found on Google says that the session needs to be shared between servers, but I don't believe this is the case in this scenario. I have turned on sticky session with a cookie called DO-LB in the load balancer so all requests from the same session go to the same server, and I am tailing the Apache access log on both servers, and I can see all requests such as the get-csrf and the auth route (using Sanctum) both hit the same server so would I would still be getting a token mismatch.
I am also using the cookie session driver.
UPDATE
I've found something a little strange, if I point my DNS to a singled droplet I see the X-XSRF-TOKEN is sent as a request header, but if I change DNS to point to the load balancer then X-xSRF-TOKEN is not sent as a request header. I am using Axios to send the request but I can't see how a load balancer can affect Axios
UPDATE 2
It looks like when I run it locally XSRF-TOKEN is not an HttpOnly cookie but when running it on production the XSRF-TOKEN is flagged as HttpOnly which from what I've read means its inaccessible from Javascript hence why Axios isn't sending it. I seem to have confirmed this by doing Cookies.get("XSRF-TOKEN") and printing the result, locally it prints the token to the console, but in production its undefined.
UPDATE 3
I updated my Apache configuration to override the headers as a test to remove the HttpOnly flag which seems to have done the trick, and I can now see when I log in, Chrome sends an X-XSRF-TOKEN in the request even though I still get a CSRF Token Mismatch.
I've compared the string in the chrome cookie store with what is being sent in the X-XSRF-TOKEN and they both match so I don't understand why Laravel keeps returning me a mismatch and I am at a complete loss.
I think I've figured this out, if it can be migrated to server fault then please do but I thought as figured out it makes to say what it was instead of just deleting.
I was using cloudflare and made the error of using self signed certificate between DO droplet and cloudflare and gave this cert to the load balancer. Although no errors were thrown by DO, in the Apache log I noticed that although the web site load, when an API request was made I noticed the apache error log Server name not provided via TLS extension (using default/first virtual host). Not sure if this is the actual cause but made me think if the issue was caused by the self signed certificate.
I generated a new origin server from Cloudflare which means it has a trusted CA and then gave that to DO load balancer and the problem went away.
We have our current website in PHP. We are currently upgrading it in Node. We will upgrade it step by step so we'll have some pages in PHP and some other in Node.
Problem is, when users will connect we have to make sure they have a session in both PHP and Node, so they won't have to connect twice.
In PHP we create a PHPSESSID cookie and we store all the data in a session file in /tmp.
In Node we use a JWT token.
What i am trying to achieve right now is: when and user connects with a page that runs on Node, it has to create a PHPSESSID cookie and the session file, so when he will navigate to another page that runs on PHP he will still be connected.
The PHP website and the Node API have the same domain but run on a different port.
Right now what my code does is:
I call the signIn function from the Node API
It creates the JWT token and the user is connected properly in Node
I call the PHP website like this: http://www.mysite.local/ajax/login?user=user&pass=pwd
It creates the session file correctly
It creates the PHPSESSID cookie
But when i check the cookies of my domain, the PHPSESSID doesn't appear. But it does after i create it and print $_COOKIE in PHP.
And because of that PHP can't find any PHPSESSID cookie and can't access the session file.
I'm using Node with GraphQL and Apollo, and PHP with Zend Framework 1.12
Here is how i call PHP with Node:
const url = `http://www.mysite.local/ajax/login?email=${data.email}&password=${data.password}`
const headers = {
Referer: 'http://www.mysite.local/auth'
}
await fetch(url, { method: 'GET', headers: headers })
The sessions in PHP are managed by Zend
I'm testing on Firefox.
HTTP cookies work like this:
The client sends an HTTP request to the server
The server responds with an HTTP response which includes a Set-Cookie header
The client then stores the cookie
Later on, the client sends another HTTP request to the same server. Since it has a stored cookie, the cookie is including in the request headers.
Browsers will, in general, automatically store cookies. (There are some edge cases, like Ajax requests only handling cookies in cross-origin requests if withCredentials is enabled).
Server-side code will, in general, not automatically store cookies. When dealing with server-side code you usually need to explicitly deal with cookies, usually by configuring a cookie jar library (e.g. fetch-cookie).
You are making an HTTP request from the browser to Node.js.
Node.js is making an HTTP request to PHP.
PHP is responding with a cookie (I assume)
Node.js is ignoring the cookie
Node.js is making an HTTP response to the browser
The browser gets the HTTP response (with no Set-Cookie header in it).
At no point does Node.js either read the cookie from the request it made to PHP or copy that cookie in the response it makes to the browser.
That is what you need to do.
(And then you'll need to continue to proxy requests to the PHP through the Node.js because the cookie stored in the browser would be associated with the Node.js server).
I'm learning about Laravel passport package and creating a SPA using Vue.js to test it, I'm wondering about saving the Token in the client browser, If I saved it on local storage it would be accessible from Javascript and anyone run js on the browser would be able to read it !
My questions are; What is the solution for this situation ?
If I saved the token in the cookies It would be accessible too, and I read about httpOnly cookies, so How can I set the cookies to save the token from the response from the API if it's not accessible by Javascript ?
Is there a way to save the cookies from the API ?
I hope I can find answers for my Questions.
Well, there are a couple of things to understand here.
HTTP only cookie
First, HTTP cookies are set by the server using set-cookie header. In this case, you as a developer need not do anything. The browser will automatically set it for you and will send back to the server on each Ajax or non-ajax requests. It will send the cookie as long as it is not expired.
LocalStorage
When using LocalStorage for storing the token, any JavaScript code can read it (known as XSS attack if misused). But, the key thing to understand here is that other domain's JavaScript code cannot read the LocalStorage. The scope is restricted to your own site. Other website's JS cannot read it. So, if you are not using any external dependency or compromised CDN, you are safe.
Cross-site cookie
No. It is impossible to set a cross-domain cookie under any circumstances. Only other domain's server can set a cookie for itself (Unless you have some backend mechanism like Gmail + Youtube to share session). However, in case of a subdomain, the following things are allowed:
Parent domain can set a cookie for any child domain. That is example.com can set a cookie for *.example.com.
Child domain can set a cookie for the parent domain. That is xyz.example.com can set a cookie for example.com.
Of course, the rules are more complicated than that. This article should help you understand further.
I have two domains:
http://localhost:9000 / My AngularJS App created with Yeoman
http://localhost/ My PHP app created with CodeIgniter
My Angular app do $http.post to autenticate in the PHP app and save a session to indetify the user as logged, but, when i try recovery the user informations stored in the CI Session, just don't exists.
How i can allow the AngularJS app access the session and don't lose?
Assuming your PHP app is configured to support CORS, then Angular $httpProvider needs to be configured as follows...
$httpProvider.defaults.useXDomain = true;
And then to allow response cookies to be set, withCredentials must be true...
$http.post(url, {withCredentials: true, ...})
Lastly, you may have to tweak the cookie domain and path to be accessible across subdomains of your TLD. For example, if your CORS server resides at api.foo.com, then it will likely set cookies on api.foo.com by default, and your client app on awesome-app.foo.com will be denied access to these cookies. Of course for security reasons, you not want your client app to read the session cookies of the API.
Hope this helps. Good luck.
Ok I guess this question may be similar to other in the "remote cookies" kind, but I'm not sure that other answers I've read are applied to my case anyway, so here we go.
I have two applications, a client and a server. The server "has" (I know they're actually stored client-side) a cookie and a page which uses it to print out a computed data based on the cookie.
If I access the server page directly, the cookie is taken into account and the data is output correctly.
If I call the same server page from the client via a file_get_contents() the cookie on the server page doesn't get read, and I get an answer computed with an empty cookie.
How to make the server read its own cookies when answering a similar request? Is cURL the only option?
You need to:
Make a request that gets a Set-Cookie header in the response (assuming the cookies are HTTP cookies and not JS cookies)
Store the cookies
Include the cookies in the HTTP request to the page that displays them
cURL is probably the sanest way to go about dealing with being an HTTP client in PHP when you need to pay attention to the headers. Another question gives some guidance about how to go about doing that.
Note that there is no way to send the cookies that the browser accessing your PHP script would sent to the remote server. They are a secret that belong to the browser and that server and will not be shared with your server.