Hacker Newsnew | past | comments | ask | show | jobs | submit | ctidd's commentslogin

CSRF exists as a consequence of insecure-by-default browser handling of cookies, whereby the browser sends the host’s cookies on requests initiated by a third-party script to the vulnerable host. If a script can fake all headers, it’s not running in a browser, and so was never exposed to the insecure browser cookie handling to be able to leverage it as a vector. If no prerequisite vector, then no vulnerability to mitigate.


You want lax for the intuitive behavior on navigation requests from other origins. Because there’s no assumption navigation get requests are safe, strict is available as the assumption-free secure option.


> Similarly, why is an online event handler considered a security risk? I just don’t see the difference between that and using a named function?

It is a vector for script injection, and should be disallowed with a strong CSP (no “unsafe-inline”).


Isn’t that only the case when the inline code uses untrusted user data somehow?

Inline: alert(“Hello “+userInput) is problematic.

Inline: alert(“Hello there”) isn’t, right?


CSP is a defense in depth mechanism which can be (among other capabilities) used to preempt the capability of inline scripts. This mitigates rendering bypasses, in the event that unsafe rendering occurs. For example, imagine you have an insecure markdown renderer, where a user can manage to escape some HTML and inject it into the DOM in a comment thread of some sort. If they can do so, then they can embed JS inside that HTML and get XSS on other users. Adding a rule to disallow all inline scripts mitigates this, assuming the first layer of defense fails.


Under a properly configured CSP, allowing scripts that aren't from the same origin to inject things into the DOM is the problem.

Both of your examples are problematic.


Putting the blame on cyclists for dooring requires missing problems up the chain which cause them to be in the door zone. Road designs (marked bike lanes that are 80% or more in the door zone) and automotive traffic overtaking unsafely are two contributors that directly or indirectly push cyclists into an unsafe space.

To ride out of the door zone in many cases requires taking the lane and riding outside of a marked bicycle lane, if present. Cyclists can and should do this, but it is no surprise that many don’t, and it is no surprise that drivers complain of those who do.


The implicit premise in this argument is that safety is an add-on that you buy or install like an antivirus package. If we designed to encourage less dangerous forms of transportation from the start, there may be cost savings that aren’t surfaced in the “add-on safety” cost calculation.


The other part of this decision not to protect human-powered mobility (pedestrian, bicycle, wheelchair, etc.) is that we allow or encourage automotive traffic as a constant, and _then_ we choose not to protect people. It’s a two step process where we make an active choice to create danger and then a second choice not to mitigate the danger.


> we make an active choice to create danger and then a second choice not to mitigate the danger.

Precisely! This is why I keep suggesting charges of criminal negligence against city engineers, along side stripping them of sovereign immunity.

> Oh no, Josh, it sounds like you want someone to be responsible for the decisions they make!

Yes, yes I do.

(I wrote the article. You very correctly perceive that two-step choice. make it dangers, keep it dangerous.)


As a heads up since you mentioned "class method syntax", methods are one of the most important places to have lexical `this` binding in many scenarios.

Take the following example, which is a normal class method:

> alertSum() { alert(this.a + this.b); }

And here we have an arrow function used to create an instance method (just an arrow function assigned to a property on the instance):

> alertSum = () => { alert(this.a + this.b); }

Then let's say we want to pass the method directly as callback:

> this.button.addEventListener('click', this.alertSum)

The first example (class method syntax) won't have the necessary `this` context unless it has its context bound to the instance through `Function.prototype.bind`. There are other patterns to avoid this (e.g. wrapping all callbacks in arrow functions when passing them), but it's useful to consider that classes methods can easily create confusion because that's _exactly where_ someone more used to a different language may assume the `this` context is bound lexically.


Excellent point! I can see that getting confusing quickly.

Edit: I was confused about how this could work, so I dug through [1] for a bit. It appears that for each object of that class created, an arrow function will be created on that object and its this will indeed be bound to the same scope that the constructor function is bound to. This is really cleaver and I applaud whoever thought it up!

It is interesting to note that this creates a new arrow function on each object as opposed to the normal definitions which create a single function which is stored in the prototype of the class. (its easier to check this in a browser's dev console then it is to decode the spec)

This would suggest that one should use different approaches for different types of objects: It makes sense to use arrow functions for "resource" or "actor" objects, of which there are few but they may have callback functions. It makes sense to use normal method definitions for "plain old data", of which there may be many, (which would make the arrow functions too expensive) but they should not have callback functions.

[1] https://tc39.es/proposal-class-fields/unified.html


> This is really cleaver and I applaud whoever thought it up!

Not really. It's contortionist and wasteful and one of the many reasons why mainstream web apps are one big celebration of bloat on a boat.

The neophyte programmers who have turned into expert Modern JS programmers are always recommending arrow functions like this because they've never actually looked at the event listener interface. What happens is they try to make things more complicated than they need to be and bodge their event registration. So they apply a "fix" by doing what they do with everything else: layering on even more. "What we need," they say, "are arrow functions."

No.

Go the other way. Approach it more sensibly. You'll end up with a fix that is shorter than the answer that the cargo cult NPM/GitHub/Twitter programmers give. It's familiar to anyone coming from a world with interfaces as a language-level construct and therefore knows to go look at the interface definition of the interface that you're trying to implement.

Make your line for registering an event listener look like this: `this.button.addEventListener("click", this)`, and change the name of your `addSum` method to `handleEvent`. (Read it aloud. The object that we're dealing with (`this`) is something that we need to be able to respond to clicks, so we have it listen for them. Gee, what a concept.) In other words, the real fix is to make sure that the thing we're passing in to `addEventListener` is... actually an event listener.

This goes over 90% of frontend developers' heads (and even showing them this leads to them crying foul in some way; I've seen them try to BS their way through the embarrassment before) because most of the codebases they learned from were written by other people who, like themselves, only barely knew what they were doing. Get enough people taking this monkey-see-monkey-do approach, and from there you get "idioms" and "best practices" (no matter whether they were even "good" in the first place, let alone best).


I want to respond to this constructively, because you highlighted a useful interface I'd never taken note of previously; maybe we can focus this discussion on a technical level. Meanwhile, if you haven't had a positive response to technical feedback directed to JS engineers about this, I would encourage rereading the comment you wrote. I genuinely hope this is useful feedback, as I very much value insight from other languages and levels of abstraction, and I'd love for you not to get turned off to sharing that insight by a bad response from JS engineers. JavaScript is high level, and it's too easy to get disconnected from all of the work the engine and underlying computer are doing to make a program work in this environment.

---

As I understand the interface, practical use of the EventListener interface boils down to the implementer performing a form of event delegation, where you'd wind up delegating from a single `handleEvent()` method on a class to handle different event types and/or events with different target elements -- as opposed to a single click handler in a simple button click example. I'd love to understand and quantify the benefit of this. If it's a significant improvement, it'd be doubly unfortunate, as many callback-based interfaces in JavaScript APIs and libraries at a higher level don't support such a model.

Assuming there's a strong benefit, I also wonder if there's an opportunity for build-time tooling to rewrite code from ad-hoc callbacks to more efficient delegation along these lines. Tangentially, I also don't know about `Function.prototype.bind` vs wrapping arrow functions in terms of performance; that's also something I'm curious about, as they're often a 1:1 analog.

I'm tempted to test a few of these things out myself, but if you have references, that would be helpful.


> if you haven't had a positive response to technical feedback directed to JS engineers about this, I would encourage rereading the comment you wrote

You're mixing up cause and effect; there's a reason why the perspective laid out in that comment has come to carry the amount of derision evident in its tone. It's wrong to assume things started out like this (and it's wrong to assume that a different tone will achieve better results; experience shows that the difference in results, if any, is worse otherwise).

> Assuming there's a strong benefit, I also wonder if there's an opportunity for build-time tooling to rewrite code[...]

That's another example of "layering on more" approach, and the small matter of changing the actual runtime mechanism in isolation isn't going to solve much. The big, relevant matter at hand is a complete difference in mindset that programmers have when they're approaching a problem with the ultimate intent of solving it with code.

For example, let's say you have a list of items, and M different kinds of events you want to respond to. That's not just a matter of a difference of e.g. 1 listener (implementing `handleEvent`) vs 2 or more (individual arrow functions). If that list is N items long, now we're talking about M × N different objects (worse, closures—each with their own lexical scope, keeping the bindings alive and potentially thwarting the GC's work)[0]. But the programmer who knows not to use arrow functions here doesn't just stop at implementing `handleEvent`, he or she also recognizes that if all of those listeners share common behavior, then the whole thing can be handled by a single event listener—on an ancestor element that just looks at the event target.

Once again, though, this is much bigger than event listeners. This is about a mindset that pervades everything at every level. The mindset of programmers working in "modern", "standard"[1][2] JS is a mindset that fundamentally impacts how they approach everything, from how to decompose a system into its natural parts, to what routines need to be written and what factors to be aware of while implementing them.

Note that unlike the comments elsewhere, this isn't mistakenly misplaced aggression towards JS per se, nor is it an endorsement of other communities/ecosystems like Python, which tends to have programmers that are just as bad, if not worse. A big part of the problems afflicting the world of modern JS for that matter is programmers who have ended up there by way of Python or similar.

0. Runtimes will have some mitigations for this, but eventually that runway ends; the myth of the sufficiently smart compiler although an enduring one, is unattainable

1. https://standardjs.com

2. Let's consider, for that matter, the obnoxious temerity that it takes to decide to anoint one's opinionated, less-than-well-informed set of personal preferences—many of which ironically reek of fighting against the language itself—as "standard"


Just FYI, the standardjs link doesn't seem to support your point here. It seems like standardjs is mostly about forbidding confusing syntax and obsolete APIs. (like .__iterator__, which appears to be replaced by Symbol.iterator, or .__proto__ which is replaced by .getPrototypeOf())

The only item which standardjs forbids that I could identify as possibly producing a decent performance improvement if used is the "with" statement. They also forbid wrapping non-objects in objects, which I guess could provide extra-expressiveness, but seems like it would usually just be a performance penalty.

I have seen people recommending obviously inefficient things like including large third-party libraries just to look up an element by class name, but standardjs looks like it is just a set of linting rules. I don't agree with all of them but I don't think there is a set of rules everyone would agree to.


> Make your line for registering an event listener look like this: `this.button.addEventListener("click", this)`, and change the name of your `addSum` method to `handleEvent`. (Read it aloud. The object that we're dealing with (`this`) is something that we need to be able to respond to clicks, so we have it listen for them. Gee, what a concept.) In other words, the real fix is to make sure that the thing we're passing in to `addEventListener` is... actually an event listener.

Eh, show me an object that both owns a button and is an event listener attached to that button, and I’ll bet you just showed me an object that violates the SRP. OO event listeners make sense to encapsulate state narrowly associated with handling the events being listened for.

But, having been doing OOP since I was a teenager in the late 1980s (and even that after programming for more than half a decade), I don’t prefer to do as much JS as possible in a functional style because I don’t get interfaces or other OO concepts, but because I understand the limits of their utility and managed not to be one of the one-paradigm-to-rule-them-all programmers that came out of the excessively OO-focussed pedagogy of much of the 90s and 00s.


> managed not to be one of the one-paradigm-to-rule-them-all programmers that came out of the excessively OO-focussed pedagogy of much of the 90s and 00s

Sounds like a veiled criticism towards an implied target (of me), which would be interesting, considering the retort is an appeal to "SRP" (referred to only with shorthand, even), and indeed, the first mention of OO(P) is your comment. The shape of your foe isn't what you think it is.

> OO event listeners make sense to encapsulate state narrowly associated with handling the events being listened for

For this defense to be valid, you have to ignore the preconditions that got us here. The entire context here is making sure that `this` refers to the correct thing at the time that the event listener is executed. Either you want that, or you don't—pick one.

(And as with, like, 90% of mainstream applications of the label "functional programming", look at what people are actually talking about when they use those words, and it's immediately apparent that theirs is a style of programming where the label is unjustifiable, considering it's fundamentally at odds with what functional programming actually is. Again, pick one: you either intend to do FP and do so through the use of functions, or you want your state baggage. Modern appeals to FP by JS programmers in the mainstream and the practices that get smuggled in under that brand are just as bankrupt as arguments for modern JS practitioners' best practices regarding anything else—ones that are entirely self-defeating or fail to hold up under scrutiny otherwise.)


I'm learning all sorts of things today! handleEvent certainly seems like the language certified way to do this. It does seem like that means you need a case statement in handleEvent if you want to listen for multiple events, which I guess is not the end of the world. It does solve the "redefine the function for every object" problem though, provided any third party apis understand the EventListener interface.


> handleEvent certainly seems like the language certified way to do this

It's a platform API (the browser DOM). It's a completely separate matter from JS the language. It has, though, been the "correct" way to work with events since at least as far back as 1998 or so. It's the official platform APIs that had to change to accommodate the function-as-a-listener pattern (requiring an entire revision to the interface definition language itself so that it would have the power to express it), since so many browsers implemented that non-standard extension, and so many programmers insisted on using it. And that pattern is also directly responsible for why arrow functions and Function.prototype.bind were added to the language itself. If only it had been addressed differently, writing programs for the web browser might look a lot different than the way it does today.


The goal makes sense, but more specific questions can get substantially better responses. An example of what I'd find to be a more effective line of questions with a similar goal:

1. Is there a substantial technical or organizational change your company/org/team is currently executing? (Choosing scope based on who you're talking to.)

2. (If not) What was the last one you executed successfully? (Alternative: unsuccessfully)

3. What problem is/was this change aiming to solve?

4. Did the change introduce an anticipated or unanticipated tradeoff?

The goal would be to understand what the company currently or recently found challenging and what they're motivated to solve. It can also gauge the company's realism in evaluating the outcome.

Can you acknowledge real problems and tradeoffs, drive a change, and know when it's accomplished (or when it's time to rethink it)?


Forcing your children to eat things they aren't comfortable with is not a hack. Please do not do this. There is a significant difference between providing a positive environment for your child to encounter new foods and forcing them, physically or otherwise, to eat them.


There's something to be said for this, but I also don't think the GP literally meant forcing them. Forcing children to eat something can cause aversion and eating problems. That said, I am a fan of strongly incentivizing thought promising a later treat for the first few times there's something new to try that I want them to give a fair shake to.


> but I also don't think the GP literally meant forcing them

We only have the GP's words: and at face value, as they should be taken, they do seem to literally mean that.


To a degree. Hyperbole and idioms are a normal part of communication, as is learning to decipher meaning from them.

If someone said something along the lines of "I would kill my son if they did that", would you take that literally, or as a hyperbolic idiom meaning they would be mad at them and punish them?

I think the actual meaning of the statement in question is ambiguous given the above, and providing for the option that you misinterpreted someone's meaning when condemning their speech likely does a lot to keep the discussion civil and useful.


parents actually killing their child is rare. Parents actually making their child eat specific food, with threat of physical force, not so rare. You don't have to search for a figurative meaning where none is needed.


As a counterexample to consider, I would suggest that a client-side web app is coupled to any remote data source intrinsically by a latency-sensitive connection over the network. As soon as you have enough data, you need to defer portions of it and load them on demand based on user interactions. So now the ways in which data was or wasn't factored in a way that mirrors the app impacts it.

Now, there are tradeoffs we can make to deliver an end state to a user: we can normalize and incrementally hydrate the data shown in the client and increase visible jank in the process, or we can realign the app's experience and/or data source around each other.

Decoupling UI components from business components is of course valuable, but that's different from taking that a step further and decoupling business components from the data source. The latter is a significantly more challenging proposition.

Also, there's some fuzziness here in what we mean by decouple. REST vs SOAP vs GraphQL as transfer layers can be abstracted away as implementation details, but I'd place a higher emphasis on the shape of the data and how it has to be traversed in the client. If you have a paginated list, for example, and you only want to load it once, but you need to display both a summary and load it incrementally, things can get complicated as more functionality is built out from that starting point, regardless of transfer layer.


As a counter-counter-argument, one could argue that there's coupling to the database and one might as well then write db queries from their single file components. One stack (meteor) took that idea of trading loose coupling for productivity to the extreme but then suddenly found itself in an awkward position when react and npm exploded in popularity (and Mongodb lost mindshare).

Surely something else will eventually displace react and/or graphql, just as previous stacks and paradigms have been overshadowed. But then we go back to my original assertion: refactoring away from the legacy of the tools we no longer like is decidedly going to be more complex if we chose to sacrifice loose coupling in favor of something else (performance, initial dev speed, what have you)

Case in point, esbuild looks like a very promising replacement for some web plumbing. But if there needs to be extra collaboration to support this there, other stacks can take the opportunity to dash ahead (e.g. vite) while the react team is busy collab'ing with all these compiler projects.


> but I'd place a higher emphasis on the shape of the data and how it has to be traversed in the client

There is something incredibly satisfying in rendering an entire UI experience from a single GraphQL payload, without having to build intermediary data structures to stitch it all together from multiple endpoints.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: