Should I store users IP addresses in a separate table? - mysql

I am building a new website that will store IP addresses in multiple tables like users, login_history, payments and more.
I am wondering if I should add an ip column in each table and store the actual ip, or I should create a separate table named ip_addresses and store the ip identifier in the columns.
Method 1:
users:
username | ip
jon_snow | 134744072
Method 2:
users:
username | ip
jon_snow | 1
--
ip_addresses:
id | ip
1 | 134744072

Since IP addresses will change for most of the users over time, the best place to store them is perhaps in the login_history table. This way you can associate the IP addresses with the users and their sessions.
Of course, if you want to restrict user access based on IP address and you rquire your users to use the same IP over the time, then store it in the users table.

IPv4 addresses are meaningfully formatted 32-bit integers. IPv6 ones are meaningfully formatted again, but much larger. Either way, you'd be creating a 1:1 mapping of dense data. Unless you need to do it for other reasons, I would not normally choose to normalise them into another table. You're unlikely to gain speed or save space, unless your users have a very restricted set of IPs.
The used of inet(6)_aton will pack string representations, and the _ntoa version will unpack them efficiently, so you can use meaningful strings and store efficient binary versions.

Related

Should you put USER data in tables within a single MySQL database, or have a separate database for USER data?

Is there an advantage to separating user data into a separate MySQL database from the main application database? The number of tables in a db can add up, and separating them by function seems a good way to reduce the clutter.
The way I was told to think about your database data is that if you are going to be referencing the data again it should be in a separate table, just like if you are likely to enter the same data more than once it should be in a separate table and then linked or joined.
Using a separate Database is a little excessive.
For example lets say you have a user, who has an email address and a postal address.
There is a chance that the postal address could be used by more than one user (family members for example) so I would then put the User, eMail address and Postal Address into different tables each using the User row id as a join between each table.

Securing MySQL id numbers so they are not sequential

I am working on a little package using PHP and MySQL to handle entries for events. After completing an entry form the user will see all his details on a page called something like website.com/entrycomplete.php?entry_id=15 where the entry_id is a sequential number. Obviously it will be laughably easy for a nosey person to change the entry_id number and look at other people's entries.
Is there a simple way of camouflaging the entry_id? Obviously I'm not looking to secure the Bank of England so something simple and easy will do the job. I thought of using MD5 but that produces quite a long string so perhaps there is something better.
Security through obscurity is no security at all.
Even if the id's are random, that doesn't prevent a user from requesting a few thousand random id's until they find one that matches an entry that exists in your database.
Instead, you need to secure the access privileges of users, and disallow them from viewing data they shouldn't be allowed to view.
Then it won't matter if the id's are sequential.
If the users do have some form of authentication/login, use that to determine if they are allowed to see a particular entry id.
If not, instead of using a url parameter for the id, store it in and read it from a cookie. And be aware that this is still not secure. An additional step you could take (short of requiring user authentication) is to cryptographically sign the cookie.
A better way to implement this is to show only the records that belong to that user. Say the id is the unique identifier for each user. Now store both entry_id and id in your table (say table name is entries).
Now when the user requests for record, add another condition in the mysql query like this
select * from entries where entry_id=5 and id=30;
So if entry_id 5 does not belong to this user, it will not have any result at all.
Coming towards restricting the user to not change his own id, you can implement jwt tokens. You can give a token on login and add it to every call. You can then decrypt the token in the back end and get the user's actual id out of it.

Storing multiple values for a single variable (PDO)

I have a MySQL table that stores user emails:
user_id | user_phonenumber
----------------------------
id1 | 555-123456789
I want to allow the user to store multiple phonenumbers and I don't want to limit the number of numbers a user can be associated with.
What's the best way of structuring my data, and how would a query work in PDO?
For example, should I store them all in the same field with comma separators and then parse the output when the query is returned, or should I use another table and have each row as a separate number with common user_ids? How would a lookup work then (please provide example code if possible)?
Thanks
Generally RDBMS systems are designed to access fields/rows. Everything will be much harder when you start to break the data-field link/consistency/logic.
I mean when you start to store more data in a single field.
But you know your system's future. It can happen that you won't ever have to access for example the first phone number, and if you can handle it everywhere as a blob then it can be fine to store more values in a single field.
Anyway If this is not a homework or similar short living task then you should choose the 1 phone number/1 record approach.
I mean something like this can be future proof:
create table user_phonenumbers(
id auto_increment primary key.
user_id integer references user(id),
phonenumber varchar(32)
);
Yes, use another table to store user phone numbers.
use inner join to lookup, it would be good.

store users and pass in single table or separate table

I want to create a user management system for my site ,
what is better for security and performance .
Type 1 :
table_user : user_id , user_name , user_email , user_password . user_phone ...
or
Type 2 :
table_user : user_id , user_name , user_email ...
table_pass : user_id , user_password .
table_phone: user_id , user_phone .
which one is better ?
Ideally:
Don't store passwords at all (even encrypted). Store hashes derived from passwords.
Salt the passwords to prevent rainbow attacks.
Put hashes on a separate database server, behind its own firewall and its own well-defined API1. This API should do only three things:
For given username, retrieve the corresponding password hash.
For given username, set the new hash (to support resetting the password).
Remove given username and its hash (to support user unregistration).
Do the same for salts: put them on their own server and behind their own firewall and API. This API should do only three things:
For given username, retrieve the corresponding salt.
For given username, set the new salt to a random value (to support resetting the password).
Remove given username and its salt (to support user unregistration).
Both hash and salt servers should be cut-off from the world (and from each other) and only accessible from the server that runs your Web application (i.e. PHP or ASP.NET or whatever...).
When user tries to log-on by entering username and password:
Make sure this is done through HTTPS so the entered data safely reaches your server.
Call the API that retrieves the password hash for the username.
Call the API that retrieves the salt for the username.
Salt and hash the password entered by the user and compare it to the retrieved hash.
If they match, user is granted the access.
By their nature, hashes are irreversible - other than the user, nobody, not even you, knows the exact password. In case the user forgets the password, you can't send the password to them, but you can allow them to reset the password assuming they pass some additional verification (i.e. have access to a particular e-mail address and/or answer a secret question).
BTW, log-on is a relatively rare operation, so it's unlikely to pose a performance bottleneck unless you completely disregard proper indexing.
1 E.g. implement a Web Service, then open only the port needed for that Web Service and nothing else.
I will go with option 1.
Think there are lakhs of users. So to get the user data you will have to deal with n tables instead of 1 table, which obviously add LOAD on server and finally you will have BAD PERFORMANCE.
So, I would go with option 1.
For tel. number, add field as landline_number, mobile_number, alternate_number as adding field in table won't make that much difference then adding table for the field.
And yes, as per Steve comment, store password using secure hashing mechanism.
So what option are you going to choose?
Firstly, as #Steve comments, you should store passwords using a secure hashing mechanism - storing plain text passwords is irresponsible - it means that anyone who can hack into your system knows user passwords which they may have re-used on other sites.
Secondly, there is no inherent security or performance benefit in either design - from a security point of view, you have to assume that an attacker who can get access to your database can run queries, and it would be trivially easy to retrieve data in both schemes. From a performance point of view, the cost of the joins in option 2 is unlikely to matter if you have primary/foreign key indices.
If you have requirements to re-set passwords after a certain period, and you need to store password history to prevent people re-using passwords (this is a feature Windows supports, for instance), you need to go have a "UserPassword" table, with valid_from and valid_until columns.
It depends. If you would like to keep password history and if user can have many telephone numbers then you create additional tables for passwords and phones. In other case one table is enough.

data type for emails

I have a program where the user can enter multiple email addresses to get notification. I'm creating a field in the database to keep track of this and I'm not sure what would be the best data type to choose for all the email addresses. At this point I believe we will limit it to 4 email addresses.
What data type would be appropriate here for mysql?
Not sure this is relevant but I plan to serialize the data (with php function) When processing the email addresses. Interested in any feedback on my plans and if there is a better way to do this.
This indicates that you have 1:many relation of user:email addresses. Create another table with user_id and email columns and link it up to your users table via user_id.
Never serialize data and stick it in a column, you'll regret it later.