Sorry to burst that bubble, but KISS doesn't produce neither secure nor reliable software. Security and reliability is something you have to design for.
These types of guides always overlook the most important principle of software security:
Always avoid reading, storing, or interacting with secure, personal, or otherwise "interesting" data. As much as possible, strip this information from your application, so that when it gets pwned the blast radius is absolutely miniscule.
Unless the point of your software is to collect and manipulate this data. Like Facebook (in one sense); or like electronic medical record-keeping software (in a very different sense); or... like most free-without-microtransactions casual mobile games today, that are "free" because they make all their money on selling audience analytics.
While this is great advice in principle, in practice it substantially complicates development. We need far better and more accessible end-to-end encryption tools if we want developers to start doing this by default in non-security critical use cases.
No it doesn't. It just requires a shift in your thinking.
Having a database is a code smell.
If you absolutely have to have a database, then having a `users` table (or equivalent) is a code smell.
If you absolutely have to have a `users` table, having any columns in it other than `id`, `username`, and `password_hash` is a code smell.
...and so on.
Admittedly this isn't necessarily easy in a company setting. It's in direct conflict with what the sales & marketing people want, and unfortunately that means your job is sometimes to fight with the sales & marketing team. But it's not complicated.
It's not actually a reasonable goal. Almost all pieces of software will need some nontrivial amount of data to fulfill their purpose.
I am convinced, however, that it is a very useful heuristic. The platonic ideal of a perfectly secure database is a completely empty one. Every step away from that requires individual justification. That doesn't mean your database will be small, but it should mean the database is as small as possible.
I treat permanently storing user data (any data, for any reason) as my solution of last resort. That doesn't mean I don't use it. It just means I have to convince myself I don't have any better ideas before I do.
So where do you store this data then? Or do you just live with forgetting everything about a user (their name, details, history) every time they switch devices?
First I try really hard to not need it. e.g. I'm "vec" on HN. They don't know my real name, my physical address, or my Twitter handle. Any features that did need that data are simply not going to be implemented, and the site is designed accordingly.
Next, I don't store what I cam fetch or derive. Say I'm using GitHub as an oauth provider. I don't need to store an email, an avatar, or a password hash. I can use GitHub's data. All I have to store is an opaque oauth ID.
Finally, if I do really need it and I can't get it from anywhere else then I'll happily store it. I just won't do it first, and I often won't do it until I've had a talk with the designers about what's possible with the data we already have.
I work in a SAAS company whose product is used by businesses to exchange data and run reports, which are emailed. What exactly should we cut without destroying the utility of our work?
* Build your software to stream data directly from Client A's API to Client B's API without it ever being at rest on a machine you control.
* If your users want reports based off their data, then see if you can fetch the relevant data from the client on demand, build the report email in memory, then forget the raw data.
* Tell your clients you prefer to use their oauth provider of choice to authorize instead of storing usernames and password hashes yourself.
* Key your access logs off of an (arbitrary and short lived) session id instead of a user id.
Maybe none of that's appropriate for your use case. Maybe your company already stores the minimum viable dataset for its needs, and maybe that minimum viable dataset is still huge. But the fact remains that you can't leak what you don't have, and even marginal differences can still make the data you do hold a little less valuable to thieves and a little harder to deanonymize and collate with other leaks.
I use the term "code smell" in the same sense sense as "`if` statements are a code smell". It doesn't mean never to use them, it just means that solutions that don't use them tend to be consistently better than solutions that do. Solutions that store less (or no) data tend to be consistently more secure than solutions that do store more data. That doesn't mean those solutions always exist, just that one should prefer them when they do.
IMHO I think that's only sort of true. I would also like to add something:
If you can, move the computation to the data and never take possession of it _or any equivalent_ such as _a credential that allows perpetual access to the data_.
A lot of the time, while it may complicate the conceptual part of development, it doesn't really complicate the implementation too terribly much and it also forces a kind of sane layering.
That said, we should really embrace the idea that it doesn't matter if it complicates development. Start with that premise and back off if and only if you cannot accomplish your goals.
The "or equivalent" thing is very important and does not get enough attention. I was evaluating a solution (a competitor) at one point that as part of installation required, and cached, an (active directory) domain administrator account name and password (obviously in reversible form). That's just crazy. It's begging for the product to be at the center of a complete compromise of the administrative systems of the customer.
I have had clients even in recent (<5yr) history that stored all their credit-card details unencrypted in the database - including CVV.
One client had a single table with all CC info including name, address and postal/zip code.
One client didn't save it in their database, but had development logs enabled in production, saving all CC details to their logs for every transaction. We discovered they were enabled for more than a year.
To the best of my knowledge, they have fixed these issues. Regardless I have seen such similar patterns often enough to know it's not an uncommon practice in spite of PCI requirements to the contrary.
Not trusting user input is a good start, but the client shouldn't be trusted, either.
I have seen plenty of web apps that fell short on this...
Whenever I'm on a web app that has a button shown but disabled, you can be pretty sure that I will enable that button and click it...
If the client is limiting the maximum length of the contents of a textbox, I'm probably going to change that and see if the server is performing the same validation...
My favorite so far, though, was client-side calculation and validation of order amounts for some products. Intercepting the JavaScript file and tweaking it before the browser started using it allowed me to place an older for a bunch of products for only $0.01 (going negative was also attempted, too, but this particular system did a pre-approval with a payment gateway and it didn't like that... so I settled on a penny).
These were all things I've done with permission, of course... but it's amazing what you can do when people assume the browser will always follow the rules...
At my last job the HR guy installed this super annoying Slack bot that would spam everyone every week with a "happiness survey". I got so tired of it I eventually logged the requests my survey made and used curl to replay one with a happiness score of -100 (usually the value would be between 0 and 10). Response said "success".
Turned out the backend happily took that value and it skewed our average a lot and the next week I was laughing my ass off while HR was trying to figure out why everyone was suddenly so unhappy.
My favourite too was being new into a development job and buying our biggest package for a penny. What I hadn't counted on was that this was a fairly new system and the CEO was still copied in to every buy order.
Thankfully the company took it in good spirit, I was even sent an expenses form to reclaim the penny! :)
Same for performance or space optimization. Always measure. I'm working on embedded systems where performance and sometimes size matters. I know so many senior engineers that "optimize" a lot of things without measuring, it's insane.
Presumably, if you don't want to store some state on the server for a client, you can go stateless and store it only on the client but with MAC, so you can authenticate it. For example for session cookies.
They're implying that you are storing state in the client which sends that state back to your system in subsequent requests, e.g. an HTTP cookie. If doing so, make sure to use a MAC [0] to tell if the client has tampered with the state you stored.
This security list is only a partial list, and it's not realistic for a busy programmer to cover everything well.
On the other hand, visual tools(low-code/no-code), sold in cloud based models(and probably grabbing a lot of money), are backed by teams of experts who do security well and don't expect the user to do any of it.
And as for tools take 100% of the security burden from the hands of the programmer - i haven't seen any.
So my conclusion is: where security will matter - visual tools will dominate.
36 comments
[ 4.0 ms ] story [ 60.3 ms ] threadisn't crossdomain.xml an adobe flash thing?
Just for curiosity, you can check twitter's [2]
[1]: http://www.adobe.com/devnet/adobe-media-server/articles/cros... [2]: https://twitter.com/crossdomain.xml
Seriously, keep it EFFING SIMPLE. The more complex and involved it is the more things can and will break.
Does no one follow that anymore?
Always avoid reading, storing, or interacting with secure, personal, or otherwise "interesting" data. As much as possible, strip this information from your application, so that when it gets pwned the blast radius is absolutely miniscule.
Create software not liabilities.
Having a database is a code smell.
If you absolutely have to have a database, then having a `users` table (or equivalent) is a code smell.
If you absolutely have to have a `users` table, having any columns in it other than `id`, `username`, and `password_hash` is a code smell.
...and so on.
Admittedly this isn't necessarily easy in a company setting. It's in direct conflict with what the sales & marketing people want, and unfortunately that means your job is sometimes to fight with the sales & marketing team. But it's not complicated.
I am convinced, however, that it is a very useful heuristic. The platonic ideal of a perfectly secure database is a completely empty one. Every step away from that requires individual justification. That doesn't mean your database will be small, but it should mean the database is as small as possible.
I treat permanently storing user data (any data, for any reason) as my solution of last resort. That doesn't mean I don't use it. It just means I have to convince myself I don't have any better ideas before I do.
Next, I don't store what I cam fetch or derive. Say I'm using GitHub as an oauth provider. I don't need to store an email, an avatar, or a password hash. I can use GitHub's data. All I have to store is an opaque oauth ID.
Finally, if I do really need it and I can't get it from anywhere else then I'll happily store it. I just won't do it first, and I often won't do it until I've had a talk with the designers about what's possible with the data we already have.
I use the term "code smell" in the same sense sense as "`if` statements are a code smell". It doesn't mean never to use them, it just means that solutions that don't use them tend to be consistently better than solutions that do. Solutions that store less (or no) data tend to be consistently more secure than solutions that do store more data. That doesn't mean those solutions always exist, just that one should prefer them when they do.
If you can, move the computation to the data and never take possession of it _or any equivalent_ such as _a credential that allows perpetual access to the data_.
A lot of the time, while it may complicate the conceptual part of development, it doesn't really complicate the implementation too terribly much and it also forces a kind of sane layering.
That said, we should really embrace the idea that it doesn't matter if it complicates development. Start with that premise and back off if and only if you cannot accomplish your goals.
The "or equivalent" thing is very important and does not get enough attention. I was evaluating a solution (a competitor) at one point that as part of installation required, and cached, an (active directory) domain administrator account name and password (obviously in reversible form). That's just crazy. It's begging for the product to be at the center of a complete compromise of the administrative systems of the customer.
i know you just stored all of that somewhere, CVV included.
I have had clients even in recent (<5yr) history that stored all their credit-card details unencrypted in the database - including CVV.
One client had a single table with all CC info including name, address and postal/zip code.
One client didn't save it in their database, but had development logs enabled in production, saving all CC details to their logs for every transaction. We discovered they were enabled for more than a year.
To the best of my knowledge, they have fixed these issues. Regardless I have seen such similar patterns often enough to know it's not an uncommon practice in spite of PCI requirements to the contrary.
I have seen plenty of web apps that fell short on this...
Whenever I'm on a web app that has a button shown but disabled, you can be pretty sure that I will enable that button and click it...
If the client is limiting the maximum length of the contents of a textbox, I'm probably going to change that and see if the server is performing the same validation...
My favorite so far, though, was client-side calculation and validation of order amounts for some products. Intercepting the JavaScript file and tweaking it before the browser started using it allowed me to place an older for a bunch of products for only $0.01 (going negative was also attempted, too, but this particular system did a pre-approval with a payment gateway and it didn't like that... so I settled on a penny).
These were all things I've done with permission, of course... but it's amazing what you can do when people assume the browser will always follow the rules...
Turned out the backend happily took that value and it skewed our average a lot and the next week I was laughing my ass off while HR was trying to figure out why everyone was suddenly so unhappy.
That's in there:
"Validation must occur on the receiving side of communications. Validation on the sending side is a user experience decision."
Validate everything. Re-check authorisation always.
My favourite too was being new into a development job and buying our biggest package for a penny. What I hadn't counted on was that this was a fairly new system and the CEO was still copied in to every buy order.
Thankfully the company took it in good spirit, I was even sent an expenses form to reclaim the penny! :)
Just don't assume, please. Golden rule.
> If a stateless architecture being used, use a MAC or an authenticated encryption mode to authenticate input.
I ask as a developer of a SaaS product. I understood most of the tips but not this one.
[0] https://en.wikipedia.org/wiki/Message_authentication_code
On the other hand, visual tools(low-code/no-code), sold in cloud based models(and probably grabbing a lot of money), are backed by teams of experts who do security well and don't expect the user to do any of it.
And as for tools take 100% of the security burden from the hands of the programmer - i haven't seen any.
So my conclusion is: where security will matter - visual tools will dominate.