More LoC is always a greater attack surface, regardless of development trustworthiness.
Minimize code ruthlessly.
More LoC is always a greater attack surface, regardless of development trustworthiness.
Minimize code ruthlessly.
IMO, the OP post has an unfounded sense of hubris. Everyone else's code is bad except for me, who only writes minimal code with no exploits.
TLS is an example of when you probably would not make that trade-off, but there are lots of other examples where it would make sense.
Assuming you're fallible and write code with exploits like everyone else, your program will probably have different exploits from mine. An attacker won't be able to target a widely used library and enjoy being able to pick from several targets. Instead, they'll have to tailor an attack for your code base. Each exploit found yields less of a reward, which will frustrate less motivated attackers.
Libraries are not only larger because they are written for more use-cases, but also because they cover more tested edge cases.
> Instead, they'll have to tailor an attack for your code base.
This misstates the actual threat.
Assume detection of exploits is automated (even if it isn’t completely automated now). Assume exploit code is modularized and passed around on hacker markets, because they are.
Your recommendation only increases the cost to exploit by a small factor, but it also increases the inevitable costs of legitimate usage by possibly a much larger factor (patching the inevitable bugs which are found). Because developers aren’t specializing (in how to efficiently+safely write logging code) bugs both in the designs phase and implementation phase will be higher than in a counterfactual specialization world.
But using "don't roll your own crypto" doesn't generalize to using every possible library to avoid writing any code. Down that path lies the madness of leftpad.
Crypto and security protocol implementations are exceptionally difficult to write in a way that avoids all exploits, so, yeah, don't write your own TLS library unless you're willing to fund a team of all the necessary experts which is going to be very difficult.
OTOH a very large number of libraries implement simple things in overly complex ways (sometimes by necessity because a library needs to try to be all things for all people) and can be very easily replaced by small amounts of code that do only what my product needs.
Every third-party library you add is an additional source of bugs, unmaged surprises (e.g. they decide to break their APIs for the lulz), attack surface and constraints. It is wise to weight the benefits against the drawbacks for each library individually before making it part of your code.
At the same time, there's a lot of hubris that goes into the statement "Every third-party library you add is an additional source of bugs, unmaged surprises", but somehow the code you write was typed by God himself.
Everyone points to leftpad madness of dependencies despite the fact that the dominos leading up to leftpad was the work of one very dedicated individual. Despite other languages having the same kind of simple dependency management never having anywhere close to the same issue (like Ruby, on which npm was based). Regardless, the OP doesn't use leftpad as an example; he uses log4j. I agree that log4j had insane defaults, and that's on the maintainers, but the implication is that you should roll your own logging facade and that's something where I wouldn't want to work on a project where all the logging is done through printf (except in probably an embedded environment) or maintain an in-house logging library because the original writer thought it would be "just small amounts of code".
You (everyone) should't allow hubris to drive these decisions, instead make an objective evaluation.
If you're going in saying "I can write this same functionality better than anyone else so I'll just do it", stop and rethink.
Every line of code (to an approximation) adds more potential bugs. So if you pull in a library with a million lines of code, you've added that level of magnitude for possibly future bugs. If you actually need most of those million lines because you use all the features, then you need them. In that case it would be hubris to assume that you can write the same but slightly different million lines and do much better. You can't.
But as other subthreads here point out, often you really use like a thousand lines out of that million line library. If that's you use case, you can reduce your attack surface by 999000 lines of code by writing a few functions of your own, customized to your needs without any unused frills. You don't need a god in your staff, just someone who values the reliability and security that simplicity brings.
> unmanaged surprises
To unpack this statement, I meant that when using a third party library you are now subject to their schedule and roadmap over which you don't have any say or ability to manage it. They might drop a feature you need, or break APIs in a minor release, etc. This is undeniably true, so must be taken into account when doing a risk analysis on depending on some library. Well-run libraries offer a stable platform but tons of libraries are not well-run from a release engineering aspect. Choose carefully and know what you're getting into.
The same goes for parsing and other complicated operations containing pitfalls.
Honestly, I hope most crypto, parsing, numerics libs, and OS kernels and drivetd were rewritten in Rust and given C, C++, etc. interfaces.
Everything has a cost (usually in time) and everything comes with trade offs (usually a different set of bugs). Not-invented-here comes with a gigantic upfront time cost and a larger set of bugs. The best heuristic depends on what you’re optimizing for. There’s never an easy answer.
> Minimize code ruthlessly.
Minimize functionality ruthlessly.
> More LoC is always a greater attack surface
More… than what? What does the counter factual look like?
If I only care about 1 application in a vacuum, reducing LoC is not terribly difficult. If I run my application on any modern OS, I depend on thousands of applications, daemons, libraries, and a kernel. I would far rather their developers take reasonable efforts to import common libraries when appropriate. The aggregate LoC of an ecosystem is more important than the LoC of a single application.
Also, telling people the metric of relevance is LoC is wrong and will lead people to game the metric, losing sight of the actual goal of code quality. There are infamous examples of Perl code golf; they optimize for LoC, but aren’t at all useful for code quality or security.
Far better to expand LoC a reasonable amount in favor of developer readability and to reduce complexity.
Obviously, pulling in something like left-pad is worthy of derision. But generally you should pull in whatever dependencies let you go faster, and minimize the amount of time spent planning for black swan events.