Are IDs (ObjectIds from mongo) safe to use in a URL? - security

I was recently told that using mongodb _id fields in a URL is unsafe. I was wondering if that's true.
My site is restricted to registered users, and every user has their URL endpoints which contains an id from mongo. It's the typical mongodb _id field - a SHA1. AFAIK, the id is unguessable, and even if someone hits upon someone else's id, session based authentication in my app doesn't allow access. No one has direct database access other than the application itself.
I'm curious to know if there's anything I'm missing.
Edit: Clarified question. (mongodb ObjectIDs aren't SHA1s)

_id field from MongoDB is (by default) of type ObjectID. It is not a SHA1.
And its string representation (like 4ed7cbfd1d96406ca0000015 is, for sure, URL-safe. I use it everywhere.
I mean, it is safe to expose it everywhere where you would put a regular int identifier (/products/3 or /users/42 or whatever).
On your site you should check if a user is logged in and if he has access to given URL. You should not blindly allow users to visit URLs with ObjectIDs in them, just because they (ids) are not easy to guess (they're easier than SHA1, though)

It's rather good idea to use seemingly random string as _id (or create guid) in URL rather than number. If you have public API, user/1001, user/20032 its just begging for hackers to guess next number and get onto random user info.

Related

Which back-end design choice is better for handling guest users? Storing guests as users with is_guest feild, or storing guest data on the session?

I am building an ecommerce website which should be able to handle guest checkout. When a user visits the website, they are considered "Guests" unless they register / log-in to their account.
However, even as a guest, certain information needs to be stored about that visitor (partially incase they make an account in the furture, but also just for the website to function for them) like their prefered currency, email (if provided), cart and its contents, and an order_id (if they placed an order)
My question is which of the following choices would be better for handling this?
By the way: I am using NodeJS's express-session in this project.
Creating a "User" object for all new visitors and adding the user_id to the session. In this case that user object would need a feild called is_guest: true/false to tell the two apart, and it would also need a is_logged_in: true/false feild so the front-end can tell whether to load the log-in form or the profile page because a user object would always be present.
Only creating a "User" object after an account has been registered through the register form, and storing all data about the cart and email ect. for guests on the session object instead.
I can see problems with both. 1) could result in a really large database if all new visitors create a user object. 2) could result in information being scattered more and the session object becoming cluttered (especially if the cart becomes large). Having never done something like this before, I would appriciate any ideas about objections or solutions to the approaches and what you think would be the best.
Both solutions are fine, and I've seen both being used.
I would guess that storing things in the database is more common. Since you will probably be logging user interactions in your database anyways, it won't take up much more data. Secondly it's slightly simpler to use the same function to render pages for logged-in and logged-out users.
If you don't use a database, you may wish to use LocalStorage instead of a cookie since there are size limits to cookies (although few carts will get large enough to reach that limit).

How to restrict the route access to certain limit(say 3) for non-sign up user

I've routes that offer some features to the users. I want new users to access the routes say for 3 times after that they should be routed back to login page.
We can do it in many ways but which one would be the most robust approach?
For e.g we can save the user session in cookies but if user clear the cookies they can access the routes and that is not what I want.
Any help would be appreciated
Storing cookies on the client devices is not a safe solution. Users can delete their cookies. But it can be useful if you combine this with other methods.
You probably don't have a 100% solution as users can change every information you collect from them for unification. But you can make it as hard as possible.
Let's talk about device unification solutions.
IP: You can get the user IP, store it on your backend. And link it with user type to detect if the user has access to content or not. There are some downsides of this solution; you need to implement a system to update user access. This means another complexity at the backend; most of your users have dynamic IP addresses. They can change it, and this will cost them 10 minutes.
Cookie: As you said, they can delete them easily.
Fingerprinting: There are some unique ways to detect devices. This library is one of them. It abuses some browser features to create unique ids. It is a clientside library, and you can create an id and send it to your backend for persisting. The downside of this solution: It blocks the browser for a second or something like that. But even incognito, it creates the same id.
My way: I would combine all of them and use storage with TTL at the backend. My document would be like this:
Random generated device id at cookie: string
Fingerprint: string
IP: string
User features: bit flag value
Visit number for the feature: int
Whenever a user deletes or changes cookies, I would identify the user from IP or fingerprint. Whenever a user changed its IP, I will identify it from other unique ids I have. And also, on each change, I would update this document. When the user bought new features, I would update the bit flag value. Also, if I can't link this visit with any of the previous visits already existing in the database, I would create a new document.

How to Protect/Encrypt MongoDB Data

I have an existing NodeJS app that allows users to store personal information in a mongo database. This data must be encrypted in some form, or at least not tied to a particular user.
I was planning on using the NPM mongoose-encryption package, but it doesn't work with updating fields. Right now, passwords are hashed with a salt and both are stored in the user document. I was thinking another option could be hashing the user id and using that to associate other docs with the user. This way, if there is a security breach, the data will be unusable without knowing which user it belongs to.
Any thoughts/recommendation on this? What is the best way to protect users personally identifiable information?
Hashing user id or username might not be a good idea, it is ok for user login. but it might bring more pains when u trying to do some aggregation or statistics on the stored data, every time you make a query related to user id, u might need to hash it first and then construct the query.
Besides, user id/username column becomes unsortable and it is hard to build index on top of it, since hashing is not invertible.
Just my personal thinking.

Node express public accessible url security

Good day everyone.
I would just like to run this scenario past you to ensure that I don't have any gaping holes in my approach.
What I want to achieve.
1.Send a mail to a client with a url + parameter that can uniquely identify the client when he clicks on the url and the parameter gets sent to my express server.
2.My express app receives the parameter and decodes it to retrieve the parameter from the encoded string so that I can do a lookup of the customer.
My approach
1.When sending the mail I generate a base64 encoded string that uses the customer_id + '~' + customer_name as the url parameter on the mail I send out.
I also url encode the string.
2.When the user clicks the url and the request gets to my express server I decode the string to retrieve the customer details (customer_id and customer_name) then do a lookup for the customer.
The information I'm displaying is semi sensitive so I don't want anybody tampering with the url to see another client information.
Is my approach correct?
Thank you guys!
This is not that secure. Since you mentioned you are concatenating customer ID + name and just converting to base64, a knowledgeable user could simply decode it and then try variations to "potentially" access other users records.
As a general rule of thumb is not to pass any customer info as link parameter if its sensitive. Instead, create a UUID and store in against the customer record. I personally even set TTL on this UUID. Its a bit more harder to guess and a bit more secure. Then pass that as the link's parameter which could be used for lookup and further processing.
Hope this helps!
While the original approach is not secure, using MongoDB's ID's is not secure either. See this related question.
Unfortunately, MongoDB ID's are guessable, as they were not designed to be used as a source of entropy.
But it really depends on the value of what you are protecting with these URL's, and how much you are willing to compromise security for the sake of convenience. MongoDB ID's are certainly better than the original approach, and may be secure enough for you to be willing to accept the risk.
But if I saw that in your application while performing a security audit, I would mark it as a weakness and recommend that you use a Cryptographically Secure Psuedo-Random Number Generator ( CSPRNG ) such as /dev/urandom.

Is there any danger to creating UUID in Javascript client-side?

I need to generate UUID to eventually store in a database. Can I generate theses UUID from Javascript on the client browser (There are some examples here)?
Is there any security risk of doing it this way? I understand that anyone can modify the UUID before it's passed to the server for storing. So i'll need to check if they are trully unique before storing them in the database, but other than that, is there any other things to checkout?
(Sorry for my english, feel free to correct any grammar errors)
edit: To answer questions about why I would want to do this, it's because I can create a new object and it's identifier in Javascript and add it to my view and then make an AJAX call to the server to add it to the database. This way, I don't need to load it back from the database to know what is it's primary identifier.
Not really. As long as it's a simple identifier and nothing more, and you are indeed checking it for validity and uniqueness, it's no different than user accounts having an id in the url, for example.
Look at your URL bar. I bet 1296234 is the primary key of this question, but I can't really do anything with that information. Same deal with your script.
What benefit do you see in generating these client-side? In all honesty, the best option is to generate it server-side, out of the users reach. It may not give save you from any serious security issues, but it will cut down on redundant validation.
Is there some reason you can't have the database generate (increment) an ID?
If, like you say, you'll have to check the uniqueness of the value before submitting it anyway, why not just have whatever backend language you are using generate it. That would make it much more opaque.
Yes. The risk is not specific to UUID, any client-side generated ID has some risks, depending on what you do with the ID. The problem is that it's very hard to authenticate the Javascript. If you accept ID generated by client, you accept any IDs from the hackers.
The risks may include,
Session stealing. If you use the ID to identify the session, someone may use an existing ID as generated ID and the server may treat it as an existing session if proper care is not taking.
Duplicate keys. True UUID is random but someone can generate duplicate keys which will mess up your database.
You might find ways to defend against each of these attacks but that's passive protection. It might defeat the original purpose of generating IDs on the client, which is simple.

Resources