user data database structure - php

I'm running a basic website with some user accounts (no cookies, php session system.).
I'd like to store some data generated by the user only visible for themselves.
For the moment I store the data from all users in one table, with an extra column for identifying (this is an input from php session user-id). (We are talking about max. 50-100 keys per user).
On data request I have an extra parameter (AND "user-id"=x) in the mysql query.
Is this a safe (there is no sensitive data on the site, but the accounts have to be private anyway) way of storing data?
Are there better ways to handle this? (I read about separate databases etc.) and if so, how?
thx,
M.

Is this a safe (there is no sensitive data on the site, but the
accounts have to be private anyway) way of storing data?
There is nothing wrong in having the user-id=x in your mysql query to get the data from the table. But make sure you are not directly reading this value from your query string and appending to the mysql query without doing proper sanitization and cleaning. Otherwise you will be a vicitm of SQL injection.
Are there better ways to handle this? (I read about separate databases
etc.) and if so, how?
I don't see any reasons to have seperate database to handle this. You can use your current database. If needed, you may create additional tables for this. I am not sure what is your db schema and entity relations. So i am not in a position to tell you how to do that. Look into your tables and make sure it is normalized.
If you want the data stored to be seen only by that particular user, You probably want to check in whether the current logged in user id ( get from the session variable ?) is same as of the userId of the db record. May be you can compare with the "CreatedById" field value if you have one.
I believe this link is a must read if "SQL injection" is a new term for you.
http://www.unixwiz.net/techtips/sql-injection.html

Just use the PHP $SESSION.
By using session_set_save_handler you can define your own session storage method, which could be a MySQL database for instance.
The values in a session can not be altered by the user directly (as you can with cookies). So this approach is perfectly safe, so long as you don't expose the PHPSESSID cookie value anywhere.

No way is 100% safe. Your method sounds very insecure but I cannot see your code. If your are cleaning the input correctly to avoid mysql injection and also there is no way for a user to specify a key of another user then you may be ok.

Related

Including obscured IDs in the URL

I need to include the user ID in the URL like this:
http://www.example.com/user.php?id=123456
However, there is a problem. If a user manually changes the ID in the URL to 123455 for example, that could potentially lead to an erroneous update of the database.
For this reason, I need to somehow make the ID in the URL unreadable to the user so they can't just subtract 1 from the ID and be able to alter another user's data.
Another requirement is that the ID in the URL must be usable, meaning that whatever we do to it, PHP must have a way of figuring out the database row corresponding to that particular ID.
There are 2 possible solutions I can think of. I would be happy to hear your opinion on which one is better. If there's an even better solution that I haven't thought of, please let me know.
Including an encrypted version of the ID in the URL - that should make it extremely difficult for a user to just change the ID in the URL and guess another user's encrypted ID. It's also easy for PHP to decrypt the ID when needed and use it to request the user's data from the database.
Adding a new column called "hash" in the "users" table in the database. As you may have guessed, every user will have a unique random hash or UUID stored in the database which will be included in the URL. That makes guessing another user's hash very unlikely. PHP can easily retrieve the user's data by using the hash in the database query.
If a user manually changes the ID in the URL to 123455 for example, that could potentially lead to an erroneous update of the database.
The way to solve this problem is to have sanity checks on the server so the user is not allowed to erroneously update the database. You either want some sort of permission checking ("this user is not allowed to update this record"), or other consistency checks that ensure no updates can be made erroneously ("the user is generally allowed to update this record, but right now it would cause a conflict with something else, so we won't").
You will have to include some id in the URL, and a user will always be able to change that id. At best you can make valid ids harder to guess by using something other than consecutive numbering, but that doesn't solve the underlying problem that your server has no sanity checks. Don't fault the user for generating errors, it's your code that's allowing it.
You should use sessions for this, not GET[] parameters, sessions are the tool for this Job. You can try the solutions you think of but from my point of view using sessions will be a lot better and simpler to use and implement.
But if you need to do something like the classic "recover my acount" so you don't have a way to log in you user, them you may use a hash in an URL and send it by email to "ensure" your user is the one who get's the URL.

PHP App Save User Data, password and login info is better in more than one table?

I have an app in php and Mysql. For security purposes is better to save user´s data in differents tables? or if I save all in the same table has no problem? The first approach, makes that the user info in some object is not complete in memory. Is that in php safer?
Yes, this could be done as a defense in depth approach to security.
You could have one table that stores username, and bcrypt password hashes, and the database account that authentication uses is limited to this table only.
Another approach is to have another database that the page that authenticates has access to, then use another database for the rest of your site that the post-authentication connection uses.
This would limit any data extraction from your system if a vulnerability such as SQL injection exists. Of course it is better to concentrate on protecting your system against existing vulnerabilities initially, then design in separate databases as a part of a system hardening exercise. Separation of databases will help you if there are any future mysql vulnerabilities that may allow injection of queries. You never know if such vulnerabilities exist until they are discovered.
It's ok to use one table. Don't store password in the db, only it's hash to compare in the future.
Separate your back end from the UI well. Escape all user inputs. The question is not about storing the data in one table. It is about how strong the protection of the entire DB is.

Should I validate/sanitize $_SESSION variables in php?

I'm building a quiz site, where I store some variables
(time taken to answer, which answer-option was chosen by the user etc etc) in $_SESSIONs after each question - where I put those stats into the DB only after the user finishes the quiz.
I've implemented a few if's to check if those $_SESSION variables are numbers (is_numeric()). Also I validate the length (strlen()) etc.
But is there a reason to do that?
Or is it enough just to real_escape_string() those before storing them
in MySQL?
Also if there would be many users, then won't that put a big load on
the server?
No, since you set them yourself.
Unless of course you deduce them directly from user input in which case the exact same rules that apply to every bit of user input apply.
There is nothing special about $_SESSION variables. You need to sanitize user input when you receive it from the user - regardless if you store it in a database, a session, or so on.
Like JPod suggested - when performing SQL queries - always use prepared queries which mitigate SQL injection.

Should a users table be in a different database than website content?

Apologies if this has been asked before, but I did some searching and wasn't able to find an answer to my question.
I have my website content stored in a MySQL database (let's call it content) and I need to write a simple login system for my website. So, I need to create some sort of users table that holds usernames, passwords, permissions, etc., and what I'm wondering is whether I should just make this a new table in my content database, or if it would be more secure to have it stored in a new database? The downside to having it in a second database is that I will have to use two database connections instead of one.
Maybe this is a silly question, but I appreciate your input!
You don't need to use a differnt db. That's more reserved for when you've got data that has completely DIFFERENT purposes, e.g. company A has a db and company B has a db.
Note that simply having two different databases does NOT require two different database connections to access. As long as the user ID you're logging into the DB with has proper access rights, you can do:
SELECT onedatabase.table.field, someotherdatabase.table.field
...
Moving sensitive information to another database is a great Defense In Depth strategy because it is limiting the impact of SQL Injection. This works off the principle of isolation and planning on failure. This is a common practice for protecting sensitive Medical or Finical information. Often these separate databases will go a step further and store the information in an encrypted state.
SQL Injection under MySQL is very limited, you cannot stack queries (e.g: '; drop table ...) and without MySQL's file privileges you cannot get a shell. The only thing left that is useful is obtaining credentials using a union select or sub-select to access other tables or databases. As long as you have separate user accounts, and separate permissions an attacker will have to find SQL Injection in a query that is accessing the sensitive database, which reduces your attack surface. Not be able to access sensitive information with SQL Injection makes this attack much less useful.
Also, you should be using parametrized queries.
It's a good idea. For security reason, it might be better not having users logging in at all. An idea is having a central admin account that you control, and then have the users send their content to you by mail. That way, you can be sure no one else will have access.
As you say, you’d need to maintain more than one database connection if you were to do this. Although sand-boxing the databases is a nice thought, 99% of database-powered websites with user registrations will store the users with the content.

Database encryption

I have a database that contains user details including sensitive data. They're not as sensitive as financial, but they are sensitive nonetheless. The passwords to the accounts are hashed and salted but the rest can only be encrypted not hashed to allow editing.
How far would you go encrypting the fields? Would you go as far as encrypting everything including generic fields like username, first name, last name, or only fields like address and phone. The first name is used frequently after the user logs in.
Can someone suggest an algorithm (with sample code if available) to encrypt the fields? I use PHP and MySQL primarily.
I wouldn't encrypt the fields at all since it's going to be a royal pain in the rear end :-)
I would instead move sensitive data to a separate table and use the security features of the DBMS itself to protect the data while still allowing access to the non-sensitive data.
In other words, have two tables (user and user_sensitive) tied together with a userID column. Let anyone peruse the user table to their hearts content but access (of any sort) to user_sensitive is restricted to admin-type bods).
And, if my DBMS didn't provide such facilities (I do not know whether MySQL does), I would move to a DBMS that did.
If you want a user to have access to their own sensitive data but not that of other users, we once implemented such a scheme in DB2 by providing a stored procedure. It retrieved all the desired rows but also checked to see which user was executing it. For rows that didn't match that user, the sensitive information was blanked out. The underlying table was fully protected from everyone except the stored procedure itself.
In order for that to work, you would have to be able to run the stored procedure under a different user from the one invoking it. Whether that's possible under MySQL, I have no idea.
I'd google for "transculent databases" - there are both printed books on the subject and some on-line resources.
There are variations of this method but basic idea is to:
encrypt only sensitive fields
encrypt with key from data only the user knows of (like login/password pair)
Password ofc must not be clearly saved in any table. Keys should be held only for session. This way the attacker doesn't have the means to decrypt information whether the database and/or the application is compromised (forgetting for a moment possibility of modifying app code and silently gathering keys).
You want to encrypt the database but still be able to access it using the application. This means that the application needs to have a way to decrypt the data. If the attacker has access to the database, it is quite likely that he will gain access to the application and figures out how to decrypt the database.
You could use transparent disk encryption. However, this only guards against physical access to the disk. It does not add much security if your server is stored somewhere safe.

Categories