Handle users with MySQL users or table w/ encrypted password? - php

I am preparing a web application that runs only on local network for a small business.
I am using MYSQL and writing the front-end with PHP.
I am not sure on how to best handle users. I have roughly 20 different people accessing the app, and at least 3 different groups with different privileges.
So far I have created users and passwords in MYSQL directly, with a users table that stores personal info (name, last name, email and login info) but NOT the password.
My thought is that this way I can add a layer of security by restricting the users privileges on MYSQL (e.g. avoid that somebody access a page and calls a DELETE query).
I am worried, however, because this approach forces me to keep the password stored at all times (while using the app) in $_SESSION (because I need to connect to DB almost in every page).
Is this approach acceptable?

Related

PHP, MySQL application user and credentials should run on application or db? [duplicate]

This question already has answers here:
Opinions about authentication between application and database tiers
(2 answers)
Closed 4 years ago.
We are creating PHP/MySQL web application.
On one side:
I have my PHP developer that believes creating a table with users/passwords/permissions to give or deny access to some parts of the final application.
On the other side of the equation, my DB expert wants to use the database directly to create users/passwords/permissions.
For the DB option, I think we need to create a separate web service in front of MySQL, for this to work? or do I give users direct access to the DB?
What would make the best way to do this?
How does well stablish php/mysql apps work, like Dupral or Joomla?
Yes this is a question about design best practices, but I need to find out the best practices for PHP/MySQL development. Is MySQL supposed to manage web users, or just one DB user and the rest on the app level.
Go with the PHP route.
Whether you create the logins through PHP or directly through MySQL, they'll still end up in your MySQL database. There are a few differences between the two approaches though. The main point being that if you go the PHP route, your users will be able to create their logins themselves (which means picking out their passwords themselves). If you go the database route, your users will have to have passwords allocated to them.
In MySQL, it's possible to use something like SHA() to securely hash a password (with a salt), though as far as I'm aware you're unable to pick a more secure encryption algorithm in MySQL. SHA-256 / SHA-512 will almost certainly suffice for your needs, though you may want something a bit more secure.
With PHP, you have access to methods like password_hash() and password_verify(), which can be used alongside alongside an algorithm like PASSWORD_BCRYPT or PASSWORD_ARGON2I (which is much more secure than the standard SHA-256 or SHA-512).
Finally, you have to consider what should happen in the event of a database breach (which there are roughly 30,000 of every day). As previously stated, the encrypted password is stored in the database in either case. If you create logins through MySQL, you'll likely also be exposing the method of encryption (possibly along with any salts used). If you build the logins through PHP, an attacker would need full shell access to your website in order to be able to work out how you encrypted your passwords.
Most importantly, never give users access to your database. In fact, I would recommend ensuring that your main database user role only has the required privileges to interact with the data (likely SELECT, INSERT, UPDATE) and using a separate user with CREATE privileges for creation of the users.

How to hide sensitive data from developers

I'm wondering how we could hide sensitive data (databases passwords and other passwords) from some developers for our PHP projects. We are using Subversion for our projects. Is it enough to just disallow some users to access the folders where we have the files with the passwords? Any other suggestions?
Do not store sensitive data in any code versioning system. Keep the variables empty.
After first checkout, set the variables locally.
In case of distributed/remote databases, simply create another access for that user to access that database and provide credentials.
Once you set the values, exclude these files from being updated later.
You could have a DB table that stores sensitive data, and only users with right credentials can read from it.
Each developer has to enter username and password to access a DB via some configuration file.
Also you don't need to set user and password for each developer as you can have ie 3 access levels so create just 3 users ie
DeveloperAdmin ( can change password table)
DeveloperTrustedRead (can read password table)
DeveloperNotTrusted ( no access to password table)
So you distribute same db user pass for not trusted dev.
It should be enough.
If you want to implement a cost-effective yet secure way to let different people access the same resource (the password protected one, as a database) with different levels of security, look at this answer Different ways to store a password variable in a Java web application? and implement the option 3 in this way
create multiple usernames/passwords to access the same resource - like another answer suggests a DeveloperTrustedRead, DeveloperNotTrustedRead, etc... role in the database, each with a different username and password. DeveloperNotTrustedRead (for a database) should not create procedure, alter table, drop tables, access other DBs other than the one he operates, etc..
encrypt username/password for each role with a different key in your application (i.e. option 3)
give the untrusted developer the key only to decrypt the username/password linked to the role that has less permissions, like DeveloperNotTrustedRead or DeveloperNotTrustedWrite
This way you can distribute any file in the SVN, as you will be holding the key to decrypt the credentials that matters, while the distributed key will give access to a less powerful/dangerous set of permissions.
This makes sense only if you need them to access the password-protected resource (i.e. a DB) but you are worried to give high privileges to untrusted people, so you want to minimize their permissions for the DB (or any other protected resource) and keep sharing the code easily.

How to map application credentials to database credentials

As I have been led to believe, the vast majority of web apps use a single database login credential, typically hard-coded into the app code itself or a secured config file. Application logic and sessions take care of managing user interaction with the database; the database remains ignorant of who is doing what.
However, I would like to take advantage of MySQL's current_user() + triggers to perform certain database actions specific to the individual user. This requires that users make database connections with their unique MySQL credentials. Because the PASSWORD() hashed MySQL password cannot be used to make connections, it is required that the app (1) stores the user's MySQL pwd in clear text in a DB table or ACL file, and (2) stores it in clear text in the session, to be used when making connections. That is not ideal.
Is there a better, more secure approach for doing this?

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