Authenticating across different subdomains (but not all) - php

I have a site set up on www.domain.com, the site can authenticate users and persist their credentials in a cookie.
On occasions the users access handlers that are set up on different servers on a different sub domain. handlers.domain.com
I can't afford to use wildcard subdomain cookies (Cookies should not be available for other subdomains)
My solution for access control up until now was that every URL used for handlers.domain.com had a guid specific to the user. The handlers on the other site would assume the identity of the guid owner. This of course is not such a good security practice.
i was thinking about an alternative solution: All links to handlers.domain.com will actually be links to a redirector script on www.domain.com that will redirect to an encrypted time stamped url on handlers.domain.com which will then know for sure that it was accessed as a direct authenticated redirection from www.domain.com.
This solution will work fine on GET scenarios but will fail with handlers expecting POST data (up do big uploaded files)
Does anyone know or can think of a better solution or have any insight on my solution?
(In this case I am using ASP.NET but the solution will probably be platform agnostic, so I will tag this with various web platforms)
Thanks!

As you do not want to use cookies to establish a session (group of requests) you need to find other ways. As the information of the cookie is passed readable within the HTTP request, I do not see a problem if you for that one particular request pass that information as part of a POST request.
If you prefer a GET request I would additionally add a flag inside the users server-side session prior the redirect so to give the script that is the destination of the redirect the possibility to verify the validity of the request on the server-side.

You said you "can't afford to use wildcard subdomain cookies (Cookies should not be available for other subdomains)". Does that mean you can't afford it monetarily or you you don't want the user to have access to all subdomains? If it's the second, you could still use subdomain cookies by putting in an encrypted value with that user's ID and check it versus access permissions on your various subdomains. That keeps everything at the server where it's more secure versus at the URL level. The only way a potential hacker can get past it is to guess another user's ID and figure out your keys for properly encrypting it.

Related

Store Temporary Variables Using PHP?

Okay, on my website, I have a lot of embedded pages for Twitch. Below all the embeds, I also have an authorization flow so that people can log into Twitch and click a follow button.
Normally, the flow would start at: mydomain.com/channel/name, and at the end of the flow, they would be returned to mydomain.com/auth. Originally, I had it so that the start URL would be stored in browser session storage using javascript; and then when they reach the final auth endpoint, I would use the javascript and pull the session storage and relocate them back to the original URL.
This has been working great... however, one of the features I have on my website is the ability to use custom canonical urls to proxy to their channel on my website. So someone could use theirdomain.com to proxy to mydomain.com/channel/them.
This created an issue with the session storage since session storage follows cross-domain restrictions. They would start at theirdomain.com and end at mydomain.com/auth. Since the domains don't match, I can't access the session storage to forward them back to the original URL.
I am using PHP, so I'm wondering what would be the best way to get around this. I figure instead of storing the start URL in session storage, I can save it using AJAX to temporary storage using PHP, linked to their IP addresses. However, I don't know how to do this.
Does PHP have some sort of temporary storage system with definable TTL? That also works across multiple domains? (it would be the same server)
If the request is proxied to the same application then the session is accessible, it's just the session identifier (which is stored in a cookie, hence the cross domain issue) which is causing the problem.
What you can do is pass the session identifier from one domain over the transition to the other domain, as part of a get request, so when you do the leap from theirdomain.comto example.com do it with a link formatted as http://example.com/blah/?session_id=[session_id_from cookie] (ideally using https).
Then on on example.com grab the session_id and use that to set the session_id in the cookie for that domain, and it will load the session from the source domain.
This can be used for session hijacking, but so can having your session_id in a cookie, so it's generally OK to do, though using https endpoints will improve security.

Use URL Query String to Authenticate in PHP

Normally When I design a site that allow users to login, I create session variables of the user info from the database and ensure that at least one of the session variable is available on each page of the site, else the user would be redirected to the login page like this:
if(!isset($_SESSION['username']))
{
header("Location:login.php");
}
But then I've been thinking lately, instead of using session variables to authenticate users, why not use the query string. My idea is to create a unique string which is based on some factors, like date(month, year, day) or access time(day, hour) or ip address, and maybe hash it using md5 so the url might look like this
://mysite.com/dashboard?auth=12jsdnnau819wiskj3jdnck23ksj12j3.
So now I can easily logout a user if he has not accessed the site for more than one hour or more than one day. But I do not know if this is a good idea, that is why i am here, to seek for advice on a better way to go. Thanks all.
Because URLs:
Leak easily
Get bookmarked
Don't carry their data over automatically when the user opens a new tab and navigates back to the site
and because nothing is stopping you from storing the same data in a session and using that to easily logout a user so it doesn't even add the one benefit you highlight.
Don't do this.
Do you remember the days when PHP session ID could be stored in the URL, and you would have URLs that look like: index.php?PHPSESSID=.... ?
We have moved away from this to more secure implementations, user friendly URLs, etc.
Just as a simple example of what can go wrong: A web crawler can crawl your website, and if reaching the admin panel with a properly authenticated URL (as you described), it could become publicly available to ... anyone.
So ... don't reinvent the wheel.
I can think of a few reasons not to do this:
The hashed request parameter is publicly visible. This means anyone using that url will be considered an authenticated user.
As I can see, the token is per user, so all requests using this token will be done on behalf the same user. If you share a url, anyone using that url will impersonate the same user, and have all the access rights granted to that user.
Other answers have mentioned that the urls can easly leak, or be bookmarked. In addition to their points, once the token expires, the url may become broken, if you trigger a login or other authentication redirect mechanism.
A pure technical drawback of your idea is also this: you need to persist the token when navigating across different pages in your app
The HTTP Session has been designed to serve this purpose and at the same time be safe enough. The application session length can be tuned so that it matches your requirement. I recommend you to get familiar on how HTTP sessions work and how to tune your session expiration policy, rather than compromise your application's security

User authentication- Security risk passing session cookie over HTTP?

I have a "Client Center" on my website which is only accessible via HTTPS. I'm currently using a single session cookie to track PHP session variables such as User_Authenticated, Client_ID, etc once they log in.
I want to change the links on my navigation bar from "Login" to "Logout | Client Center" once they have logged in. This is easy enough, but most of my website has absolute links that point to HTTP instead of HTTPS. I could make all of my links relative and that way hopefully keep them on HTTPS once they've logged in, but my site is graphics-intensive and I can't guarantee that they'll stay on HTTPS (if, for instance, they type http://mysite.com on their browser after logging in).
My question is as follows:
1) Is there a risk in passing this cookie over HTTP? I hear that it can be intercepted and spoofed. That would be bad!
2) Can I use two cookies, one which is a secure_only cookie which contains their credentials, and another which just lets the browser know if they're logged in or not, for the links on my navigation bar? Is it possible to use multiple sessions simultaneously like this with different cookies?
I've also heard about using a database-based session management system, but for now that is way over my head. I'm new to PHP and MySQL (this is my first site).
Thanks in advance!
You can do what you want, using a second cookie. Then you can use the session cookie for HTTP and HTTPS pages (to get the login state), but make the authentication only with the second HTTPS-only cookie.
I wrote an article, describing how to separate this two concerns, maintaining the session and authentication. It's a good thing to do, even if you decide to use HTTPS for the whole site.
I would think about enforcing HTTPS for the whole site though, this would make your life easier. If your site has not very high traffic, it should be no problem for todays servers.
Authentication cookies being passed over http is a bad idea. That's the problem that firesheep brought to light, and the reason that Google, Facebook and Twitter, among others, now encourage (or require) https all the time.
If you're worried about sesion hijacking on your web site then you should be enforcing https for every page and asset that needs to be secured. Ideally enforce https for all assets to avoid annoying borwser warnings about mixed security on the page.
You can use this
http://systembash.com/content/force-https-ssl-access-url-apache/

Cross domain cookies

I have a small problem.
How do I set a cookie for multiple domains?
I do understand the security problems, and I am sure it has been done before. The reason for this is SSO.
ie.
account.domain.com will need to set domain logged in for:
domain.com,
domain1.com,
domain2.com.
Is there any easy way, using PHP and cookies, or any alternatives?
There is absolutely no way for domain.com to set a cookie for domain1.com. What you are attempting to do can only be solved by getting the user's browser to submit requests to each domain which will then set its own cookie.
Then you need a way for each domain to verify the user's identity. There are two approaches to this:
Back channel - the sites contact each other directly to determine if a user is logged in.
Passing a token in the GET or POST - when the user's broweser is redirected to the other site a digitally signed parameter is passed containing the identity and session status.
It's really quite complicated. I suggest you don't roll your own. Take a look at SimpleSAMLPHP for a PHP implementation of what I'm describing.
What you're attempting can't be done. (It's a browser security issue, not a PHP one.)
Other than using some form of off-site authentication, the nearest you can achieve is making a cookie accessible across sub-domains, in which case you just use the optional 'domain' arg of PHP's set_cookie function.
This can be done via one domain acting like a master and others like a slave.
Say we've got a domain accounts.domain.com and it's our master.
Then we've got our slaves domain.com, something.com and another.com
When you'll log on on domain.com, it'll be actually site accounts.domain.com, then you'll get a cookie with unique ID for your browser and then you'll be redirected to domain.com's post-logon landing page (ie. domain.com/logon?check=true&unique-id=<browser unique id>&request-id=<unique request ID>). the landing page will contact the accounts.domain.com, querying it with the browser ID. If the transaction's okay, then you'll get logon cookie from domain.com.
Next, on every domain (domain.com, something.com and another.com) will be initial redirect to accounts.domain.com/roaming-check?return-url=<URL the redirect was initiated from>. Because we're returning home (we're logged already on accounts.domain.com), we'll be redirected again on our landing page (<domain name>.com/logon?check=true&unique-id=<browser unique id>&request-id=<unique request ID>) and from this point it's the same as the part with logging on. We're seamlessly roamed to another domain (without user knowing it as browsers doesn't usually show the redirected page until it passed the headers send(server)/receive(browser) section).
In case there's in fact no active logon, the site will save this "negative logon" to session and not try to check logon anymore (until we try to logon or load another domain).
I think this solution will suit your needs: "Simple Single Sign-On for PHP"

Is it possible to set a cookie for a site /server other than you own?

Here's the quick version of my question:
Is it possible to set a cookie somehow into a client's browser when the cookie is for use with a different server (in this case an Exchange mail server)? In this scenario the server trying to set the cookie is at "intranet.myschool.edu" and the exchange server is at "owa_server.myschool.edu".
Here's the full question:
I have a php script that uses cURL to make an HTTP POST to our Exchange server that has Forms Based Authentication enabled.
When I make a successful HTTP POST (which includes the user/pass in the posted url), the Exchange Server (or more specifically, the https://my.school.edu/exchweb/bin/auth/owaauth.dll file) outputs cookies.
Specifically, it outputs a "sessionid" and a "cadata" id.
With these cookie ids written to a text file on the server, cURL/PHP can reference it and then request data (via webdav and such) from the Exchange/OWA server.
That part works.
The problem I'd like to solve is now passing the cookie ids to a clients browser, so that they can use these cookie ids to auto-login to their own OWA account.
In essence I would like our users to log into our intranet with their Active Directory IDs, and see a snapshot of their recent emails. Then, if they need to, I'd give them a little link to switch over to the full OWA web application. When this switch happens, I don't want them to have to login to the OWA manually. Since they already submitted their Active Directory UserName and password at the front of the intranet, I'd like them to be auto-logged into the OWA.
I should note that using Windows Authentication to try to do single sign on is not possible since we have a mix of Mac OS, Windows, and Linux.
I had thought that I would be able to do a "setcookie" and assign the cookie ids that cURL got and put them into the clients browser.
Is this not possible? Is it not possible to "spoof" Exchange/OWA (or any other site) this way.
I have legitimate cookie ids that cURL captured. Is there no way to pass these to a client browser on a different computer?
In a worst case scenario, would using Javascript to just auto paste the username and password into the OWA login page be my only hope?
Does anyone have any other ideas on how to avoid my double login problem with Exchange/OWA?
Thanks for any help provided!
From RFC 2965 (NB HDN = "host domain name)
Host A's name domain-matches host B's
if
* their host name strings string-compare equal; or
* A is a HDN string and has the form NB, where N is a non-empty
name string, B has the form .B', and B' is a HDN string. (So,
x.y.com domain-matches .Y.com but not Y.com.)
Note that domain-match is not a
commutative operation: a.b.c.com
domain-matches .c.com, but not the
reverse.
So using .myschool.edu as the domain should work. NB the leading . is essential
You may be able to set a cookie with a domain part of '.myschool.edu'. In theory that's then sent to any other site hosted under a subdomain of 'myschool.edu'.
In practise however, your client software may decide that the cookie's scope is too wide, and refuse to send it back.
I think this would be a serious security loophole if it were possible...
In this scenario the server trying to set the cookie is at "intranet.myschool.edu" and the exchange server is at "owa_server.myschool.edu".
You should be able to do that.
I do this on my site (which I will change the names for the purpose of the example):
I have a web app at url
webapp.domain.com
And when users login, I set the cookie of the PunBB forum package which is at:
forum.domain.com
By setting/clearing the PunBB forum cookie, I can automatically login/logout my users on their forum account for convenience (this of course assumes that the registrations are syncrhonized, in my case I removed the forum registration and the main site registration creates the forum account for the user).
All you need to do is in subdomain#1 to set the cookie path to "/" (the default), and set the cookie domain to "domain.com". Then your app in subdomain#2 should see the cookie.
EDIT: I see barrowc has answered, I've seen the ".domain.com" pattern in some examples, my site uses "domain.com" for the cookie domain and it works too (maybe php set_cookie adds the leading dot if missing?)
Your browser gets to decide that... but usually no, you cannot. That is considered a type of XSS vulnerability.
you could use an iframe to set the cookie, ie. have an iframe on your web server that makes a request to a page on your exchange http server (https://my.school.edu/exchweb/) with your wanted cookie vars set as get or post variables. then use the vars to set the cookie for that domain, and redirect the user to the exchange server.
now, there could be logic on the backend of OWA that checks ip address, user agent, etc.... when registering the session that may invalidate this..... not sure
We've been fighting this one hard for months, the best we can come up with is allowing the web server to get the cookie for Exchange at EVERY LOGIN. problem is, that without cookie affinity, we don't have a way to make sure that the cookie obtained by the web server came from the same load balanced node that the client connects to.

Categories