440 karma · joined May 26, 2010
http://twitter.com/ashearer
http://ashearer.com/
Calling it "sanitization" implies that the data is somehow dirty, so naturally it should be cleaned as soon as possible, and after that it's safe. But all that accomplishes in general is corrupting the data, often in an unrecoverable way, and then opening up security vulnerabilities because the specific use doesn't happen to exactly match the sanitization done in advance.
It's great to validate the data on input and make it conform to the correct domain of values, but conflating this with output formats and expecting this to take care of downstream security as well just leads to incorrect data along with security vulnerabilities.
PHP's long-ago-removed magic quotes feature was an example of this confusion in action. It not only mangled incoming strings containing single quotes in an effort to prevent SQL injection, but did so in a way that left some databases completely exposed, depending on their quoting syntax.
If good uses were common—and I'm struggling to come up with them—AWS could suppress the alert for IAM users that were already sufficiently locked down. But since that would become dangerous if the permissions were loosened later, AWS would wind up creating two classes of keys, public and non-public, in order to know whether to warn about loosening restrictions. Simpler just to forbid making keys public.
To publish such a key anyway without having to go to the trouble of unwinding an AWS auto-quarantine, breaking it up in code (like "part1" + "part2") might be enough to foil the AWS bot. Can anyone confirm?
I've been hearing this argument for decades, and every time it's been earnest but transparent blame-shifting. "The industry didn't understand security risks back then." "No one could have predicted this." The risks were well known back then by anyone who cared about risks.
Going with that, then why create that cloudy day when it would take very little effort not to?
And what message does it send to actively defend creating those cloudy days?
To go with the fire alarm analogy and exaggerate a little, it would work like this: you could attempt to install and maintain small disposable fire alarms in the refrigerator as well as every closet, drawer, and pillowcase. I'm not sure if these actually exist, but let's say they do. You then have to keep buying new ones since the internal batteries frequently run out. Or, you could deploy that type mainly in higher-value areas where they're particularly useful (near the stove), and otherwise put more time and money in complete room coverage from a few larger fire alarms that feature longer-lasting batteries. Given that you have an alarm for the bedroom as a whole, you absolutely shouldn't waste effort maintaining fire alarms in each pillowcase, and the reason is precisely that they won't ever be useful.
There are side benefits you mentioned to writing unit tests, of course, like helping you write the API initially. There are other ways to get a similar effect, though, and if those provide less benefit during refactoring but you still have to pay the cost of rewriting the tests, that also lowers their expected value.
To avoid misunderstanding, I also advocate a mixture of different types of tests. My comment is that based on the observation that unit tests depending on change-prone internal APIs tend to need more frequent rewrites, that fact should lower their expected value, and therefore affect how the mixture is allocated.
Of course, you don't know ahead of time exactly which tests will catch bugs. But given finite time, if one category of test has a higher chance of catching bugs per time spent writing it, you should spend more time writing that kind of test.
Getting back to unit tests: if they frequently need to be rewritten as part of refactoring before they ever catch a bug, the expected value of that kind of test becomes a fraction of what it would be otherwise. It tips the scales in favor of a higher-level test that would catch the same bugs without needing rewrites.
The issue is that when developers hear they should "reject bad input" in order to avoid vulnerabilities, they often interpret it as a call to reject any user input that isn't already known to be good. Since user inputs are often free text, like the name field, they wind up forbidding any input they hadn't specifically imagined, which doesn't align with any particular recipient's actual data requirement. It creates false-negative edge cases while only providing illusory help against vulnerabilities.
The issue isn't whether a value originated from the user. It's the units/data type, as you said, such as plain text vs. HTML.
Requirement: Name input box.
Implementation: We'll sanitize the input by rejecting any characters likely to be dangerous if mishandled, like single quotes, or anything else we don't immediately imagine to be useful. If a character turns out to be needed later, that's no problem. We'll just change the list.
Security audit: Passes
Later customer complaint: I can't sign up! — J. O'Brien
Dev team: Sorry, too bad. We'd have to re-audit everything and possibly modify code to allow your last name, because there might be code somewhere that relies on the original sanitization for security. That was the point of sanitizing on input, after all. If you want to sign up, it would be easiest for us if you would just change your name.
(I've seen the line of thought taken one step further: taking the realization that it's impractical to make strings universally safe for any context—even if you HTML entity-encode it twice, what if a recipient decodes it three times?—and concluding that security is hard and we can only approach it asymptotically, so shrugs XSS-like bugs are normal and unavoidable given finite time & budget.)
If the mindset is more like converting units, it becomes clearer. You can't concatenate HTML with a general Unicode string without converting the string to HTML first, any more than you can add inches and centimeters directly. "Cleaning" the centimeters would make no sense.
clang appears to correctly detect that `collatz` only directly defines a result for `1`, and any other input expands to yet another recursive call to `collatz` (the parameter is irrelevant). To avoid infinite recursion, `collatz` must eventually be called with the value 1, so that's what clang concludes.
In explaining the choice of per-hour, the author gave the example of choosing either an afternoon riding a mountain bike or an afternoon flying a sailplane. The example works because they involve about the same number of hours. But it's also the same number of decisions, so per-event works just as well there.
Per-event fixes distortions for quick activities, where durations are meaningless because they're dominated by setup time that isn't counted (or alternatively, the risk varies by multiple orders of magnitude depending on whether you count the overhead).
The chart shows summiting Everest as being 100x safer than base jumping. But if you're deciding which activity to do, it's more relevant to compare risk per-summit to risk per-jump-trip (say, 5 jumps?) or even risk per-jump, since you can calibrate the number of jumps on your trip based on your risk tolerance, but you can't do a fractional summit.
Using the author's numbers, jumping has a risk of 0.13% per jump, or 0.67% for a trip with 5 jumps. Everest has a risk of 6.5%. So in terms more relevant to decision-making, a decision to summit Everest comes with a 10x higher risk of death than a decision to go base jumping, instead of 100x lower as the chart might lead you to think.
Below that, it says you can draw these charts in JavaScript with a <chart> element, as if browsers natively supported it.
This keeps the stored functions version-controlled along with the source code, and avoids any need to hunt through migration files to find the latest definition. Adding a stored function or modifying its function body just works.
The less common operations of deleting a function or modifying its argument list do require an explicit line in a migration file, but those situations are rare (and potentially backward-incompatible, requiring extra caution regardless).
One subtlety is that a migration that adds a new table with a trigger should define an empty stub function as the trigger. This avoids duplicating code. The real function body will be loaded from the fixture immediately afterwards.
The monospaced example reminds me of TeX-produced CS papers at first glance. I'll have to give it some time.
The second point needs a citation.
It would certainly be a strong case if a suspect had actively sought the final ingredients of a self-planned act of terror, which would have killed people had the FBI not responded to the call first with fake equipment. But the objection in these cases is that when you subtract the FBI-provided motivation, plans, and equipment, all that's left are the person's own suggestibility and weak moral compass. Those don't constitute a criminal act in themselves. Experts could argue that they aren't likely to have ever resulted in one.
The religious targeting aspect is even more unfair. As far as I know, the FBI isn't spending similar time and resources to identify disaffected and suggestible non-Muslims, and then convincing them of the glory and honor awaiting them if only they would help push a button to bomb a local mosque.
Edit: In the above example, the "predictably persuadable" person isn't criminally responsible for murder if the ride was given to an FBI agent, and there was no actual robbery or murder.