Imagine we are building a shared bookmarking app with the following tables:
Company (companyID)
User (userID, companyID)
Bookmark (bookmarkID, content, companyID)
A user should only be able to access the bookmarks which match their companyID.
Traditionally you would ensure this kind of security by not giving a client direct access to the database. Instead you would have a server that would authenticate the user, and the client would send a unique token to the server along with a request for Bookmarks. Once the server receives this token, it would know exactly which records in the Bookmarks table the user is allowed to access.
That's great, but what if you don't have a server, and you want to rely purely on CloudKit?
Since you don't have a server, it seems like you must allow full access to the Bookmarks table to each user. Then, the client side code would be responsible for preventing access to records that are off-limits. (E.g. When you send a retrieve Bookmark request, you would use a predicate such as companyID == 3.)
The question is how secure is a system like this which allows full access by the client, but limits it based solely on client side code?
(Note: For this question, assume an attacker jailbreaks their phone, and uses whatever means necessary to access data they aren't allowed to see. In the case where we were using a server, we don't care if they jailbreak their phone, since all requests still need to go through our servers. The only way they would be able to access data they can't see is if they found out the secret token that is assigned to another user. However, when the attacker has access to another user's phone, I'm assuming all bets are off: the attacker would be able to figure out the secret token that other client is using and then access that user's private data. Therefore, the original question I posed can ignore the case where the attacker has access to another person's phone, since even in the more secure version (with a server), all bets are off. In other words, assume the attacker has access to their own phone only for the following questions.)
Examples of things I am wondering:
Can the attacker figure out which credentials the client is using for CloudKit and then run custom queries against CloudKit?
Assuming I am using a predicate such as #"companyID == %#" and replacing the %# with the contents of a variable, can the attacker simply change the value of this variable before the query is sent?
Assuming I am using a predicate of the form #"companyID == 3", can the attacker simply change the string to #"true || companyID == 3" so that they get all records?
Can the attacker monitor network traffic and see requests that are being sent to CloudKit and then modify those using a man-in-the-middle technique?
Say I want to prevent duplicate companyIDs from being created so before I create a company, I run a query to fetch that companyID. Once I have the company stored in a local variable, I run code such as if companyID != nil { return } before I create the company. Can the attacker modify their client so that it doesn't execute this line of code? What if instead of companyID != nil, I use a boolean, companyExists. Would that make any difference?
Before I send a new bookmark to CloudKit to be saved, I run code such as bookmark[#"companyID"] = 3 to set the proper companyID. If the attacker changed this value to 4, for example, it would be a security violation. Can they do something of this nature?
Does the client matter? I'm primarily concerned with iOS, but what if I made an Android or JavaScript client? Would that make it any more/less secure?
Does the OS version matter? Should I only users to run the app if they are on the latest OS for maximum security, or does that not matter?
Are there any other things you can think of that would make this system less secure than the server based model? (I can think of at least one: If you had a bug in an old version of the app which printed the entire contents of a table, for example, there would be no easy way to correct this. A user could purposely avoid upgrading their app with the intent of stealing people's private data forever. The only way around this would be to migrate all the data to new tables that the old client doesn't know about. I'm sure this would be a pain.)
Related
I want to authenticate my users based entirely on cookies and sql db.
What I do is:
1. Once they login, I generate a random string, create a hash from it, save it in the database along with the user id and his IP.
2. I send the hash to the user as cookie
3. Whenever he wants to access something, I verify if his cookie hash matches the one on the server and also if his IP matches. Of yes, he is valid or else, log him out.
4. (As pointed by Akhil) If he clears his browser cookies or anything does not match the information on the database, I clear all the rows with his username and log him out.
Note: I use a session cookie for storing the random hash, which again is generated using the timestamp, and as long as time doesn't repeat itself(I believe), its random in the corect way.
Is this fine? How can I make it better?
Once they login, I generate a random string
Make sure you use a cryptographically secure method to generate the random string. Do not use mt_rand use something such as openssl_random_pseudo_bytes.
create a hash from it,
Make sure to use a secure hashing algorithm (not MD5, and at least SHA-2).
save it in the database along with the user id and his IP.
One thing to bear in mind is that some internet connections share IP addresses or will sometimes change the client IP address (e.g. AOL or mobile).
I send the hash to the user as cookie 3. Whenever he wants to access something, I verify if his cookie hash matches the one on the server and also if his IP matches. Of yes, he is valid or else, log him out.
It sounds like a good way of doing it and there are no flaws in itself. I would implement a session timeout mechanism. For example, store the date last used in the DB for a sliding expiration and the query will only query records that have not expired. You could have a background process that runs to clear out old, expired records.
Also, use HTTPS and set the Secure and HttpOnly flags on the cookie. This will prevent them being leaked over HTTP, but I would not go as far as disabling HTTP on your system as there are workarounds for an attacker if it is anyway.
I would not be concerned with the cookie being stolen by another user on the same machine. If the cookie can be stolen in this way then the user's machine is probably compromised anyway and you cannot make your system protect data that is outside of your control. You could however renew the token (random string) on a periodic basis giving the user a rolling cookie. You would have to ensure only one user can be logged in at once under the same account though for this to be effective.
Your method only makes sure that the user possess the random string you generated and is using the same external IP address. There exists several way of abusing this system:
if your website doesn't enforce HTTPS then a user connecting using an unsecured public WiFi network could be at risk: if another user of the WiFi network is listening to all the packets being sent on the network, he could intercept your cookie and use it to access the website as your legitimate user. Your server would be unable to differentiate them because they'll both use the same IP address... (There is a Firefox extension available which enable anyone to intercept such login cookie easily: http://en.wikipedia.org/wiki/Firesheep)
This system is also more generally vulnerable to man in the middle attacks (without HTTPS)
If your cookie is stored on the user computer's hard drive it could be reused by another user.
So to answer your question, your system can be deemed as secured provided a few conditions:
you enforce the use of HTTPS on your website (unencrypted HTTP connections should be refused)
your random string is truly random (there exist right and wrong ways of generating random strings in PHP)
your cookie has a short expiry and preferably is set as a session cookie.
You should take a look at the following related question providing details about the proper way of doing what you want to do: How to secure an authentication cookie without SSL
One cannot say this is "bad". But in Web Development, and specifically in its security domain relativity talks. I recommend you to download a CodeIgniter (google it for more info) Session Class (standalone version) and use it. The basic idea is the same as yours, but it is properly more mature since it is developed in such a famous php framework. You can do your DB operations within that class too, since it allows session saving to DB.
I'm currently working on a web application which deals with multiple users. Whilst it currently works, it relies on some real bad practises which I'll outline in a minute.
We're using MySQL as the database system, since we're updating our current application, we want to ensure everything is backwards compatible. Otherwise I'd look at MongoDB etc.
Our users are stored in a table aptly named login. This contains their username, email, hashed password etc and a field which contains a JSON encoded object of their preferences. There is no real reason for doing this over using a meta table.
So the bad practises:
We're storing the entire users login row, excluding their password (although this is an internal-only app) in a cookie. It's JSON encoded.
Once the user logs in we have a secure HTTP cookie, readable only via Node.js for their username and their password so that we can continue to keep the user logged in automatically.
We have a app.get('*') route which constantly ensures that the user has their three cookies and updates their acc cookie with new preferences. This means that every time the user switches page or accesses a new AJAX item (all under the same routes) they have an updated cookie.
Every time a user performs an action we do this to get their user id: JSON.parse(res.cookies.acc).agent_id yuck!
Now, each user is able to perform actions to certain elements on the page, this effects everyone as the application is internal and anybody can work on the data inside of it.
I know what I want to achieve and how it should be done in say PHP, but I can't figure out the most effective way in Node.js.
I've started creating a User module which would allow us to get the user who performed the action and neatly update their preferences etc. You can see this here bearing in mind that it's a WIP. The issue I'm having with the module is that it doesn't have access to the users cookies, since it's not "a part of" Express. Which explains the last bad practise.
What would be the best way to handle such a system and remain bad-practise free?
I doubt it meets all of your requirements but its worth checking out out Drywall; A website and user system for Node.js
Hopefully it (or parts of it) could be helpful to you.
http://jedireza.github.io/drywall/
I'm writing a GWT application where users login and interact with their profile. I understand that each form entry needs to be validated on the server, however, I am unsure about potential security issues once the user has logged in.
Let me explain. My application (the relevant parts) works as follows:
1 - user enters email/pass
2 - this info is sent back to the server, a DB is queried, passwords are checked (which are salted and hashed)
3. if the passwords match the profile associated w/ the email, this is considered success
Now I am unsure whether or not it is safe to pass the profile ID back to the client, which would then be used to query the DB for information relevant to the user to be displayed on the profile page.
Is there a possibility for a potential user to manually provide this profile ID and load a profile that way? My concern is that somebody w/ bad intentions could, if they knew the format of the profile ID, load an arbitrary amount of information from my DB without providing credentials.
-Nick
What you are dealing with here is a session management issue. Ideally, you want a way to keep track of logged in users (using random values as the session key), know how long they have been idle, be able to extend sessions as the user is using the site, and expire sessions.
Simply passing the profile ID to the client, and relying on it to send it back for each request is not sufficient - you are correct with your concern.
You want to keep a list of sessions with expiration times in a database. Every time an action is executed that needs user permissions (which should be pretty much everything), check to see if the session is still valid, if it is, extend it by however long you want. If it is expired, kill the session completely and log the user out.
You can store your session keys in a cookie (you have to trust the client at some point), but make sure they are non-deterministic and have a very large keyspace so it cannot be brute forced to get a valid session.
Since you're logging a user in, you must be using a backend that supports sessions (PHP, .Net, JAVA, etc), as Stefan H. said. That means that you shouldn't keep any ids on your client side, since a simple id substitution might grant me full access to another user's account (depending on what functionality you expose on your client, of course).
Any server request to get sensitive info (or for any admin actions) for the logged in user should look something like getMyCreditCard(), setMyCreditCard(), etc (note that no unique ids are passed in).
Is there a possibility for a potential user to manually provide this profile ID and load a profile that way? My concern is that somebody w/ bad intentions could, if they knew the format of the profile ID, load an arbitrary amount of information from my DB without providing credentials.
Stefan H is correct that you can solve this via session management if your session keys are unguessable and unfixable.
Another way to solve it is to use crypto-primitives to prevent tampering with the ID.
For example, you can store a private key on your server and use it to sign the profile ID. On subsequent requests, your server can trust the profile ID if it passes the signature check.
Rule 1 - Avoid cooking up your own security solution and use existing tested approaches.
Rule 2 - If your server side is java then you should be thinking along the lines of jsessionid. Spring Security will give you a good starting point to manage session ids with additional security features. There will be similar existing frameworks across php too (i did not see server side language tags in the question).
Rule 3 - With GWT you come across javascript based security issues with Google Team documents and suggests XSRF and XSS security prevention steps. Reference - https://developers.google.com/web-toolkit/articles/security_for_gwt_applications
I'm developing a mobile application for a company. Everyone at the company has an #company.com email address. The app itself is confidential, so it will only be installed on employees' devices. This app communicates with an external server to store and retrieve data.
Ideally what I would like to accomplish is to let people log in to the app by just providing their email address, without a password. Here is my current thinking:
A new user opens the app for the first time on a certain device and puts in their email address. The email address is sent to the server, along with a static token embedded in the application (which is the same for all instances of the application).
The server verifies the token and the fact that the email address is #company.com. It responds with a new token/key for use only with that user and device, which the client stores in plain text locally. That key is effectively the user's password. It is hashed, stored in the server database, and marked as disabled.
There are two possibilities at this point:
The server sends an email to that address confirming that they want to log in on a new device. The email contains a link which, when clicked, marks the key as enabled. There would need to be rate-limiting on new device requests so people can't get spammed if someone discovers the token embedded in the app.
An administrator specifically approves new device requests.
Every subsequent client request to the server must include the key.
Assuming all communication is over SSL, does this sound like a secure strategy? Is there a more secure or simpler approach?
Additionally, what is the best way to generate the token that will be stored client-side? Since I want users to only put in their email address the first time they use the app, I believe that this token will never change. Here is my current algorithm (PHP) loosely based on Drupal's drupal_get_token():
// Usage: get_token($email) or get_token($client_token)
function get_token($value = '') {
$salt = hash('sha256', 'Some static, predefined phrase');
$hmac = base64_encode(hash_hmac('sha256', $email, $salt, TRUE));
return $hmac;
}
As you can see it doesn't protect against parallel attacks (e.g. if someone figured out the predefined phrase and algorithm and they had access to the database, they could generate hashes and compare them against the ones stored in the database) but because the original key value is already long I don't think this would be nearly as effective as it would be against normal passwords. Additionally I am not sure of a way to create a dynamic salt that an attacker would not already have access to if they could access the database (or honestly if it would even matter at that point, since getting access to the database would expose the data we're trying to keep confidential anyway).
After some research and more thought, I believe that the answer to this question comes down to the vulnerability of the local storage. Since it's safe to assume in this case that only company employees will be using the app, there is insignificant risk of malicious code running in it even if there was a problem in the code that would make that possible. As a result the main risk is from some other app taking advantage of a security hole in the OS's local storage implementation to read the local private key off the disk. Since the existence of the app should not be known to anyone outside the company, it is very unlikely that this information would be directly targeted. So I think this is an acceptable process for this company.
In the general case though, anyone considering implementing a similar model should be aware of the risks of basically storing a password in plain text locally. (This is as opposed to storing a password in the user's head, or equally likely in plain text in a password file elsewhere on their machine; it's your call which is more secure.)
So lets say i have a member base website and when the user signs in i put put a cookie (or a session) with a key value pair remembering who the user is. But its just come to my attention which information i should use to remember the user so that its secure. I cant use username=username or user_id = user_id (because my user_id will be 1), because people then can just simply guess what the cookie values are and logged in as that user. So what key/value pair should i use to be able to identify users and still connect their information to the database securely? Thanks.
Ben, there are a few different types of attacks you need to be concerned with. For example simply encrypting the identifier with a private key doesn't prevent someone who can intercept the encrypted value from simply replaying it to your server (and appear to be the user). Some common security risks are detailed here (and in associated links at bottom of this page):
https://www.owasp.org/index.php/Session_hijacking_attack
Session management can be quite complex and depending on the level of security you require, it is not something you want to tackle yourself, because likely your development environment / framework already has a solution that has been vetted moreso than a homebrew solution. Here is a link detailing some things to consider, unfortunately this topic has more to it than a simple Stack Overflow post:
https://www.owasp.org/index.php/Session_Management
If you dont prefer encryption for whatever reason, then a simpler solution could be to use a GUID to identify the user. This way, a hacker would have to launch a denial of service kind-of attack on your application to be able to run through even a very small fraction of the GUIDs.
If you want to do this properly, then you should have a look at http://jaspan.com/improved_persistent_login_cookie_best_practice also.
I'm definitely not an expert in security, but I have recently implemented user management tool and I have done the following.
Don't use encryption, its slow and most of the time for simple implementation its just a waste of time.
Here is what you do need to store on the server - in order to authenticate each request.
UserId (obvious)
CookieHash (made out of userId, some secret private key and crypto randomly generated number)
LastLogin
SessionRenewed (useful for when to cancel someone's session eg. renew cookieHash every 10 min, otherwise log out user)
LastIP
What I store in cookie is following
UserId
CookieHash
How to use this basic security
Simply when user logs in you check username/password etc. (just the usual) If everything is fine then log in user and generate new cookiehash and fill those values given above.
Every request check UserId against its hash. If someone gave UserId = 4 but hash didnt match then automatically drop a session and forward user to login screen. Possible log is good to see how often people try to play around with your hard work.
I hope this helps.
You can just encrypt the user id with a private encryption key that you keep on the server. There are a few things to watch out for with this approach:
Every call to the server will require you to decrypt the cookie to get the id of the user. This will add overhead to each request.
If the key is ever compromised, you will be forced to abandon the current name for the cookie you use and use another encryption key when assigning to the new cookie name; this will cause the user to have to re-login, of course.
While I don't think that these are major hurdles, they might be to you, and you would have to evaluate the impact on your site for yourself.