Hiding sensitive data in URIs
it seems there is one prime contender for the solution, which is to encrypt parts of the URI or all of it. Hashing does not seem to be an option since the data is highly predictable and calculating the entire set of values is easy. Encrypting the entire URI will limit a lot of the advantages of the approach. Symmetric encryption requires distributing a secret key widely and therefore defeats the purpose. The option that seems the best is to encrypt on the sensitive data with a public key.
Your logic is sound.
I know of one product that does exactly as you suggest; sensitive data is encrypted in the end-users browser by Javascript code, and an HTTPS GET request is made in which some of the 'key=value' parameter pairs have a public key encrypted, base64 encoded string.
The advantage is that these requests can be passed across networks with multiple TLS endpoints without the sensitive data being subject to decryption, and any web server logs or proxies in the middle won't have access to the sensitive data.
Does this approach seem valid and/or is there anything else I am missing?
It is valid, but here are the things you don't want to miss:
- You need to have a client with enough intelligence to perform the encryption for you. That means Javascript, or a custom app, or something.
- Don't roll your own crypto. Use a solid, reputable library and get a code review of your app.
- Key management. You need to generate keys, publish keys, rotate keys, and retire keys... and you need to do it carefully, because to do it right means to balance between losing control of the data and losing access to the data.
Would it be valid to use the same key-pair that would be used for TLS?
I would recommend against it. Aside from the general rule-of-thumb of "don't overload cryptosystems," there are some situations where that key isn't "trusted". One that I've run into is that DDoS mitigation services often like to have a copy of your web certificates and keys if they're fronting your traffic during an attack.
There probably needs to be some other information in the encrypted portion to avoid replay attacks
That depends; if the REST transaction you're working with is idempotent, then it's not that important. If it does change something, then yes, replay protection is more important.
or mapping an encrypted value back to given key, correct?
Yes, it's not absolutely necessary - depending on how many keys you use and how long their OUP and RUP tail is - but it's much easier not to have to guess which key :)
I was reminded of this because it came up as a "popular question." Since I asked this I have learned that the OWASP recommendation is to use request headers:
- In POST/PUT requests sensitive data should be transferred in the request body or request headers
- In GET requests sensitive data should be transferred in an HTTP Header
While this makes the API somewhat more difficult to use, there is support for this approach in at least some common frameworks.
Does this approach seem valid and/or is there anything else I am missing?
Your approach is valid, however; I wouldn't dismiss using a preshared symmetric key for the following reasons.
- Asymmetric is far slower to decrypt than symmetric. If the service has to decrypt multiple values from your URI performance could be impacted.
- The attack vector for this encryption is limited. TLS should be protecting this data in most cases.
- Different consumers can be given different pre-shared keys for added security (addressing your concern with widely shared symmetric). This also allows for more flexibility with key rotation.
- Asymmetric encryption will result in a large encrypted text. If your URI + querystring are long enough it could possible cause a 414 (Request-URI Too Long)
Would it be valid to use the same key-pair that would be used for TLS?
In theory you shouldn't because if an attacker obtained your key-pair they could decrypt both your TLS connections & your encrypted headers.
... Now from a realistic/support standpoint, if your TLS key-pair is obtained that's a doomsday scenario. Having a second keypair would not prevent a "full breach" event since you'd likely have sensitive data in the headers/body that could be decrypted.
I think you need to carefully weigh the options for your specific business need.