Securing MySQL id numbers so they are not sequential - mysql

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.

Related

How to query (hashed) Discord ID in MySQL and return user-defined name

I currently have a database of about 300 freely chosen names and corresponding Discord IDs.
I wish to make a discord bot that "checks" if a user already has a stored name on the database.
It should accept a Discord ID, and return the name that corresponds to the ID.
The problem is that the name is freely chosen and doesn't correlate with the discord tag or username.
For security reasons, the Discord IDs on the database are hashed. However, that poses one problem with salt.
Up until now, I mostly interacted with the database using PHP, where the same problem occured.
The main idea for logging pages seems to be:
SELECT password WHERE username = ?
comparing the hashed value with the entered password by hashing the latter
However, since the bot should return the username, this is troublesome. I cannot filter how many rows return since no filter can be applied, and performing every comparison would add up to minutes of waiting time.
Hashing the value and querying it also does not work, as the salt is randomised.
At the same time, somehow hashing without a salt would prevent this, since you can hash the id and literally compare it in a SQL query. But that of course causes a security issue with rainbow table attacks.
To sum up the problem, I have a list of IDs that should be hashed for security reasons, but they are not associated with any account, but simply correspond with a value. You should be able to enter an ID, and the database should return a username that corresponds to it (if it exists).
Is there a way to hash sensitive data, while also being able to compare it using a SELECT WHERE query, instead of being forced to SELECT everything and loop through every entry?
Some info that might help:
Mysql v5.7.23-23
The bot is created using discord.js#14.6.0
Performing queries with sequelize#6.25.3

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.

Storing userID and other data and using it to query database

I am developing an app with PhoneGap and have been storing the user id and user level in local storage, for example:
window.localStorage["userid"] = "20";
This populates once the user has logged in to the app. This is then used in ajax requests to pull in their information and things related to their account (some of it quite private). The app is also been used in web browser as I am using the exact same code for the web. Is there a way this can be manipulated? For example user changes the value of it in order to get info back that isnt theirs?
If, for example another app in their browser stores the same key "userid" it will overwrite and then they will get someone elses data back in my app.
How can this be prevented?
Before go further attack vectors, storing these kind of sensitive data on client side is not good idea. Use token instead of that because every single data that stored in client side can be spoofed by attackers.
Your considers are right. Possible attack vector could be related to Insecure Direct Object Reference. Let me show one example.
You are storing userID client side which means you can not trust that data anymore.
window.localStorage["userid"] = "20";
Hackers can change that value to anything they want. Probably they will changed it to less value than 20. Because most common use cases shows that 20 is coming from column that configured as auto increment. Which means there should be valid user who have userid is 19, or 18 or less.
Let me assume that your application has a module for getting products by userid. Therefore backend query should be similar like following one.
SELECT * FROM products FROM owner_id = 20
When hackers changed that values to something else. They will managed to get data that belongs to someone else. Also they could have chance to remove/update data that belongs to someone else agains.
Possible malicious attack vectors are really depends on your application and features. As I said before you need to figure this out and do not expose sensitive data like userID.
Using token instead of userID is going solved that possible break attemps. Only things you need to do is create one more columns and named as "token" and use it instead of userid. ( Don't forget to generate long and unpredictable token values )
SELECT * FROM products FROM owner_id = iZB87RVLeWhNYNv7RV213LeWxuwiX7RVLeW12

When to use a relational database structure?

I'm creating a file hosting service, but right now I am creating the account email activation part of registering. So I had to come up with a database structure.
And right now it's:
users
id
first_name
last_name
email
password
since
active
hash_activate
But I can do it like a relational database too:
users
id
first_name
last_name
email
password
since
activation
id
user_id
hash
active
What would be the best way to go about it? And why?
If every person has only one activation hash active at at time, then it's feasible to store it in same table with users.
However, one advantage of separating it is that users only have an activation hash for a brief period of time, so to keep the user records smaller, you could store the hashes in a separate table. Keeping the user records small keeps it more performant. In this case, you wouldn't have active column. You'd just delete inactive hashes.
If you do store the activation columns in the user table, just be sure to select the columns by name. E.g. in most cases, you'll want do this:
SELECT id, first_name, last_name, email, password
FROM users
Instead of:
SELECT *
FROM users
You'd only want to select the activation columns when you needed them.
The second would only be sensible if one user could have multiple activations. You don't say whether this is true or false, so I couldn't possibly advise you.
If activations are a temporary thing, or having a hash defines someone as active, then make them different. Otherwise, that really won't matter.
However, neither is necessarily more or less relational than the other, without much more information. If you put a unique constraint on the combination of values in each row, and set each column up with a NOT NULL constraint, your first one would be quite relational.
You use a relational design when correctness of data, over time, is as important, if not more important, than what the application does with that data, and/or when data structure correctness/consistency is critical to the correct operation of an application, but might not necessarily be guaranteed by the application's own operation.

What is the best practice to create a unique url for every user profile

In my every application i want to create a unique url for users profile as http://app.com/username .
I have the name of user is : 'Vijay Kumbhar' i can create http://app.com/vijay_kumbhar, but if there is another user registers with the same name then what will be better way of creating url for that user.
one way is to add vijay_kumbhar_1, but i dont think this is the proper way of creating a unique url
Can you please suggest me the better way of doing this.
Keeping in the User experience in consideration, firstly provide the user with unique id, through which you can identify the User easily. After that you can allow the User to opt for any new User Name (screen name), but there should be a check again that the user name has to be unique again. Depends upon your requirement. Do keep us posted what way you opted at last.
You can use the same approach as stackoverflow using
stackoverflow.com/users/unique-number/user-name
Usually user names must be unique. If you're using login in the URL, then they urls will be unique. It is common thing to prevent registering two users with the same login.
EDIT:
If you'd like to keep usernames not showing (e.g. for some security reasons), you can use in URL hashes from users logins, not the logins e.g.
app.com/mylogin > app.com/123123123
You keep your registered users most likely in some kind of a database. In SQL it is natural that every row has a unique ID. You could use such an ID as a part of the url, instead of an own running number for every name combination.
You definitely need to make sure you do NOT show the actual "username" in the URL if you have a publicly accessible URL.
If you use an ID number, just remember to avoid the error that Wordpress made - creating the user IDs sequentially, starting with the default admin user as "1".
That made it easy for hackers to query with something like
example.com/profile?author=1
That would return
example.com/admimuser
And show him the actual username of the admin... and then cracker starts pounding away trying to brute force the admin username's password.
And never show the login name to anyone or in any URL other than to the user or admins!