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
Related
I am working on a site that has a login API. So when people login on my site, they will automatically be logged in to other sites.
Is their way by which a session can be setup so that other websites can use it? If not, is their any other solution?
One way - you can store your session values in database, and can use in other sites. :)
Example:-
let suppose if my site is deployed on multiple servers and end user might be redirected to different servers accordingly to traffic, then it would be good to save the session values in db.
Yes. It's possible using in example Redis for the session storage. You should look for configuring php sessions to use custom storage. Here is php man for this http://php.net/session.customhandler
What you want to do is probably using a cookie that is spread over your whole domain. This cookie can then be linked to a session. I'm currently working on something like this on Symfony2.
As example:
login.mydomain.com
application.mydomain.com
etc.mydomain.com
login.* will obviously contain my login logic + forms etc. This will also contain an API which the other applications can verify the cookie to. My Application will first check if the user is logged in. If not, it will check if it has the required cookie. If it does not, it will redirect to the login.* login page.
If it does have the cookie, it will validate this in my login.* API. Expired > redirect to the login page, if not it will return the required info of that user and "login" to my application.
The only problem I have at the moment is storing the session. I use mcrypt to encrypt the contents and store it in mysql (cookie_id, cookie_contents). I have but 1 problem, it doesn't automatically purge the expired sessions, I still have to find a solution for this.
What you are basically looking for is Single Sign-On (just a guess, but I think accurate).
In my login code on my website, if the password & username are correct, I set a cookie to keep the user logged in.
I just heard from a user that he doesn't accept cookies automatically through his browser, and that that prevents him from logging in. That rhe cookie is not set.
Is there an easy way to counter that?
Tell me if you need the code I use.
It is possible to get this to work but often a real pain if you're using complex javascript/ajax.
In short, instead of storing the session id in a cookie, you embed it at the end of every link.
so
http://example.com/somepage.php
becomes
http://example.com/somepage.php?SessionId=ABC123
Unfortunately, while PHP can do this for you in some cases, it doesn't help with links you build yourself in javascript - and it only takes clicking a single link without the id to effectively log the user out
See this page for more information
As mentioned by Quentin in the comments, if you're not using a cookie to identify the browser which created the session, it's possible that sharing a link would share the session. This could be mitigated but not prevented by checking IP address/user agent but this would likely fail in large corporate environments with NAT and standard browsers
I'm currently trying to join 2 web apps on different domains example1.com and ex.example2.net so that you can login to example1 and click on a link to example2 and be instantly signed in, as it would be more convenient for customers to just login the once and navigate between the sites.
I've researched various means ie. php sessions, openID, JOSSO and Kerberos, but what would be a secure and easy way to implement this?
Kerbros is very extensive and for systems requiring high security. Its very difficult to work with, and even just setup over all, I would not suggest this route unless you know linux very well, and provided your hosting provider allows you that type of access over the machine.
Im not familiar enough with JOSSO or openID to comment well on those however.
Any php sessions are only good for the domain, and server the domain is on, kind of like cookies but not, though in all you would use them.
I think your easiest solution more so if the 2 sites are on the same hosting account/server. Is to have a database specific to this cause. What you would do is create a login system like you would normally but instead you would have 2 sites reading off this login. Aside from the normal login you would also have a session tracking table. Typically you already set sessions when users login to keep them logged in, and you'd do the same here, but you'd add a cookie into the equation one both sites can recognize and use to compare entries in this new table where your tracking your users. I'd say keep try by IP, Browser, and maybe a userID all in one cookie with a unique hash of some kind as well thats specific to the user based on something only the servers could recreate on the info they have for the user.
Of course I dumb it down in conceptual speak, its a little more elaborate than I make it out to be, but this would be your general stepping stones.
Also if the sites are independent of one another you could always create an API between them to pass info back and forth JSONP style so one can act as the hub for the login while the other just validates
But in all its all dependent of what your wanting to do overall how, when where, etc..
You can have one application handle logins for both sites using php sessions.
example1.com
user logs in and php session cookie is stored.
ex.example2.net
check example1.com and validate session cookie. if it does not exist redirect to example1.com login page or a custom login page on example1.com. If it does exist, then log the user into ex.example2.net.
If you only want a link then you generate a hash and pass that to the second app once they have logged onto the first. If the hash validates, then log them in.
If it works for you, my suggestion would be to go the openID route. It's the easier way and it's secure enough. Besides, the registration process is easier and quicker to users too.
You can actually only allow IDs from your sign-in domains, if you prefer, making it pretty much a "private" login system.
There are downsides too... You don't have fine control over the registration process, you are dependent of openID authorization process... There are some problems that might happen if your host is not well configured (timezone differences, for instance).
But overall, it's a relatively secure system, easy to implement.
Kerberus is extremely secure but it's a nightmare to work with. Unless you're dealing with highly sensitive user information, like credit card numbers, or think your websites make apetizing targets for hacking I don't think it's worth your time.
I would use a database table that is shared between the two sites. If you go down the PHP session route don't try and just pass the session data from one site to the next on separate domains, it won't work. I found this post helpful many moons ago: Single Sign On across multiple domains
I am needing help with single sign on. I have siteA.com that requires login credentials, once you are in SiteA.com you can do many things and one of them is access another application siteB.com. If you click on the option to go to this other application, the other application also has a login screen whose credentials are the same as siteA.com, so siteA.com and siteB.com have login screens of their own with the same credentials.
I am trying to make it a single sign on is there anyway I can remote login or pass credentials from siteA.com to siteB.com?
I am interested in:
Solved exactly same problem (actually also for 4 domains). The only solution I've came up with was, to include 3 hidden iframes on the 'Successful login page' and those iframes just load www.domain1.com/register_session.php, www.domain2.com/register_session.php, etc....
As a parameter for register_session.php I use 'sid' which contains session ID:
session_id($_GET['sid']);
session_start();
This is actually for keeping session alive on all those domains but the same would be for your case with cookies.
I think this could work but the problem is given the credentials, how can I make the script login to siteB.com?
I have done something which KIND of works...I copied the html of siteB.com and added that to hidden in siteA.com and at siteA.com made it do a double POST, one to siteA.com's login and another to siteB.com's login. This works only if the user has logged in to siteB.com lately, I think that logging in to siteB.com it sets a cookie to control access thats why doing the double POST allows you to fool the login system and as long as the correct credentials are provided it does a successful grab of login cookie, allowing you to login.
Store the user's information in a cookie( such as the user's id in the database ) then on the login page, look for that cookie. if it exists and is a valid user, go ahead and log them in.
When creating a cookie, you should be able to set it's domain to the domain of siteB.com so that siteB.com can see it. Simply create one cookie for each domain that needs to be able to read that cookie, and set acceptable expires settings on each cookie so that they either expire on session end or after x days.
Depending on how much security you need, you may need to put some kind of protection to prevent someone from simply creating their own cookie to get in freely (such as encryption)
I once had to tackle a similar problem. What I ended up doing was appending a hash to the URL query string of any link [or form] going from SiteA to SiteB, and visa versa. I used an MD5 hash of the user ID in the database for the value. On both sites, if that hash is present in $_GET, log the user in using a search for "MD5(user_id) = ?" instead of searching by username and password.
Edit: Note, this isn't a very secure solution - it just happened to be perfect for what I was trying to achieve. Please do keep security in mind. In my post above, an attacker could potentially determine that the token is an MD5 hash of an integer and start tinkering with it.
I'm new to PHP and trying to get my head around security.
I have an admin page that gives access to certain administrative tasks. Right now, it lets you repopulate database tables with some seed data.
To access the admin page, you first need to login. Currently the login is not over https (it will be soon).
If you authenticate, a token is written into $_SESSION. In every admin page, the token is checked. If invalid, the page is redirected to the login page.
My question:
Is this the proper way to "lock" down sensitive administrative tasks in PHP? Checking a value inside the $_SESSION variable? What more should I be doing?
That's pretty much the standard way to do it. Authenticate the user against your user database / password file / some other authentication data, store the state of authentication in a session variable and finally check whether the session variable is properly set every time the user attempts to make an action that requires authorization.
You could look into role based Access Control Lists if you need a more fine grained level of control. This way, authenticated users are granted or denied access to certain parts of your application based on the role you have given them. This is an additional security measure on top of regular password authentication.
If you only got one user, e.g. the admin, ACL is overkill though.
Session IDs are stored client-side usually as a cookie. If someone steals the cookie, they can hijack the session. Even if you use a secure connection for the login, later, unsecured requests will send it over the wire, and any XSS vulnerabilities can be used to capture the session cookie regardless of encrypted communication. Use session_set_cookie_params to limit the subdomain and path of the pages the cookie is sent to.
You can try to use non-spoofable client data to detect hijacking. Since you don't have control over the protocol, about the only such data is the remote IP, though an attacker can make a blind attack while spoofing their IP. However, this doesn't protect against hijackers behind the same NAT as the valid user and has problems with proxied requests.
You might be able to work out something with HTTP digest access authentication. It's a challenge-response authentication protocol and thus designed to work without protocol-level encryption. However, it's based on MD5, which has known weaknesses. Considering the life of the challenge, this may not be an issue. Digest auth is vulnerable to a man-in-the-middle attack.