7 ms·
Having seen this at too many companies, we at fair.com decided to adopt stronger policies to prevent this, viz: - all inbound API requests first go to our API
by ryan_j_naughton 9y ago
Having seen this at too many companies, we at fair.com decided to adopt stronger policies to prevent this, viz:
- all inbound API requests first go to our API proxy in the secure layer.
- the API proxy encrypts all PII using the encryption service in the secure layer
- then API proxy sends the request on to the appropriate service, having swapped all PII for tokens.
- all services in the general layer are not able to talk to the encryption service to decrypt data.
- thus all data that would normally be considered very sensitive (e.g. credit reports) can be stored or passed around the services because values like SSN and others are tokenized.
- our services with UI's like our CRM, wherein the customer service rep needs so see the data unencrypted, works perfectly bc the response from the API proxy outbound decrypts the data, but selectively so based on the person's permissions through our abstracted auth layer.
Thus in the Lyft example, the majority of employees could have access to "God view" but with all the PII encrypted (so they couldn't search their friend's account by email, for example) but they can still look at rides and transactions, while just those who need to see the decrypted PII could be given those permissions.
Of course, this assumes that the encrypted PII is sufficient for anonymization. If you can look for all rides within a block of an address in their God view, then you could quickly figure out which person was your friend by narrowing down to rides originating from his house and his work. But again that comes down to properly limiting certain search capabilities in the UI.
I don't get why more companies don't follow our approach. I've seen way too much personally sensitive data in plaintext in databases over the years.
- jjeaff 9y agoWhile I like that, and is a cool approach, what is really the difference between just storing PII encrypted in the same database and then keeping your keys locked down based on permission levels? The API proxy would be great if you have a trusted 3rd party in charge of it or something. But abstracting it out to a separate layer doesn't seem necessary since it's all within the same company anyway, and developers will need access anyway
- brisance 9y agoProbably due to granularity of permissions, key revocation etc reasons. Parent's method is analogous to a high school hall pass to access the restrooms; your proposal is to tell the janitor a "secret" password.
- ryan_j_naughton 9y agoThere is a big difference. - Logs: we can log all params within the general layer without worrying about leaking PII to the logs - Monitoring Network traffic. If I need to use wireshark or something similar in the general layer, all the data there is already encrypted/tokenized so it is safe to do so. - If you let each service encrypt the data itself, then all of those services are in scope from a security perspective. Access to those services from engineering's perspective would have to be considerably more locked down, potentially preventing engineers from access to their ENV variables, memory dumps, sshing into those boxes/containers, etc, for fear you could get the encryption keys (of course while many of those things should be locked down anyway). - Further, having each service do the encryption itself means you are duplicating that solution over and over again and introducing more opportunities for error. Having a single encryption service within the secure layer allows us to change our approach more cleaning than it being spread out everywhere. And the list goes on and on...
- marshallbrekka 9y agoIn addition to the points already raised by ryan_j_naughton, another consideration is how to perform key rotation and cipher upgrades over time. This is a lot more complex if every application is doing it on their own, but is quite easy if you centralize all (or most) crypto to a single service. See my reply to another comment: https://news.ycombinator.com/item?id=16236798 https://news.ycombinator.com/item?id=16236798
- kevin_nisbet 9y agoThis is a very intriguing approach. I'm curious about one aspect though, have you put much thought into what happens and the side effects of doing something like key rotation if you're encrypted service is potentially compromised / leaked. The second aspect I'm curious about, is you mention services in your general layer are not able to talk to the encryption service to decrypt data, but what about encrypting data? The reason I'm curious is the tricky part with anonymization, is I don't necessarily have to decrypt PII to unmask it. I don't really know what you're service does, but say it's tracking location, and one of the pieces of PII is phone number. If I can go to the encryption service and ask for the encrypted version of a phone number I know, I then have the encrypted phone number that I can use to search the dataset.
- marshallbrekka 9y agoI can elaborate on these points. The service acts more like a key value store (this is a simplified explanation, but for your questions it will do). You give it a value, it gives you back a token, which you can later exchange for the original value. This means the real value is stored in the encryption service, not in the receiving applications database. This gives us the flexibility to perform key rotation (and even upgrade our ciphers as the crypto landscape evolves) at any time without having to worry about where the the encrypted value is being used, as the only data stored outside the service are opaque tokens. As for de-anonymizing, the service is not designed to take an encrypted value and return its token. If that were possible, we wouldn't have done a very good job encrypting it ;)
- segmondy 9y agoFor de-anonymizing, the idea is to give the encrypted service the plain text and get a matching token. But then that will be more of a hash. If you are encrypting where all the tokens are different, you can't do a join or analysis. You can't for instance count how many unique phone numbers you have. If a user is using your app, how do they see their PI data?
- marshallbrekka 9y ago
- wyattjoh 9y agoAre you using something like Vault [0] for that? Always been interested in different approaches for this. [0]: https://www.vaultproject.io/ https://www.vaultproject.io/
- marshallbrekka 9y agoThe service is written in-house, but we do use Vault for things like provisioning temporary credentials.
- tzs 9y agoWhy in house? We did a similar thing for credit card storage. We did it in house because I failed to find any open source solution that I liked that would fit in with the rest of our stuff. Things in this space (free or commercial) seemed to have strong opinions about how the rest of your software should work. I received at one point permission to release our stuff as open source, but didn't have time to clean it up for outside release. I could probably get that permission renewed and find time to do it, but I'm not sure if it would be worth it, for a couple reasons. 1. Once upon a time I got totally fed up with the idiocy and complexity that is SOAP and the way I kept running into subtle incompatibilities between SOAP servers and SOAP clients when the clients were provided by different vendors than the servers and were in different languages. I yelled "SCREW SOAP!" and hacked out that weekend something I called RADIO (named after the old joke [1]). RADIO lets you write a service in Perl with some annotations in comments that describe the services provided. You then run that through the RADIO generator, and it spits out a Perl CGI that implements the service, and client modules for it in Perl, PHP, and Python. The Perl CGI also provides a human usable interface on the web that gives you a form-based interface that provides documentation for each API call and lets you invoke them from a browser. I used RADIO to implement the credit card storage service. I'm not sure many people would be interested in running a Perl service implemented using a weird sort of framework sort of code generator. 2. How it uses cryptography (choice of cipher, mode, padding, and such) has not been reviewed by a cryptographer. I know enough to not implement my own cryptographic primitives, of course, and so used well-known implementations from CPAN. However, I still had to make choices about HOW to use those, and those choices have not been checked by an expert. [1] Two polar bears are sitting in a bathtub. The first one says, "Pass the soap." The second one says, "No soap, radio!" https://en.wikipedia.org/wiki/No_soap_radio https://en.wikipedia.org/wiki/No_soap_radio
- jacquesm 9y agoI sincerely hope that your approach becomes common enough that I will see it implemented in practice. Right now it is rather the opposite, plain text data flying around everywhere and at rest in test databases and backups is the norm. And if you are really unlucky you will find it on the laptops of developers in the form of a two week old copy of main database. And if you are even more unlucky that developer does not have his hard drive encrypted and takes the bus every day to work. And already lost another laptop, just like that one, only nothing ever came of it so the data is most likely still safe.
- crdb 9y agoA database would already provide a layer of security (most people, including many "professionals", would not know what to do with it). Customer data is often stored in a large, denormalised table in an Excel file called "customers" which contains the entire set of customers past and present, including those who unsubscribed or have not ordered for years, with all attributes (phone, address, etc.). There is also no oversight on who has access to this file, since "marketing needs it for Facebook" or "customer service needs it for returns" or whatever the excuse du jour is. Even the newly hired intern with a stronger than usual interest in every system's credentials gets a copy. You get some measure of security when there are more than one million customers and they need to start partitioning. The most secure setup I've seen was a company whose entire repairs department ran on paper slips. Since nobody had the time or inclination to enter the information somewhere digital, no internal staff knew how to find customer information, even if they walked to the shop floor. I think a couple of old timers knew how to navigate the pile of slips and were the de facto DBMS engine.
- anigbrowl 9y agoTechnical solutions are great, but ultimately this is a human problem. Not every firm has the resources or know-how to do all that, but any firm can have a clear policy of termination and lawsuits for anyone found abusing access to customer data.
- rmc 9y ago> Not every firm has the resources or know-how to do all that The upcoming EU Data Protection law (GDPR) has fines for data protection breeches. It can be up €20 million or 4% of global revenue. And NGOs can sue you on behalf of affected people. When there's a price tag on non-compliance, suddenly it becomes easier to justify allocating resources to doing it (or paying someone else to tell you how to do it).
- tallanvor 9y agoBut it is both a technical and human problem. Obviously a company should have policies against the abuse of data - and I'm sure almost all of them do. But you need a technical solution to be able to determine when people have accessed information they shouldn't have, otherwise the policy is worthless because you won't know that the abuse has happened until it blows up in your face. So, since you already need a solution to be able to audit activities, adding controls to help cut down on the number of people who are able to abuse the data reduces your potential liability immensely.
- Natsu 9y agoWhat do you use as the API Proxy?
- marshallbrekka 9y agoIt's a custom Go application that proxies rest/json based APIs, as well as gRPC/Protobuf.
- misterbowfinger 9y agoWould you consider open sourcing it? It seems quite interesting and valuable
- marshallbrekka 9y agoIt's so specific to our architecture that there would be little value in open sourcing it. That being said, there are some lessons we learned along the way that I do think are worth sharing. As I mentioned above the API proxy supports REST and gRPC API calls. For REST based APIs, we developed a YAML syntax for declaratively specifying (per route) the input/output keys that needed to be encrypted/decrypted. This is accomplished using a JsonPath like syntax, along with attributes for each key that specified the type of data, as well as letting us perform limited validation on the data. However this approach provided little visibility into what fields are not being encrypted, leaving room for mistakes. This is where gRPC/Protobufs come in to play, it's the newest addition at the API Proxy level, but is not new to our internal architecture. Using protocol buffers as our IDL has been a huge help in terms of our data auditing capabilities. Unlike our YAML based solution before, with protobufs we can see every single field that is expected as an input or output of an API call. We've utilized this feature by creating wrapper message types that indicate when a field contains data that needs to be encrypted/decrypted, and have helper libraries that can traverse an instantiated protobuf message, perform the encrypt/decrypt operation, and swap out the original value(s) for the one(s) returned from the encryption service. Once we have the library to perform the traversal and the compiled protobufs, integrating it into the API Proxy (along with grpc-gateway to translate to REST/Json) is actually pretty straight forward.
- closeparen 9y agoIsn’t it pretty standard practice to confine (overt, obvious) PII to the users table/user CRUD service, so that the rest of the infrastructure only speaks in user IDs?
- ryan_j_naughton 9y agoNot if you have credit reports and other data that could contain PII as well. You don't want the name or address in the credit report to just point to your user's table, with an assumption that that was the name in the report. And if you don't know with certainty that the credit report pulled was for that person (there are collisions, mismatches, etc), then you want to store that data as associated to the report and not the user (which the report is then associated to the user). For proper data integrity and data provenance, you want to know what you knew at each point in time. Thus, simply pointing to a user_id and hoping the data on the user's table was the data at some point in time in the past will result in leakage for data science (https://www.kaggle.com/wiki/Leakage https://www.kaggle.com/wiki/Leakage).
- closeparen 9y ago>You don't want the name or address in the credit report to just point to your user's table, with an assumption that that was the name in the report Well ok. In your example, call it a "credit report subjects" table. >Thus, simply pointing to a user_id and hoping the data on the user's table was the data at some point in time in the past References can be versioned or even hashed, i.e. Git. You would run the same risk with tokens, no?
- schwabacher 9y agoThe tricky part about this sounds like it would be specifying in the proxy service which parts of structured requests are responses are PII - how do you handle this?
- marshallbrekka 9y agoIn short, our REST based APIs are done via a YAML syntax, but our newer APIs are through Protocol Buffers. See my other comment for more details https://news.ycombinator.com/item?id=16237349 https://news.ycombinator.com/item?id=16237349
- iovrthoughtthis 9y agoI've always wanted to do this but couldn't justify the time as my business partner didn't value user privacy as much. It would have made GDPR compliance waaaay easier. Could you write it up as a blog post? I would love to know more.
- marshallbrekka 9y agohttps://news.ycombinator.com/item?id=16236798 https://news.ycombinator.com/item?id=16236798 https://news.ycombinator.com/item?id=16237349 https://news.ycombinator.com/item?id=16237349
- maze-le 9y agoThis list should be made a 'Best Practices' document. Good Work!
- cornholio 9y agoThe key problem with both Lyft and Uber is that employees who had the right to view the data abused the privileges. While encryption can help to enforce the privileges against technically capable employees, the main problem is the privilege system itself, or lack thereof. 95% of the abuse would be eliminated with no encryption, just proper design of the internal interfaces and queries talking to the plain text database. And many employees really do need elevated access for their work. It's then imperative to create a privacy focused internal culture where it's clear that abuses result in termination and civil/criminal actions, and put in place strict access logging and enforce these policies.
- zaroth 9y agoAgree completely. Encryption or tokenization is great but a much easier first step which covers the first order problem of employees abusing access privileges is simply a secure audit trail and someone to actually look at the logs and discipline or terminate employees who misuse their access. There are probably innumerable reasons to have access to a particular ride’s exact route, or a particular users ride history, or feedback history, etc. Just like the police have many perfectly valid reasons to run a plate. Audit logging and request throttling are the low hanging fruit. If your system can tie each request to the service ticket which prompted it, even better.
- datr 9y agoWe considered doing something like this on a project once but we had concerns about performance. How much latency does your API proxy add in for responses with thousands of tokens? Additionally we found that this broke any sort of database indexing. Let's presume that Lyft would need to tokenize the start and end points of journeys (otherwise it would be quite easy to de-anonymise someone) then just doing simple queries like I want to know how many journeys happen in this area either become incredibly slow or you have to have anticipated needing this type of query and providing a non-tokenized "area" field which can be indexed (but is sufficiently coarse not to leak data). Were you able to come up with any sort of solution for this issue?
- DerBesserWisser 9y agoIMHO the problem is not encryption but to wide access rights ("Marketing needs access") and bulk access ("get me all customer data").
- hoorayimhelping 9y ago>I don't get why more companies don't follow our approach. How much latency does this process add to the rendering of a web page? How many people did it take to design, implement and now maintain?
- marshallbrekka 9y agoFor an API call that requires decrypting data it can add about 5-10ms, most of that comes from reading the values from the token database. Encrypting will incur a similar performance penalty (again from the database). The core pieces (API Proxy, Encryption Service, secure/general infrastructure divide) we're done by me in the first 2-4 months. We now have a team of three (myself included) who maintain those systems (among many other responsibilities).
- bowbles 9y agoProductive this and sell it at a low cost if it’s that simple. I’d love to use something like this but building it from scratch in house is cost prohibitive.
- Cthulhu_ 9y agoFor a system like Lyft, I think you'd want all rides to be anonymized by the user's app, so that in case the user contacts support, they can if need be give permission (and send the key) for support to review a single ride. Something like that. A bit more tricky for drivers though, due to billing and tracking and such.
- daenney 9y agoWould you please consider open sourcing some of this? If not the code then perhaps a more comprehensive design doc, explaining the different components involved, some API samples and flows so people that want to can recreate this?
- dboreham 9y agoTo add to this (which is excellent btw), we have taken the following measures: Rate-limiting on admin interfaces and APIs (so a "rogue" human with admin rights can't just suck out PII in bulk). Access controls on sensitive data and dangerous operations (such as account deletion) that allow these things to be limited to a small number of admin staff. Ability to mark specific accounts (e.g. celebrities, senior management) as inaccessible by admins, overridable only by special privileges that require sign off. Regular audit of log files and raw database content to verify that no PII is leaking into uncontrolled areas. There are probably other measures I can't remember but the basic idea is to throw sand in the face of a potential internal attacker while still allowing legitimate activities to be carried out. In a larger organization you might be able to use ML to detect anomalous admin activity. Update : I remembered another thing -- don't collect sensitive data that you don't need. I've had several discussions over the years along the lines of "we found that we can get xxx (PII field of some sort , e.g. the user's cell phone number even if they didn't know they gave it to us), where should we store that?". Answer : don't.
- afpx 9y agoThe biggest issue is that consumers don’t read privacy policies or user agreements. If a company gets a user to waive their privacy, their data can and will be traded on the secondary market. It’s just simple economics. I think most people who reside in the US would be shocked if they knew how much PII is traded about them. Very few people these days don’t have a personal record. Knowing what’s out there, I wish I lived in the EU.