ASP.NET Core: how to hide database ids? - sql-server

Maybe this has been asked a lot, but I can't find a comprehensive post about it.
Q: What are the options when you don't want to pass the ids from database to the frontend? You don't want the user to be able to see how many records are in your database.
What I found/heard so far:
Encrypt and decrypt the Id on backend
Use a GUID instead of a numeric auto-incremented Id as PK
Use a GUID together with an auto-incremented Id as PK
Q: Do you know any other or do you have experience with any of these? What are the performance and technical issues? Please provide documentation and blog posts on this topic if you know any.

Two things:
The sheer existence of an id doesn't tell you anything about how many records are in a database. Even if the id is something like 10, that doesn't mean there's only 10 records; it's just likely the tenth that was created.
Exposing ids has nothing to do with security, one way or another. Ids only have a meaning in the context of the database table they reside in. Therefore, in order to discern anything based on an id, the user would have to have access directly to your database. If that's the case, you've got far more issues than whether or not you exposed an id.
If users shouldn't be able to access certain ids, such as perhaps an edit page, where an id is passed as part of the URL, then you control that via row-level access policies, not by obfuscating or attempting to hide the id. Security by obscurity is not security.
That said, if you're just totally against the idea of sequential ids, then use GUIDs. There is no performance impact to using GUIDs. It's still a clustered index, just as any other primary key. They take up more space than something like an int, obviously, but we're talking a difference of 12 bytes per id - hardly anything to worry about with today's storage.

Related

Company Name? Claim? New Column?

I am planning to use Identity Server 4 and Asp.net Core Identity together. My website that will be talking to Identity Server 4/Asp.net Core Identity will be expecting that a company name comes back with each user.
Should I create a new customer table called Company and in the Asp User table add a column linking them together.
Or should this be a claim?
I know when I authenticated my user and they are sent back to my main site, I will have a company table and they will be linked but just not sure for the purposes of identifying them.
I feel like it should be a claim but I want to double check since I am new to all this.
In terms of using IdentityServer, technically everything is a claim. The "user" object IdentityServer returns will have all the properties mapped as claims. In that sense, it really doesn't matter which approach you go with.
However, it's generally better to keep data on your user table, if it makes sense to. Something like a foreign key relationship is especially valuable to exist at a database level, as there's more value to that than simply getting a company name.
Storing data as claims is most useful when that data is transient or not applicable to every user. Typical examples include things like third-party access tokens, such as from Facebook. Storing that on the database-level would inevitably result in denormalization of your database table, so it makes more sense to use a claim.

Sending out Database Document Ids (Security)

I have a web app that stores objects in a database and then sends emails based on changes to those objects. For debugging and tracking, I am thinking of including the Document Id in the email metadata. Is there a security risk here? I could encrypt it (AES-256).
In general, I realize that security through obscurity isn't good practice, but I am wondering if I should still be careful with Document Ids.
For clarity, I am using CouchDB, but I think this can apply to databases in general.
By default, CouchDB uses UUIDs with a UTC time prefix. The worst you can leak there is the time the document was created, and you will be able to correlate about 1k worth of IDs likely having been produced on the same machine.
You can change this in the CouchDB configuration to use purely 128bit random UUIDs by setting the algorithm setting within the uuids section to random. For more information see the CouchDB Docs. Nothing should be possible to be gained from them.
Edit: If you choose your own document IDs, of course, you leak whatever you put in there :)
Compare Convenience and Security:
Convenience:
how useful is it for you having the document id in the mail?
can you quickly get useful information / the document having the ID ?
does encrypting/hashing it mean it's harder to get the actual database document? (answer here is yes unless you have a nice lookup form/something which takes the hash directly, avoid manual steps )
Security:
having a document ID what could I possibly do that's bad?
let's say you have a web application to look at documents..you have the same ID in a URL, it can't be considered 'secret'
if I have the ID can I access the 'document' or some other information I shouldn't be able to access. Hint: you should always properly check rights, if that's done then you have no problem.
as long as an ID isn't considered 'secret', meaning there aren't any security checks purely on ID, you should have no problems.
do you care if someone finds out the time a document was created? ( from Jan Lehnardt's answer )

Securely store data for multiple party's in a single table

I'm certainly no DBA and only a beginner when it comes to software development, so any help is appreciated. What is the most secure structure for storing the data from multiple parties in one database? For instance if three people have access to the same tables, I want to make sure that each person can only see their data. Is it best to create a unique ID for each person and store that along with the data then query based on that ID? Are there other considerations I should take into account as well?
You are on the right track, but mapping the USER ID into the table is probably not what you want, because in practice many users have access to the corporations data. In those cases you would store "CorpID" as a column, or more generically "ContextID". But yes, to limit access to data, each row should be able to convey who the data is for, either directly (the row actually contains a reference to CorpID, UserID, ContextID or the like) or it can be inferred by joining to other tables that reference the qualifier.
In practice, these rules are enforced by a middle tier that queries the database, providing the user context in some way so that only the correct records are selected out of the database and ultimately presented to the user.
...three people have access to the same tables...
If these persons can query the tables directly through some query tool like toad then we have a serious problem. if not, that is like they access through some middle tier/service layer or so then #wagregg's solution above holds.
coming to the case when they have direct access rights then one approach is:
create database level user accounts for each of the users.
have another table with row level grant information. say your_table has a primary key column MY_PK_COL then the structure of the GRANTS_TABLE table would be like {USER_ID; MY_PK_COL} with MY_PK_COL a foreign key to your_table.
Remove all privileges of concerned users from your_table
Create a view. SELECT * FROM your_table WHERE user_id=getCurrentUserID();
give your users SELECT/INSERT/UPDATE rights on this view.
Most of the database systems (MySQL, Oracle, SQLServer) provide way to get current logged user. (the one used in the connection string). They also provide ways to restrict access to certain tables. now for your users the view will behave as a normal table. they will never know the difference.
a problem happens when there are too many users. provisioning a database level uer account to every one of them may turn difficult. but then DBMS like MsSQLServer can use windows authentication, there by reducing the user/creation problem.
In most of the scenarios the filter at middle tier approach is the best way. but there are times when security is paramount. Also a bug in the middle tier may allow malicious users to bypass the security. SQL injection is one thing to name. then you have to do what you have to do.
It sounds like you're talking about a multi-tenant architecture, but I can't tell for sure.
This SO answer has a summary of the issues, and links to an online article containing details about the trade-offs.

Guid(Random ints) vs regular int primary key for chat application

I am not asking a general "guid vs ints which is better" question. I know that, or atleast think I know that they both have specific scenarios where one is better than the other. But I do have a specific scenario where I am writing a chat application. I started the application with all my primary keys being ints. But after doing a bit of research I realized that I might be having a security flaw in the application as I am passing the primary key to a user's browser for different entity requests such as chatrooms, talkers and such. One would agree that a subsequent primary key could be guessed and hence it is possible for users to alter other users sessions and states. In trying to prevent this, I was considering using guids as my primary key but then another thought hit me. A thought about performance. Since this is a chat application, is using a guid really going to cost me performance-wise if the application comes under heavy load, say 10s or 100s of thousands of users simultaneously for e.g. I am not really informed enough to make a choice here. My question in short is, do I need to change my primary keys to guids to help make guessing primary keys harder or is there some other way that I could secure my application without resorting to guids. If the question is not clear enough, let me know and I will clarify, thanks.
No you don't need to change your primary key to GUIDs. This will not necessarily give you any additional security and it is arguably security by obscurity.
Using GUIDs makes it infeasible for an attacker to guess another user's ID, or a chatroom's unique key. However, it doesn't stop them seeing the IDs if they're transmitted and then being able to perform whatever action you're currently worried about.
Instead, when a user makes a request on the database you must validate whether they are allowed access to that data. For example, they should only be able to retrieve their own user information, or basic user information about other users (such as handle, but not e-mail address).

What are best practices for handling ids in web services?

We have two separate systems communicating via a web service. Call them front-end and back-end. A lot of the processing involves updating lists in the back-end. For example, the front-end needs to update a specific person. Currently, we are designing the back-end where we are making the decision on what the interface should be. We will need the actual database ids to update the underlying database, but we also see where propagating database ids to our consumers could be a bad idea.
What are some alternatives in forcing the clients (i.e. front-end) to have to send ids back into the web service to update a particular entity? The other reason we are trying to avoid ids is the front-end often saves these changes to be sent at a later date. This would require the front-ends to save our ids in their system, which also seems like a bad idea.
We have considered the following:
1) Send database ids back to front-end; they would have to send these back to process the change
2) Send hashed ids (based off of database ids) back to the front-end; they would have to send these back to process the change.
3) Do not force the clients to send ids at all but have them send the original entity and new entity and "match" to our entity in the database. Their original entity would have to match our saved entity. We would also have to define what constitutes a match between our entity and their new entity.
The only reasonable way for front-end would be to someway identify persons in DB.
Matching the full entity is unreliable and isn't obvious; for returning hashed ID to front-end you need to receive not-hashed ID from front-end first, or perform some revertible "hashing" (more like "encrypting") under IDs, so anyway there would be some person identifier.
IMHO it does not matter whether it will be a database ID or some piece of data (encrypted database ID) from which the ID could be extracted. Why do you think that consumers knowing the database ID would be a bad idea? I don't see any problem as long as every person belongs to a single consumer.
If there is many-to-many relation between persons (objects in DB) and consumers, then you may "encrypt" (in the broad sense) the object id so that the encryption will be consumer-dependent. For example, in communication with consumer you can use the ID of the link (between object and consumer) entry in DB.
If sending IDs to consumers seems to be the bad idea for you because of the possibility of consumer enumerating all the IDs one-by-one, you can avoid this problem by using GUIDs instead of an integer auto-incremented IDs.
PS: As for your comment, consider using e.g. GUID as an object ID. The ID is the part of data, not the part of schema, so it will be preserved when migrating between databases. Such the ID won't contain sensitive information as well, so it is perfectly safe to reveal the ID to consumer (or someone else). If you want to prevent creation of two different persons with the same SSNs, just add an UNIQUE key on your SSN field, but do not use SSN as the part of ID, as such approach has many serious disadvantages, with inability to reveal the ID being the least of them.
From my point of view the id of a record does not convey any sensitive information to anyone.
As a result there is no problem transmitting database ids to front-end (and in general).
The only concern would be related to database consistency issues, but I can not see any.
Additionally from performance it is much better, since you don't need to query the database on attributes to find the database id.
Additionally if you send a hash of the id you can not extract the id from the hash.
You would have to find an id in the database that matches the hash and that is not good IMO
So:
we also see where propagating database ids to our consumers could be a
bad idea.
I don't see it. If you could explain why you think is a bad idea, may be there would be a discussion.

Resources