I am using a token based authentication for accessing a few crude web APIs I have designed for my site. At login, the username and password are posted to the login API, and it generates a token with a unique secret key, and the key is stored on the database. At each subsequent call, the token is sent with the request and verified on the server with the secret key.
I am using a web app to consume this API service and deliver a front end to the users. The web application is designed using HTML/Bootstrap/JQuery and the backend is written on php.
I have successfully tested my app and the token based authentication works. However, I have one concern. I find that the user id and token are displayed directly, only using url encoding on the address bar of the browser.
http://hasconpanel.ckoysolutions.com/hasconpanel.php?inputs={%20%22username%22%20:%20%22Debopam%20Parua%22%20,%20%22uid%22%20:%20%2220170520193421DP%22%20,%20%22token%22%20:%20%22Sa2pHyooWPoI79vfvJzLlw7UO%252B2p5hOpBttkEq7LQ%252BjAGm9XEmxfhLAcnJoLbqrsXCp75%252BG1M7nEUoCgsDVbIQ%253D%253D%22%20,%20%22list_of_devices%22%20:%20[{%22device_code%22:%22b8:27:eb:f1:b3:0f%22,%22device_name%22:%22First-Pi%22}]%20}
Now, if this address is copied, or suppose the browser is made to resume the previous session, no matter who tries to access it, they get an entry. Especially in case of public computer centers, if anyone accesses my web app with their credentials, and forgets to logout before killing the browser, the token system seems to fail miserably. Is there anyway to secure the token like encrypting it? Or someway for the app to not store the parameters in case of a browser/browser-tab close or at least not display it on the address bar? I have thought of making a fresh token at each request, but it slows the system drastically, so I want to avoid it.
Please suggest some way to solve this problem.
Thanks in advance.
Edit:
Explaining how the system works now:
The api system is hosted on the main domain of a shared server, and the app is hosted in a sub-domain. The main domain also hosts several webservices that are being called from a few raspberry pis installed at home.
This is how it works, the login is made from the primary website and on successful login, the web app is called with a get call with the user id, the token and a list of working devices for the user. Check is provided to prevent the app page being accessed without any of these three parameters. On fresh load, the user gets the choice to select a device from a drop-down menu. Now, each of these working devices can have three separate systems running. So, on selecting the device, a get call is again being made to the app, with the selected device added as a parameter along with the three previous parameters. This shows the token and the uid on the address-bar.
Token based authentication is very standard in the web world. The details vary, but what you are trying to do certainly isn't crazy. However, your security concerns are valid, and there are a number of potential solutions:
Use HTTPS exclusively. This will protect your token from being easily readable by everyone in between the user and you. Actually, do this regardless of anything else. HTTPS should be considered the default for security purposes these days: just pretend that HTTP is deprecated.
Move the token into the header of the request instead of the URL. As long as you are using HTTPS this doesn't actually change anything from a security standpoint, but it is fairly standard for the industry. It will also keep the token out of the browser history.
It is strange that you have a URL showing up in the browser address bar. I would expect a client-side application to make requests exclusively via ajax, which means there should't ever be anything in the address bar. You might need to clarify more on how exactly this application is working. I suspect you need to refactor so that none of your application URLs ever end up in the address bar, and instead operate via AJAX requests exclusively.
Still, HTTPS is the most important part. Your entire transaction after DNS lookup will be transmitted securely, so the token cannot be stolen by a man-in-the-middle. This is the most important step you have to take to secure it. If you don't use HTTPS, you might as well broadcast it to the world. Of course, if you are making non-ajax requests to a URL with the token in the query parameters then the token will be visible in the browser's address bar and history. Again, avoid that by using ajax requests only and put the cookie in the header.
Once you have HTTPS in place with ajax-only requests, the chances of having a token stolen are much smaller. Still, it can happen (in particular via an XSS attack), so become familiar with the principle of "defense in depth". Also, there are steps you can take to try to detect a stolen token an invalidate it. Things like:
Invalidate a token (for the user to log back in) if the IP Address changes (although this can impact mobile users, which probably isn't desirable)
Invalidate a token if the user agent changes (although that can be spoofed)
Enforce a server-side maximum session length
Make sure and require the user to re-authenticate if they want to change email/password.
Those are just a few suggestions off the top of my head. Again though, this is a pretty standard problem, so google will be your friend.
Related
I think it's important to say that I don't have any experience in the technologies nominated below, I have some idea what is going on, I've googled a lot, but still - more I google more dumb I feel. :)
Making an app in Ionic 2, users of this app can read/write data about themself in DB.
I am using Wordpress as backend, actually users will change values in the table that was created by some Wordpress plugin.
First problem - I have no experience at all.
Second one - I must understand which user is knocking to the server.
Because user can change only his own data in DB.
I've solved it by creating a script that checks GET request from app & that request has a param with user nickname, so I have turned this script to template and assignined it to the page. ( template was first thing that went to my mind, if you have better idea - please tell me how to do it better! ).
Well now I knew who it is, but I disliked that this so unsecure!
Its only GET request with user name in it and changes to bring into DB.
NOT GOOD.
I've thought that I should send not only nickname but also some kind of a password, so I can check if the user is actually genuine user, well, you know.
But knowing nothing about security, didn't know where to start so I've started googling.
I've find out that there is 'Basic Authentication' - disliked it because password is verry simple to decode (base64) and you must send it with every request (not safe).
Then I thought about crypting pass with strong algorithm like bcrypt & then send it with the request. Disliked it too - because at the end you are always send a password even if strongly crypted.
Now I've started to look in the direction of Auth 1.0
(because saw that wordpress has a plugin for it, I know little about wp however).
But after all I am not so sure that I am doing things in the right way.
I must finish many things, but I am stuck with this security issue and I don't know if it's my paranoia and there is simplier ways to accomplish what I want to do.
Don't have much time, don't want to waste time anymore.
Please, someone who is pro in this stuff give me an advise how to do this thing in the right way!
because I am going crazy with that stuff.
The best practice is to issue an access token from your server to your (or even third-party) client application by the following steps.
A user uses a client application.
The client application asks the user whether to use your service.
The user answers "yes".
The client application opens the authorization page of your service using a web browser. In other words, the client application makes an authorization request to your authorization server.
The authorization page explains to the user that the client application is requesting some permissions and asks the user whether to approve it or not.
The user inputs his/her ID and password into the login form in the authorization page and then presses the "approve" button.
Your authorization server authenticates the user and issues an access token to the client application.
The client application accesses a Web API of your service with the access token.
The Web API of your service checks whether the presented access token is valid or not.
If the access token is valid, the Web API returns a successful response to the client application.
RFC 6749 (The OAuth 2.0 Authorization Framework) defines 4 flows to issue an access token. Check the specification.
I'm writing a RESTful Webservice with the Slim Microframework and use GET for reading data from a mysql database (select query) and also POST/PUT/DELETE for insert/update/delete rows in the database.
My question is now, is this not a big security issue if everybody is able to write or delete data in the database? But how could I prevent this, I thought the ST in REST stands for state transfer (so the webservice is stateless), which is a contradiction to a state like being logged in or not. And if I would pass some login data with the client which is allowed to write in the database, couldn't a bad guy catch the logindata and fake requests with it and for example delete all entries?
So, whats the normal way to go with this, the only Slim Framework examples I had found always show the route examples, but not how to secure it.
Are there also some opportunities in the Slim Framework to implement this what I need? It should be as easy as possible and the request should be responded nearly as quick as without an authentification or similar. There are no sensitive data like passwords, for me it would be enough that not everybody with a cURL commandline tool can delete all rows or things like that.
Would be great if anybody could explain me what to do and/or give some examples. I also need to know, what I maybe will need to change at the clients which are allowed to send the requests.
Lots of thanks.
Each request has to be authenticated and authorised.
People often get tied up with the word 'stateless'. This really just means that from one request to the next, the RESTful service has no prior knowledge of the users state.
BUT, the service is obviously allowed to be aware of the authenticated user that has just made a request, else how would it decide if it should allow access?
Therefore, you can 'store' the authenticated user in some variable during each request. Then it's up to you how you use this information to authorize the request.
I like to keep it simple and have all my users as a resource in my URI chain. They make requests like users/{username}/someresource.
I authenticate using http basic authentication (over SSL) and authorise based on the URI. If the request failed authentication, its a 401 Unauthorized Request. If the URI {username} and authenticated {username} do not match, the request is a 403 forbidden. If it is authenticated and authorized, the request is allowed (http code dependant on http verb)
Now that's the web service covered, now on to the web service client. This of course HAS to store state, otherwise your user would have to log in every time they make a request.
You simply store the users session in the application (as per normal session management) with the addition that you store the username and password (encrypted of course) in the session. Now every time a request is made, your web service client needs to retrieve the username and password, and send it with the request to your web service.
It will be stateless, in the sense that there won't be a session or a cookie, really. You'd normally issue out a key that would be required for INSERT/UPDATE/DELETE.
It is then up to you to pass the key with each request and to determine when a key should expire.
It would be as safe as normal http authenticated sessions. These use a cookie etc to authenticate the connected user to the stored session state.
A stateless service would be no different - the token is passed to the service just as a token is stored in a cookie for normal http. If you are worried about sniffing (IE man in the middle attacks) you would secure the link via SSL.
The authentication token generated by the service would be encrypted and would include a salt which is also verified on the server for each request. You could also limit the session time to suit your paranoia, and also check changes in source IP, user agent etc and expire the user's token if these change.
I recently ran into similar problem. As recommended by people here, I have decided to go with OAuth Authentication.
I am using HybridAuth A php wrapper for OAuth and out of the box sign in solution for Facebook, Twitter, Google, LinkedIn, etc.
We are building a PHP multi-tenant application. Each company's account will run on their own subdomain abcorp.example.com. The application allows companies to write and publish content (faqs, etc) for their customers to read.
They will tell their customers to visit: abcorp.example.com/ to read the content. Or they will put a link to that URL in their secure web application.
However these companies may not want just anyone reading the content by going to abcorp.example.com/
So, the question I have is there any way to provide some basic authentication without getting into username and password authentication. I was thinking about some kind of hidden token added to the hyperlink or something like that
My goal:
If users type abcorp.example.com/ directly in the browser, they will not be able to see the web page because they didn't authenticate or pass the token in.
Avoid using username and passwords
Another option would be Referring URL Authentication
Of course, if someone makes the token public, it will open up access to whoever finds it.
I suppose each company could link to their page using a shared token, for example:
abccorp.example.com/?t=4rrfwr23rwads3
Each token could be stored in a file or a database.
When someone requests a page, it checks the value of $_GET['t'] with the one stored on the server. If it matches, it loads the rest of the page. Of course, this variable would have to be carried throughout the site, and included in every link.
Again, this will not be very secure. An exposed token could give access to the site to the entire world.
Your "hidden token" idea is essentialy the way sessions work. A session can be used to identify a user (ie. keep track of what a user does as they browse through the site), and is propagated either by passing the session ID along in links or by storing it in a cookie.
However, using a session without any other sort of authentication is inherently insecure! When you expose the way to authenticate and track users to the user itself, the user can modify or forge their authentication. For instance, the user could change the value passed along for the session ID or change the value stored in the cookie.
Please read the PHP manual section on sessions and security.
Client-side certification. Check out http://en.wikipedia.org/wiki/Mutual_authentication.
You could also use the clients IP address as a token, giving different IP addresses access to different (parts / instances) of the system. But gain, this is not very secure, as
you have no way of knowing who is behind the client PC and
IP addresses can be spoofed. Perhaps you could develop additional specs; giving IP addresses only access during office hours, or check the clients browser (user agent) and check it against the user agent officially being used at the client.
You can use basic hashing whereby a shared secret password or "key" is stored on your system and each company system (a different key for each company and not published publicly), and then you hash the secret password with the subdomain in the link and include the digest as a parameter. Then you validate it by running the same algorithm on your side and compare to the digest.
the link might look something like
abc.example.com/?d=b5939ca22f5dcf345b4000641995478c5910dbd1607b1bdadcbf4a8618a95211
where digest is:
$d = hash('sha256', $secret_password.$subdomain);
or including the referer:
$d = hash('sha256', ($secret_password.$subdomain.$_SERVER['HTTP_REFERER']));
The hurdle to get over is making sure each of the companies can support the correct generation of these links based on the company specific key/algorithm - and that it is different for each company so one company cannot produce links for another.
It is better than no authentication, or a public shared token that is not validated at all, but I'm sure it still has vulnerabilities.
I need to login with my account with php curl in a website that uses facebook connect to login.
I'll take as example site one of my favourite apps: Mousehunt
As you can see, it uses facebook (of course) to login: if you are already connected to facebook, it succeeds in automatic login, otherwise it popups facebook login.
How i can login into it with php curl? I know some about curl & cookie (cookiejar, cookiefile, post etc) but not too much.
Which is the target url to post data? How can i return to that site as user logged in?
Let me explain how this sort of FB login works. There is of course the alternate method used for desktop applications, which would make it possible, but this website doesn't use it.
So heres the deal:
The login button opens a link on facebook servers containing the api key of the website and some arbitrary information. So far so good. You could simulate that easily.
Then after accepting the privacy stuff you get redirected back to the website. You can simulate that as well.
But then comes the burden:
The location you get redirected to contains an facebook token after the hashtag (#).
The website can then read this token by Javascript and use it to query the facebook api to confirm your dientity.
The reason why this is done that way is easy:
Think about it. Everyone could fake a request in the name of the website and read your private data. But everything after the hashtag is never readable by the server the request is directed to. The web browser just does not pass it and it would be violating http standards and cause an error.
The only way to access it is by javascript. And this can only be by the website serving the request (where facebook redirects to). And the domain where facebook redirects to is locked by the application key owner.
You see javascript is an essential part of the security here.
I think it is very insecure indeed because there are many possible explits, but its very easy which is a reason why this form of login is spreading so much in comparision to e.g. openid.
So to sum it up: You need simulate a fully javascript enabled browser. It is partly possible but very complex and there are no out of the box solutions for that.
well, there might be a way.
looks like facebook request don't sign the permission scope in any way.
so this basically means you can grant the application/website more permission than they even asked for.
then you could grant the website permament permission - log in the usual way - and save the cookies.
then you can send those cookies along with curl.
if the website uses servers side login authentication, which is very likely, you will still be logged in, because the access token is permament.
however there is no guarantee for that hack to stay functional.
I'm trying to implement single sign-on for a web portal. I've written some code to send a POST request containing the user's login credentials to an external web app to log the user in. (Don't worry, this is all over SSL)
The HTTP response from the web app contains a cookie for the user's login. Is it possible for the web portal server to then pass that cookie to the user's browser? Or is that impossible since the web app is on a different subdomain? I understand there are some security measures built into cookies.
Short answer: NO.
The HTTP server can indeed log into the other service and pass the service's cookie back to the user, but the browser will set that cookie's domain to be the HTTP server's, not the remote service's. There's no way for 'server A' on 'domain A' to make a cookie appear to have originated from 'server B' on 'domain B'. If it were possible, it'd be trivial to steal everyone's authentication cookies for their bank, facebook, myspace, etc...
There are indeed things like cross-domain policies build into modern browsers.
However once upon a time, I created a single login techlology for my own website.
There is a trick you can do. First, on the main site where the users have their
login information, have them a secret generated key. With this unique secret
key to every user, pass them to the other site like
www.abc.com/secret_key
from this secret key, your other website should be able to pull the needed information
like username, profile picture & stuff like that and should create the session on that
domain. So you would have the session created for the opposite domain.
If you still need to pass something back, I would recommend you to go a way that
incorporates RPC over PHP and post something back to your major domain.
This should solve your problems. If you want I can attach some example code.
Note: The security here is in the secret key. Since it's a unique generated key
for example, a md5 hash, it's hard to replicate this. So there is no such thing
like someone could reprocude the secret_key and then login to your site as someone
else.
You should also note that, the secret_key api should only be able to get the
needed information so that not too much information is gathered on the other side.
Why reinvent the wheel? I think that you can find OpenID implementations for PHP. For the consumer and the provider.
You can restrict your OpenID-logins to your domains only if you don't want them to be used elsewhere.