https://security.stackexchange.com/questions/17259/better-techniques-than-url-parameter-encryption
Summary. Your primary defense should be access control. You need to limit which users can view which pages. Details below.
In short: Don't encrypt URL parameters, use a separate look-up.
https://paragonie.com/blog/2015/09/comprehensive-guide-url-parameter-encryption-in-php
Don't.
Cryptography is a tricky field, especially for newcomers. To a security expert, it's immediately obvious why encrypting URL parameters is a bad idea. Let me explain why, and then I'll offer a superior alternative solution.
Why Encrypting URL Parameters is a Bad Idea
Typically, the desired result of encrypting a URL looks like this:
One problem arises that, given the desired outcome of a very short URL (which is a common constraint to any system that sends URLs over SMS), there isn't enough room to both encrypt the desired information and then authenticate the encrypted output. Encryption without message authentication is totally broken.
Unless you're a cryptographer or security engineer, you wouldn't know these details. In this situation, encryption adds complexity and lots of room for nefarious errors to your application, for no real benefit. Obfuscation is a trivial task, as we'll demonstrate below; why add unnecessary complexity if you can avoid it?
What About Hashids?
From the What Not To Do section of the Hashids page:
Do not encode sensitive data. This includes sensitive integers, like numeric passwords or PIN numbers. This is not a true encryption algorithm.
The hashids protocol has been publicly broken by simple cryptanalysis techniques.
This might seem like an attractive solution, but it won't stop users from trivially teasing the underlying database row ID out of your obfuscated URL parameter. Hashids are not secure; don't use them.
What Should I Do Instead?
Okay, by this point, we hope you're convinced that neither encryption nor hashids are the way to go forward. Encryption is very hard to get right, and hashids are not secure.
But knowing this doesn't solve your problem: How can you serve content via an obfuscated URL without resorting to encryption?
The answer is: add another column to the table with a unique, random token and reference that in your database lookups instead of your database identifier.
A little bit of math:
- In MySQL, an
INTEGER(11) UNSIGNED
primary key can hold about 4 billion rows. This is equal to 32 bits. - If you generate 9 raw bytes from a cryptographically secure pseudorandom number generator (72 bits of possible values), then base64 the result, you will end up with a 12 character identifier.
- 72 bits of possible values means a 50% chance of collision at records, according to the birthday problem.
This means you have a 50% chance of only two duplicate random values after about 69 billion records (a far cry beyond your 4 billion storage capacity). This means that you will almost never have a collision. You should still make sure every selector you generate is unique before inserting a new one, of course.
Furthermore, this record is completely randomly generated and has nothing to do with the rest of the data stored in your database. There is no pattern to be found. (The closest relevant buzz-word here is a "zero knowledge".)
Instead of encrypting URL parameters, add a column that stores a random 12-character string for each row (which is generated by base64-encoding 9 bytes from a CSPRNG), and use that in your URLs and SELECT queries.
use ParagonIE\ConstantTime\Base64UrlSafe;
/**
* Generate a selector
*
* @return string (12 characters)
*/
function generateSelector(): string
{
return Base64UrlSafe::encode(random_bytes(9));
/* Equivalent:
return strtr(base64_encode(random_bytes(9)), '+/', '-_');
*/
}
(Code snippet above uses paragonie/constant_time_encoding.)
This problem is simpler and less likely to cause bugs or implementation errors now and going forward.
A Quick Note about Access Controls
An obfuscated URL does not obviate the need for access controls. The use case here is, "I want to serve a unique ID for a particular resource without leaking metadata about the activity level of our app."
Do not use obfuscated URLs as a backdoor into your application.
PHP hash ids
https://hashids.org/php/
No comments:
Post a Comment