What's the best practis to hide primary key database in url? - web

Actually, i have this url http://mydomain.fr/user/1 in my web application. I think it is not very safe
I would hide the id which is auto_increment.
To not be able to do that:
http://mydomain.fr/user/1
http://mydomain.fr/user/2
http://mydomain.fr/user/3
http://mydomain.fr/user/4
http://mydomain.fr/user/[...]
I do not know which technique to use...
Hash MD5 stored beside primary key
UUID / GUID
I use MySQL.

You should restrict access to URLs based on authentication. Just making it 'hard to guess' an ID will not prevent someone from accessing another user's page or, e.g., deleting an unexpected user. Basically, anyone will be able to access any URL unless you provide some access control.

I think generate a random unique string for a user is the best way.
simply use sha1 hash should be ok.

There is no way properly to hide it, you can generate unique ID with a long random hashed string, it's harder to guest. Basically that won't prevent someone to access other's ID.

OP may be concerned with divulging the primary keys because it could leak information into how many of a certain resource exists.
For example, if he is building a web app and someone creates an account and sees a url of domain.fr/user/23 they will know they have created an account on an application with low adoption.
My suggestion would be to either use a GUID value as suggested above or a username that is constrained to be unique.
If you use a GUID, it will look ugly, but make sure to not just use the beginning part as you could greatly increase the chance of collision since the first 60 bits are based on the timestamp.
If you use a unique username, your url would instead look like domain.fr/user/username
I know this is easily done on RoR.

Related

How to pass a unique user ID to a page with user-specific, personal data

I'm sending a mass email though Emma (3rd party vendor) that will contain a link to a landing page. The landing page will be personalized and display some of the user's identifying info (name, title, email). Additionally, there will be a form collecting a few of the user's preferences that will be saved back to that user's record in Emma's database.
The user ID column in the 3rd party's database is incremental so I obviously can't just append that value through the query string otherwise user 522, for example, would get a link such as www.example.com?landing/?uid=522 allowing him (or anyone with the link)cto take a wild guess at other values for uid (such as 523... or 444) and change other users' preferences as well as view their personal data quite easily.
Bottom line is that I'm trying to find a secure way to pass an ID (or other unique value) that I can look up via API and use to dynamically display and then resubmit personal info/data on this landing page on a user-to-user basis.
I had an idea to add a custom column to my list in Emma for a unique identifier. I would then write a script (accessing Emma's API) to BASE64 Encode the ID (or possibly email address, as that would be unique as well) and add that to the list for each user. In my email, I could then pass that to the landing page in for the form of ?xy=ZGF2ZUBidWRvbmsuY29t, but I know this is encoding and not encrypting so not all that secure... or secure at all for that matter.
To my knowledge, there's no remote risk of anyone receiving the mailing having the ability and/or inclination to know what those extra characters in the link are, BASE64 Decode, BASE64 ENCODE another email address or integer an make a request with the newly BASE64 encoded value in order to manipulate my system in an an unintended way.
BUT for the purpose of this question, I'd like to know the "right" way to do this or what levels of security are currently being taken in similar circumstances. I've read about JWT tokens and some OOth stuff, but I'm not quite sure that's possible given that I've got the Emma API to deal with as well... and/or if that is overkill.
What is appropriate/standard for passing values to a page that are in turn used for a form to be resubmitted along with other user-supplied values when giving the user the ability to submit a "compromised" (intentionally or not) form could, at worst, could cause one of their competitors to have bad preference and opt-in saved data in our Emma mailing list?
Security on the web is all about "acceptable risk". You can reduce risk in various ways, but ultimately there's always some risk exposure you must be willing to accept.
Your very best option would be to force users to be logged-in to view the page, and to avoid using any querystring parameters. That way the backend for the page can pull the ID (or whatever it might need) out of the server's session.
Your next best option still involves forcing the user to be logged in, but leave the uid in the URL -- just be sure to validate that the user has access to the uid (i.e. don't let a user access another user's info).
If you can't do that... then you could create random keys/ids that you store in a database, and use those values (rather than uid or email or real data) in the URL. BUT let's be clear: this isn't secure, as it's technically possible to guess/deduce the scheme.
Absolutely DO NOT try passing the info in the URL as base64 encoded data, that's likely to be the first thing a hacker will figure out.
Keep in mind that any unsecured API that returns PII of any kind will be abused by automated tools... not just a user farting around with your form.
To my knowledge, there's no remote risk of anyone receiving the
mailing having the ability and/or inclination to know
^ That's always always always a bad assumption. Even if the result is at worst something you think is trivial, it opens the door for escalation attacks and literally exposes the company to risks it likely doesn't want to accept.
If you're stuck between bad options, my professional advice is to have a meeting where you record the minutes (either video, or in a document) and have someone with "authority" approve the approach you take.
In case anyone needs a working example, I found this at https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/. It uses PHP's openssl_encrypt and openssl_decrypt, and it seems to work perfectly for my purposes
<?php
$key = base64_encode(openssl_random_pseudo_bytes(32));
function my_encrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
I first ran my_encrypt in a loop to encrypt the uid of each member in the list.
$members[$uid] = array('unique-identifier' => my_encrypt($uid, $key));
Next, through the API, I modified each member's record with the new value.
$ret = update_members_batch($members);
That only had to be done once.
Now in my email, I can pass the uid through the query string like this www.example.com/landing/?UID=<% unique-identifier %>, which will look something like www.example.com/landing/?UID= XXXXX2ovR2xrVmorbjlMMklYd0RNSDNPMUp0dmVLNVBaZmd3TDYyTjBFMjRkejVHRjVkSEhEQmlYaXVIcGxVczo6Dm3HmE3IxGRO1HkLijQTNg==
And in my page, I'll decrypt the query string value and use it via the API to get the email address with something like:
$member_email = get_member(my_decrypt($_GET['UID']))['email'];
and display it in the appropriate location(s) on my page.
I think this covers all my bases, but I am going to have a stakeholder meeting to get sign-off. What potential vulnerabilities does this expose that I should warn them about?

Custom Password field on Employee Record

We have built an integration between Netsuite and our external system. We want to store the external system's credentials on the employee record but I'm having a really difficult time understanding how the password field type is supposed to work.
The documentation states "When validating, you pull the encrypted password value into a hidden field and use custom code to encrypt the value the user typed and compare it with the actual encrypted value."
But aside from this I don't feel like I have a solid idea on what the proper implementation should be.
So essentially I ended up doing what prasun did. One thing I did do what still create a password type field and add a client script on record save to encrypt the entered password and insert the value into another plain text field that was not displayed on the UI. This had the desired user experience to fulfill my requirements (showing the standard password field). From there, we just decrypted the encrypted field (the one we copied our password into and encrypted) during run time. So it's a little bit of a round about trip but it is working and in no place is the password being stored in plain text which was our desired goal!
or you can create a password fiels in plain text and can hide that field.The security level is low but still we can implement it with less effort.

Is there a way (LotusScript or Formula Language) to obtain a list of document secret encryption keys in the current ID?

I'd like to create a SecretEncryptionKeys dialog list field which prepopulates with the names of the available document keys in the current ID. Is there a way to do so? I cannot seem to find one in the documentation. (I can find #Command([UserIDEncryptionKeys]), but that just opens the Encryption dialog.)
This is a follow-on to Is it possible to programmatically tell Lotus Notes to generate a new secret key? , since I don't want the people who instantiate the new database to have to edit the forms involved to set the default encryption key. If they do, the next time the design on the database instance is refreshed from the template the settings will be overwritten.
The last time I checked in with IBM engineers about this, the answer was no. That was probably about 10 years ago, however I just took a quick look at the Notes 9 API Reference and I don't see anything there that would expose the list of keys, so I suspect that the answer is still no.

solution for: select input, dropdown tampering prevention

for hidden field tampering protection: Id, RowVersion, I use a version of Adam Tuliper AntiModelInjection.
I'm currently investigating a way to prevent tampering of valid options found in select lists/drop downs. Consider a multitenant shared database solution where fk isn't safe enough and options are dynamic filtered in cascading dropdowns.
In the old days of ASP.NET webforms, there was viewstate that added tampering prevention for free. How is select list tampering prevention accomplished in ajax era? Is there a general solution by comparing hashes rather than re-fetching option values from database and comparing manually?
Is ViewState relevant in ASP.NET MVC?
If you can, the single solution here is to filter by the current user ids permission to that data, and then those permissions are validated once again on the save.
If this isn't possible (and there are multiple ways server side to accomplish this via things like a CustomerId fk in your records, to adding to a temporary security cache on the server side, etc) , then a client side value can provide an additional option.
If a client side option is provided like was done with Web Forms, then consider encrypting based on their
a.) User id plus another key
b.) SessionId (session must be established ahead of time though or session ids can change per request until session is established by a value stored in the session object.
c.) Some other distinct value
HTTPS is extremely important here so these values aren't sniffed. In addition ideally you want to make them unique per page. That could be the second key in A above. Why? We don't want an attacker to figure out a way to create new records elsewhere in your web app and be able to figure out what the hashes or encrypted values are for 1,2,3,4,5,6,etc and create essentially a rainbow table of values to fake.
Leblanc, in my experience, client side validation has been used mostly for user convenience. Not having to POST, to only then find out that something is wrong.
Final validation needs to occurs in the server side, away from the ability to manipulate HTML. Common users will not go on to temper with select lists and drop downs. This is done by people trying to break your page or get illegal access to data. I guess my point is final security needs to exist in the server, instead of the client side.
I think a global solution could be created given a few assumptions. Before i build anything I'll like to propose an open solution to see if anyone can find flaws or potential problems.
Given all dropdowns retrieve their data remotely. - in an ajax era and with cascading boxes this is now more common. (We are using kendo dropdowns.)
public SelectList GetLocations(int dependantarg);
The SelectList will be returned back as json - but not before having newtonsoft serialization converter automatically inject: (done at global level)
EncryptedAndSigned property to the json. This property will contain a Serialized version of the full SelectList containing all valid values that is also encrypted.
EncryptedName property to the json. This property will have the controller actionname - For this example the EncryptedName value would be "GetLocations"
When the http post is made EncryptedName : EncryptedAndSigned must be sent in the post also. For this JSON POST example it would be:
{
Location_Id: 4,
GetLocations: 'EncryptedAndSigned value'
}
On the server side:
[ValidateOptionInjection("GetLocations","Location_Id")
public ActionResult Update(Case case)
{
//access case.Location_Id safety knowing that this was a valid option available to the user.
}

HTTP POST Vunerable to change?

I was wondering if anyone knows if the following scenario can happen.
Suppose I have dynamically generated a form that has check boxes for products specific to that customer. If the customer checks the boxes, the products will be deleted when form posted. The checkboxes are named after the productID.
Now my handler will check the response.form and parse the productID out, then delete the product from the database based on the productID.
Potentially could someone amend the post to allow other productIDs to be deleted, potentially everything in the product table by adding fake checkbox names to the POST?
If so, it would be easy to check prior to delete the productID is related to the authenticated user, and they have sufficient roles to delete, or to generate a nonce and label the checkboxes with that rather than their product ID, however I am not doing this at the moment. Any pointers to best practices for this would be good.
I have never considered this before, and wonder just how many people actually do this by default, or are there a million web sites out there vunerable?
Thanks
It is absolutely possible that someone could build a custom POST request with any key/value pairs (including product ID values) and submit it to your application. The fact that the checkboxes are not on the form that the POST is supposed to come from is irrelevant from a security perspective.
When thinking about web application security, the client is a completely untrusted entity. You have to assume that your JavaScript validation will be bypassed, your SELECT elements can be altered to contain any value an attacker wants, and so forth.
So yes, you should validate that the current user is authorized to delete any product ID submitted to this handler.
I'm not necessarily convinced that you need to go the nonce-obfuscation route. It is an additional layer of security, which is good, but if you are performing proper authorization I don't think it's necessary.
My $0.02
Yes this is a problem. What you are describing is an example of the "Insecure Direct Object References" risk as defined by the Open Web Application Security Project (OWASP).
As to how common it is, it currently (2011) ranks 4th in the OWASP's list of top 10 most severe web application security risks. Details of how to prevent this can be found on the OWASP page.
How Do I Prevent Insecure Direct Object References?
Preventing insecure direct object
references requires selecting an
approach for protecting each user
accessible object (e.g., object
number, filename):
Use per user or session indirect
object references. This prevents
attackers from directly targeting
unauthorized resources. For example,
instead of using the resource’s
database key, a drop down list of
six resources authorized for the
current user could use the numbers 1
to 6 to indicate which value the
user selected. The application has
to map the per-user indirect
reference back to the actual
database key on the server. OWASP’s
ESAPI includes both sequential and
random access reference maps that
developers can use to eliminate
direct object references.
Check access. Each use of a direct object reference from an
untrusted source must include an
access control check to ensure the
user is authorized for the requested
object.
Why not simply validate the values you get against the values you provided? Example: You have provided check boxes for items 1, 2 and 3, 9. The user posts 1, 2, 3, 4, 5, 6. You can find the intersection of the lists and delete that (in this case 1, 2, and 3 are in both lists).

Resources