Live data from Hacker News

Firewalling your code

lackofimagination.org

61–70 of 82 posts

Re: Firewalling your code

#62
That `userService` example is just awful, it feels like it's trying to achieve so many things with exactly the worst options.

- Not using ES modules which is compounded by: - Creating a random "bag of crap" as I call it by throwing all the functions into an exported object - Can't even get static build time feedback about the functions you're calling or if they even eixst which you would if:

The better alternatives here are:

- Just have plain exported *functions* in an ES module - If you need shared state both functions access then export a plain class in an ES module

Re: Firewalling your code

#63

I think the general concept here is putting in place restrictions on what code can do in service of making software more reliable and maintainable. The analogy I like to use is construction. If buildings were built like software, you'd see things like a light switch in the penthouse accidentally flushing a toilet in the basement. Bugs like that don't typically happen in construction because the laws of physics impose…

> I think the general concept here is putting in place restrictions on what code can do in service of making software more reliable and maintainable. The analogy I like to use is construction.

The concept is quite old, and it's called software architecture.

All established software architechture patterns implicitly and explicitly address the problems of managing dependencies between modules. For example, the core principle of layered/onion architecture or even Bob Martin's Clean Architecture is managing which module can be called by which module.

In compiled languages this is a hard constraint due to linking requirements and symbol resolution, but interpreted languages also benefit from these design principles.

Re: Firewalling your code

#64
post #35
post #23

Earlier quoted context omitted.

Letting a static analyzer do these checks is a sane approach! The runtime detection of code files is really weird and would fail with bundling etc.

Runtime is important if security matters. Assume an attacker has already compromised your program - how much damage can they do? If you check at runtime you can prevent the compromised code from calling your functions. Well maybe, we don't know what code was compromised or how it was, but many compromises are a buffer overflow that only runs a few hundred bytes of code (overflow more than that and you clobber somethi…

Thinking about this scenario I'd suppose disabling features would be the way to go - disabling individual methods doesn't look feasible and I imagine that it should be done at the configuration level (what I mean here is that you need an easy and quick way to switch the feature flag, rather than recompiling/redeploying). But then the code would have to be built as well to support such feature.

Re: Firewalling your code

#65
post #42

Sounds similar to capabilities: https://en.wikipedia.org/wiki/Capability-based_security

Capabilities is what you get if you keep traveling down this road, deal with the resulting issues, tune the approach, and iterate on it a lot. It doesn't take long to figure out that partitioning permissions by "what functions can be called" is a nice start, and I don't mean to criticize it as a start, but it is only a start. It isn't the correct dimension of the code to cut on. Capabilities is, in my opinion, the bi…

I really wish Microsoft had gone forward with their Midori project, or at least open-sourced it; they apparently put a lot of work into designing a capability system, both in language design and OS architecture. https://joeduffyblog.com/2015/11/10/objects-as-secure-capabi...

Re: Firewalling your code

#66

I think the general concept here is putting in place restrictions on what code can do in service of making software more reliable and maintainable. The analogy I like to use is construction. If buildings were built like software, you'd see things like a light switch in the penthouse accidentally flushing a toilet in the basement. Bugs like that don't typically happen in construction because the laws of physics impose…

> I think the general concept here is putting in place restrictions on what code can do in service of making software more reliable and maintainable. The analogy I like to use is construction. The concept is quite old, and it's called software architecture. All established software architechture patterns implicitly and explicitly address the problems of managing dependencies between modules. For example, the core pri…

The goofy thing is that “software architecture” was killed by YAGNI dogma and yet the need for properly layered code hasn’t disappeared, so people are inventing tooling to enforce it.

Re: Firewalling your code

#67

Earlier quoted context omitted.

I love how the comments are split along the lines of, "wait, some people don't do this?" and "this is a maintenance nightmare!" If you know, you know.

> this is a maintenance nightmare! Yeah, it's a pain to maintain, but it is damn secure.

Assuming reasonable factoring, maintenance is only a problem when trying to seriously cheat the layers, eg your controller wants to modify the template engine’s internals for a single request. Better to just be honest about it by punching a hole in the abstraction that is appropriately named and using that.

Re: Firewalling your code

#68

Earlier quoted context omitted.

> this is a maintenance nightmare! Yeah, it's a pain to maintain, but it is damn secure.

Assuming reasonable factoring, maintenance is only a problem when trying to seriously cheat the layers, eg your controller wants to modify the template engine’s internals for a single request. Better to just be honest about it by punching a hole in the abstraction that is appropriately named and using that.

No cheating!

For example, I stop creating SQL, after the first layer above the DB access layer. Everything above that, is a function-based abstraction, so there's no SQL, in most of the stack.

Some layers are meant to introduce "replacement points," so you could swap out the SQL for a NoSQL solution, if you want.

Most layers have a fair bit of validation and permission-checking, etc.

But making sure that I stick to the rules for each layer can be a pain. I stick to them, anyway.

Re: Firewalling your code

#69
post #5

Always feels like you're in a dysfunctional place when you have to program this defensively. I had an acquaintance who was writing library code for a few dozen data engineers in python, and she had to resort to locking down private methods by checking the call stack after engineers repeatedly got hold of private objects, or objects that are only there sometimes (e.g. when not running clustered). I adopted a similar s…

Were these leaky abstractions built on top of other libs?

Databricks, so it's hard to avoid.

Re: Firewalling your code

#70
Slightly tangential, but I've found importlinter neat for restricting what layers in your Python code can call each other (in this case by restricting imports, not calls): https://pypi.org/project/import-linter/

For example, you can ensure lower-level packages don't import higher-level ones:

  [importlinter:contract:my-layers-contract]
  name = Layered architecture
  type = layers
  layers =
      mypackage.cli       # can import anything
      mypackage.services  # can't import from mypackage.cli
      mypackage.models    # can't import from .cli or .services
Post reply on HN