Why do we still write insecure software?
jerf.org
jerf.org
This is fantastic.
If you've got a deadline in thirty minutes, you're probably not going to try and do everything the best possible way. Same deal if you've got a family or friends to get back to, an event to go or anything else that requires you to get things done quickly.
You're rewarded more for getting things done quickly than you are getting them done properly or securely. When your client wants their site or program done as quickly as possible for a low cost, or your startup needs to 'move fast and break things'... security will usually suffer in the process.
That's what I call the 'happy path fallacy'. If code performs along the happy path, then great, move fast, break things and release. Never mind that outside the happy path there are tons of issues, bugs, things never even looked at until they suddenly are found to be the root cause of a major breach. Those parts do not get the attention they need because there is no direct economic incentive to do so.
Software is not at all done when it 'works'. It's only done when it works well for all input and there are no unknown paths of execution that lead to unexpected results. It's pretty rare for a codebase with more than a few 100 lines to be completely known to such a level that there isn't a way to cause it to do something the author did not intend to be there. Complexity is a very bad enemy in that respect and code tends to get extremely complex and hard to reason about if you don't have iron discipline during the design process.
Yet if anyone added up the manhours it took to fix the same production issues that repeatedly popped up, it would've clearly been less expensive to fix the recurring bugs.
If you write code fast because you have a life at home to get to, and I write code fast because my employer needs it right now, and someone else writes code fast because they have a large ego to maintain, what really is the difference? If the simplest thing to do is also reasonably secure then the hope is a 30 minute deadline will not lead to an accidental security flaw.
Once all your queries are safe by default, your languages have memory safety, your templates XSS-encode by default etc etc (this is basically the situation at most sane workplaces) - there are still security issues.
There are fewer security issues left, but they're gnarlier. What we see now are "application logic" and business logic issues. Overflow and language-level sharp edges exist, but these are a small proportion of the mistakes developers (in particular, web application) seem to be making.
Situations where the server unintentionally signs user-controlled data, bad OAuth2 flows, missing or incorrect authorisation checks, accepting data from the client as "validated" - these are much more common in my experience.
The other interesting thing I've noticed is that when developers who are used to "safe by default" frameworks have to step outside the framework for any reason (e.g. front-end is 90% angular, but 10% "bespoke" JS) they will make mistakes with very high likelihood.
The solution is tooling yes, but also education and process.
How else will you be guaranteed to catch Goto Fail and similar?
What's worse is when you hit the issue of "composability" in cryptography - two servers run different algorithms making different assumptions, and when they interact the assumptions fail to translate and neither provide the guarantee they should. Like cross-protocol attacks, such as when one server becomes a signing oracle for another.
Edit: and beyond that, we have cross architecture disagreement on results of calculations intended to be deterministic. Like how SPARC Bitcoin Qt binaries previously would have had the Bitcoin reward schedule loop every 255 years and go back to 50 coins per block and restarting the countdown.
There are tools and methods to address the "first world problems" of application logic vulnerabilities too. Maybe in another 20 years those are at the forefront.
Obligatory XKCD: https://xkcd.com/927/
And 'obligatory xkcd's rarely are and I wished people would stop posting them as a way to settle an argument without being receptive to the core idea of that argument.
The word 'standard' never was on my mind, merely a way to get things implemented properly once rather than re-implemented over and over again.
How many HTML server components are there, in C alone? Then all the java ones, the ruby ones, the Go ones and all the other languages. Then all the crypto libraries and all their re-implementations and so on.
There has to be a better way to do code re-use and to avoid the NIH syndrome that seems to be one of the major generators behind all these re-implementations of roughly the same thing.
But it's so much easier to start again, rather than to delve into an existing code base, extend it properly and document it. There is little glory in a minor contribution to a much larger project. Starting over means it's your project, you get to be the big wheel and when you lose interest we have one more Swiss cheese to contend with.
The XKCD puts it perfectly... you create a better way - and God knows, there has to be many better ways than say JavaScript or PHP - how are you going to MAKE people switch?
Your better way - assuming it is perfect - is still crowded out and unable to gain any traction.
I mean... ANYTHING that gets made gets a "format war". What makes you think Google, IBM, Microsoft, Apple, etc would all agree on something long enough to make that happen? We can't even get a new DVD format without years of fighting...
What's perfect for Google (which revolves around Search) won't necessarily work for Microsoft (Which revolves around Server and Office)... Or Apple (Which revolves around... Magic?)... Or...
What language should they all agree on? What "bullet proof" product will meet all their needs? What style of programming does everything everyone needs?
You can't create that "perfect" solution, because people and companies that have such a massively different wants, needs and goals...
That's why things such as TDD, Modular code, Code reviews, etc all matter so much more than the specific platform you are on...
[1] http://evolution.berkeley.edu/evolibrary/article/agriculture...
So for entirely new bugs your objection stands, they could (and likely would) be disastrous. Even today a 'zero day' exploit for a major platform can be dealt with though, I don't see why we would not be able to deal with such exploits in a scenario where there is only one implementation of something, it's not as if right now we use the other implementations to keep things running, it's mostly a matter of impact all at once rather than spread out over time and infinitely repeating.
But they can only be dealt with once they're discovered by people with an incentive to fix it. The NSA says they weren't using Heartbleed[1], but I can't think of a single reason they wouldn't lie about it. In any case, that was a massive security flaw that could have conceivably been exploited for more than a decade. If it affects 30 percent of systems instead of 90 percent, that seems like worthwhile hedging of bets.
Bulletproofing, either in the literal or the metaphorical sense, is a series of tradeoffs and compromises. The idea that there's one right set of compromises for every HTTP server out there, not just in terms of safety but in a myriad of design decisions, is simply wrong.
is just one possible answer. Signed integer overflow depends on signed integer representation in go (it's undefined for unsigned integers in C):
https://golang.org/ref/spec#Integer_overflow
So the SafeAddInt8 in the blogpost may not be correct on architectures that use really strange representations.
Lots of C developers that wanted to make their code safer ran into a related trap in C. There it's totally undefined and the compiler may just throw the check out all together.
I wonder why Go doesn't just define signed integers to be in 2's complement representation. Are there any architectures out there that use something else for integers?
No, unsigned integer overflow is defined to wrap around in C. Only signed integer overflow is undefined.
> I wonder why Go doesn't just define signed integers to be in 2's complement representation
It does: "The value of an n-bit integer is n bits wide and represented using two's complement arithmetic" (from https://golang.org/ref/spec#Numeric_types)
I wonder what they mean with representation in the spec then?
Also, under Linux, when INTO fires, it is interpreted as a SIGSEGV. Not what I was expecting.
The problem with handling integer overflow is that the mechanisms for it are clunky. Is there a programming language that handles integer overflow using a better mechanism than those listed? (I mean without resorting to a BigNum.)