How to implement this logic in database? - mysql

Here is the situation:
I have a "user" , which have many attributes. For example, "name", "email", "password", "phone".
There are some attributes that are open for public, for example, "name", "email".
These information is open for evenbody who visit the site.
But some, only for trust body in the system, for example "phone".
These information is open for the people that the user trust.... (Assume the user have a trust list that can accept other user to the trust list.)
And the private one "password".
This information is only for the user only, other people can't get access to it.
User can change different security level based on their need, for example, the user want to change the "email" for only trusted body, they can do so. It is also allow the user change their "phone" to public.
I use three number to represent three level of right. The first one with 3, second is 2, and the private is 1. So, I design the database in this way:
User
id(PK)
nameId(FK)
emailId(FK)
passwordId(FK)
phoneId(FK)
Name:
id(PK)
name(String)
securityLevel(int)
Email:
id(PK)
email(String)
securityLevel(int)
Phone:
id(PK)
phone(int)
securityLevel(int)
Password:
id(PK)
password(String)
securityLevel(int) //It must be 1
The question is, I can do it but my database will have many table, is there any simple way to do it? Moreover, is there any books about these kind of database design is recommended? thank you.

You don't need different tables for this, because each relation is a 1-1 relation.
Should a user have, say, multiple e-mail adresses, then you indeed should put the email and securitylevels in different tables. But because in this case, each user has exactly 1 email, 1 name, 1 phone, 1 password - just one table with 1 row per user should do.

If I understand this correctly, you could simply put all this information in two tables (user and friends) because as far as I know, it is a lot more efficient to get larger chunks of data with few queries, than smaller chunks of data with many queries. You would have something like this:
Users:
id
name
name_perm // 1, 2 or 3
email
email_perm // 1, 2 or 3
phone
phone_perm // 1, 2 or 3
password // Doesn't need permissions, always 1
Friends:
user_id
friend_id
When a user visits another user's page, first you check the permission level for each field. If level 2 is found, you would then query the friends table and check if current user ID is a friend of the user whose page is being viewed. If found, user is trusted and level 2 security info can be displayed. As for level 1 security, it's really simple - only display this info if both IDs match.
Hope this helps.

Whether or not the private data is segregated into a separate table does not solve the issue of how to prevent unauthorized access. The MySQL 5.1 manual section 5.4.5 discusses request verification/privileges, but if your database is hidden behind a web application with no direct access to your tables, then standard web server security alone might be sufficient. You should probably mention the entire os/server/db/language bundle you're using (LAMP, SAMP, whatever) so someone can suggest the best security scheme for your configuration.

Related

Which data can I unhesitatingly send over a GET request?

I create a VueJS application with express and sequelize to access a mysql database (currently running with XAMPP). I have a database which consist of 3 tables:
users: [id (primary key), name, email, family_id (foreign key)]
families: [id (primary key), name]
hobbies: [id (primary key), name, user_id (foreign key)]
All of these IDs are auto_increment so the first user registered gets the ID 1 and so on.
Every user within the same family (so with equal family_id) is allowed to see the hobbies of the other family members. I have a SQL query, which gives me all the family members. On my websity I have a simple drop down menu, where I can select the member. With a GET request I then want to retrieve all hobbies of the selected member.
Now I can basically decide if I use the id or the email for the request parameter e.g. /api/hobbies/:id or /api/hobbies/:email. Email reveals more private information while id reveals information about my internal strucutre like "At least (id) number of users exists.". I think it is better to use the id.
Maybe there is also the possibility to assign a random id (not auto increment) in the database? But I dont know how to to this.
Nothing you send as a parameter to a GET request is private. Those parameters are part of the URL you GET, and those URLs can be logged in various proxy servers, etc, all over the internet without your consent or your users' consent.
It seem to me that family members' hobbies can be sensitive data. What if the whole family likes, say, golf? A cybercreep could easily figure out that a good time for burglary would be Saturday afternoons.
And if your app does GET operations with autoincrementing id values, it's child's play for a cybercreep to examine any record they want. Check out the Panera Bread data breach for example. https://krebsonsecurity.com/2018/04/panerabread-com-leaks-millions-of-customer-records/
At a minimum use POST for that kind of data.
Better yet, use a good authentication / session token system on your app, and conceal data from users if they're not members of that family.
And, if you want to use REST style GET parameters, you need to do these things to be safe:
Use randomized id values. It must be very difficult for a cybercreep to guess a second value from knowing a first value. Serial numbers won't do. Neither will email addresses.
Make sure unauthenticated users can see no data.
Make sure authenticated users can only see the subset of data for which they're authorized.
My suggestion to avoid REST-style GET parameters comes from multiple security auditors saying, you must change that.

Grouping with associated variables

i have a table as below:
Account no. Login Name Numbering
1234 rty234 1
1234 bhoin1 1
3456 rty234 2
3456 0hudp 2
9876 cfrdk 3
From the table above, you can see that rty234 and bhoin1 registered a same account no of 1234, thus i know that rty234 and bhoin1 are related and i numbered them as 1. The numbering field was based on the account no.
Then I found that rty234 also registered another account no of 3456 and the same account no was registered by 0hudp as well. Thus, i concluded that rty234, bhoin1 and 0hudp are related. Therefore, i wanted to renumber the third and forth row to 1. If they are not further related, then just remain the numbering. How can i achieve that using mysql.
The expected output will be as follow:
Account no. Login Name Numbering New_Numbering
1234 rty234 1 1
1234 bhoin1 1 1
3456 rty234 2 1
3456 0hudp 2 1
9876 cfrdk 3 3
You need to understand how to design a relational database.
These groupings that you want to make with the New_Numbering field should be done at the time the accounts are registered. I see two pieces of arbitrary information that needs to be tracked: account number and login name. Seems like the people registering the account can type whatever they want here, effectively, perhaps account numbers must be numerical. That detail doesn't matter.
What you want here is one account which can have multiple account numbers associated with it, and multiple logins. I would also assume that future development may add more to this, for example - why do people need multiple logins? Maybe different people are using them, or different applications. Presumably, we could collect additional information about the login names that stores additional details about each login. The same could be said about account numbers - certainly they contain more detail than just an account number.
First, you need one main login table.
You describe rty234 and bhoin1 as if they are unique people. So make this is a login_name column which is a unique index in a login table. This table should have an auto-increment login_id as the primary key. Probably this table also has a password field and additional information about that person.
Second, create an account table.
After creating their login, make them register an account with that login. Make this a two-step process. When they offer a new account number, create a record for it in the account table with additional identifying information that only the account-holder would know. Somehow you have to validate that this is actually their account in order to create this record, I would think. This table would also contain an auto-incremented primary key called account_id in addition to account_no and probably other details about the account.
Third, create a login_account table.
Once you validate that a login actually should have access to an account, create a record here. This should contain a login_id and an account_id which connects these two tables. Additionally, it might be good to include the information provided which shows that this login should have access to this account.
Now, when you want to query this data, you can find groups of data that have the same login_id or account_id, or even that share either a login or an account with a specific registration. Beyond that, it gets hairy to do in an SQL query. So if you really want to be able to go through the data and see who is in the same organization or something, because they share either a login or an account with the same group, you have to have some sort of script.
Create an organization table.
This table should contain an organization_id so you can track it, but probably once you identify the group you'll want to add a name or additional notes, or link it to additional functionality. You can then also add this organization_id field to the login or account tables, so you can fill them once you know the organization. You have to think about if it's possible for two organizations to share accounts, and maybe there's a more complicated design necessary. But I'm going to keep it simple here.
Your script should load up all of the login_id and account_id values and cache them somewhere. Then go through them all and if they have an organization_id, put their login_id or account_id in a hashmap with the value as the organization_id. Then load up all of the login_account records. If either the login_id or account_id has an organization_id in its hashmap, then add the other to its hashmap with the same organization_id. (if there's already one there, it would violate the simple organization uniqueness assumption I made, but this is where you would handle complexity - so I would just throw an exception and see if it happens when I run the script)
Hopefully this is enough example to get you started. When you properly design a database like this, you allow the information to connect naturally. This makes column additions and future updates much easier. Good luck!

Approach to store user login and password on database when there are some roles totally different

I am creating site and there are 3 roles on it. Administrator, Teacher, Parent. User with any role has access to site, but 1 role has full access, teachers can only put marks for students, parents can only watch these marks.
I understand how to separate roles into scripts. Just save some parameter depending on what database would return when I check login and password.
So! Administrator has only login name and username. Also it is possible to store information about how to contact the user to make system more user-friendly. That's all.
Teacher has firstname, lastname, midname (father's name), address, phone etc. And it must have login and password fields...
Parent has Firstname, Lastname, Midname only. And sure somewhere I should to store data about login and password.
So should I just check this tables 1 by 1 and depending on table I will find $login and $password I inputted in I will return role? I don't think it is a nice idea. Suggest something else please.
What I think to do. I think that it would be not very bad idea if I will create 1 more table like users where I will store: id, username, login, role, user_id (need to think about it). The problem is user_id. How exactly this table will be connected to others? For example user_id` would be 1. 101% there would be 1 row with such id.
I want to ask about exprience of your self-build systems. May you suggest something please!
You're right. It doesn't make sense to have different tables for users. I would recommend you to store authorization and personal data in separate tables. And of course you'll need additional table for roles:
The idea behind this scheme is to keep thin users table for fast authorization. If authorization was successful, than you should check permissions from roles or get personal data from user_data tables.
Look at this sql-fiddle for DDL.

MYSQL- Best design to store multiple emails/addresses for one user

I checked this question here but unfortunately the link to the diagram in not working so I'm stuck.
I am trying to have multiple emails for one user (work, business, personal, etc) and I'm not sure how to best approach this situation.
I am thinking to have 4 tables: user, email, email_type, and user_has_email (user N:M email).
I made two diagrams but I don't know which one would be the better one.
First diagram helps me if one user has the same email for both work and personal (because I don't have to store it twice). Second option is good as well but I would have to store emails twice or more even if one user uses the same email for work, business, personal, etc.
I am planning to use the same idea for storing addresses, which occupy more space than emails and I am thinking that the diagram 1 is more suitable for this.
What do you think?
Diagram 1
-explanation of user_has_email: I chose to make the email_type PK because there may be the case when a user has the same email for work or personal. If I don't PK the email_type I would only be able to have one email_type per user. Did I complicated it too much?
Diagram 2
Instead I would use
user (user_id, first_name, last_name)
user_emails (user_id, email_type_id, email)
email_types (email_type_id, email_type)
I would prefer Diagram 1 for the following reasons.
You can make the email field UNIQUE so that you can store it only once regardless of the type.
It does not seem right to make the email and the email type tightly coupled, if you face a situation where you have to establish a one-to-one relationship between the user and the email for some other feature.
Any kind of validation for the user-email relationship should be handled in the business logic (even if you have constraints in the database).
The following structure should fit the bill:
There is a 1:N relationship between users and e-mails, and each user's e-mail can have zero or more types, from the set of shared types.
If the e-mail types don't need to be shared among users, the model can be further simplified:
BTW, the case for using M:N for addresses is not clear either, due to the inherent "fuzziness" of addresses - see this post for some musings on the subject.

Efficient way to handle user roles

I am working on one portal where will be few user roles. I have been wondering what is the best way to handle them. I have created separated tables for users and clients, but clients will want the functionality as users and users can become clients easy too.
I also don't want to make many joints, so what I as thinking is this:
I will have 4 different user roles (at least for now) as follow:
user
client
reviewer
admin
I will assing "id" to each role. At the same time I will keep table in mysql with these roles. It will be something like:
1 - admin
2 - reviewer
3 - client
4 - user
This table will be used only upon creation of user, to get the code of user "permissions". So Let's say that there will be a guy who is a user and reviewer. His role would be 24.
login password email role created
----------------------------------------------------------
guy password guy#gmail.com 24 2012-12-08 23:12:30
I think this could work pretty well, but still want to ask if you guys think this is good and effective solution.
Thanks
The other way to do this would be to have a many to many USER_ROLE table where for your example guy would have the following entires.
login role
guy 2
guy 4
I generally prefer this method of tracking roles. A join against this table in a situation like this should be fast and painless, especially if you move to using a user_id instead of a login, and index appropriately.
What you're defining is a Role Based Access Control System (I would suggest looking up resources on this). An RBAC system will have a separate table for users and another table for roles. There will be a many to many relationship between users and roles. Also, you will connect a permissions table to roles in another many to many relationship. The image attached represents how to implement this system:RBAC SYSTEM IN MYSQL
A similar question was asked before: How to design a hierarchical role based access control system