Check out a free preview of the full The Good Parts of JavaScript and the Web course
The "Securing the pubsub() Function" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:
Doug demonstrates how to properly secure the publish() and subscribe() methods within the pubsub() function. He adds some error handling, replaces the for loop, and utilizes Object.freeze()
Transcript from the "Securing the pubsub() Function" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Douglas Crockford: The simplest attack to prevent people from getting publications,
>> Douglas Crockford: Is this one where we simply subscribe with nothing. So that means we're gonna push undefined on to the subscribers array. So when we go to do this loop, kaboom right? And so everybody after us doesn't get any messages sent.
[00:00:26]
So how would you fix that?
>> Speaker 2: That's not the problem though, because the people before you still get it, so-
>> Douglas Crockford: Right, but the people after don't, and so-
>> Speaker 2: The problem is we try to prevent anyone-
>> Douglas Crockford: We have to make sure that everybody receives every message.
[00:00:43]
If one person gets it we can't say that we've succeeded, but everybody has to get it.
>> Speaker 3: You can just do a type check for your tag on me, right?
>> Douglas Crockford: We could do that. Up here, we could do type check you know, if type of equals function.
[00:00:57]
>> Speaker 4: You should be re-wrapping your call in a try catch with what inside.
>> Douglas Crockford: Yeah, that's it because if they were to pass any function that throws then it wouldn't do that, so-
>> Speaker 5: So pubsub is something we give out to all the-
>> Douglas Crockford: We give to all the third parties, they all share that instance.
[00:01:15]
>> Speaker 5: So really in this case it's kind of don't trust user input.
>> Speaker 5: They can send to subscribers but they can send you a function as subscriber, an empty string.
>> Douglas Crockford: Right, well, in this case it could be a malicious failure but it could also be an accidental failure.
[00:01:30]
Someone might simply call it incorrectly and we don't want the whole system to fail because of that. So this is what try catches for, right? So we can simply catch the thing, ignore the error and we'll keep on processing. So, that's good. So we're now ready for your second observation.
[00:01:50]
>> Speaker 4: Set subscribe to null.
>> Douglas Crockford: Yeah, so we can tamper with the pubsub instance itself and we can delete the properties. Change either of them to undefined or null or replace them with other functions that could do things more insidious like allow only certain people to subscribe or allow people to think they subscribed when they didn't.
[00:02:16]
Or to filter the messages when they publish, or to tamper with the messages when they publish, there's an infinite number of terrible variations on this theme. So how would you fix that?
>> Speaker 6: Use a server.
>> Douglas Crockford: I'm sorry?
>> Speaker 4: So you aren't gonna really expose publish so much as,
[00:02:39]
>> Speaker 4: You're gonna return a function. You're gonna return a function. Returns a function?
>> Speaker 4: I don't know. It's something like a getter and a setter. You're don't wanna set it if they can only get it.
>> Douglas Crockford: You could, but there's an easier thing to do than that.
>> Speaker 7: Freeze the option here?
[00:03:04]
>> Douglas Crockford: Yeah, you wanna freeze it. So if we freeze the object then all of those attacks are completely frustrated.
>> Speaker 4: Would you do this right now in JavaScript?
>> Douglas Crockford: Yeah, freeze was added in the S5.
>> Speaker 4: Okay.
>> Douglas Crockford: So it's in IE 9 and 10 and 11 and all the good browsers.
[00:03:25]
So we can freeze. So that completely solves this. And so that's one of the reasons why I like freeze as an object construction pattern because there's a whole lot of stuff we'll never have to worry about if the objects are frozen. And freezing this object does not impair its ability to do what it's supposed to do.
[00:03:46]
That these methods still have access to the subscribers array and still can do all that dynamic stuff. It's just nobody can tamper with the instance.
>> Douglas Crockford: Okay, we're now ready for your next suggestion, your first one.
>> Speaker 4: I forgot it already.
>> Douglas Crockford: [LAUGH]
>> Speaker 4: We're gonna pass in.
[00:04:07]
We're gonna subscribe with a function that deletes, iterates through this and deletes everything.
>> Douglas Crockford: Yeah, exactly.
>> Speaker 4: Something like that.
>> Douglas Crockford: Yeah, something like that. So that'd be something like this. So we're going to subscribe with a function which will get access to this. And then that gives us access to the subscribers array.
[00:04:32]
Because this is a method invocation, even though it doesn't look like a method. We're calling a function that is stored in array, we don't think of that as being a method invocation but JavaScript does. So everything from here on will get bound to this. So in this case, we're going to set this.length to 0.
[00:04:55]
That will delete all of the subscribers but we could do much more insidious things as well. Again, there's an infinite number of bad things you can do to this object if you get access to this.
>> Douglas Crockford: And so this is a big source of confusion again, right? That in JavaScript, things with brackets are method invocations but we don't see those as method invocations.
[00:05:21]
So again, this is a confusion which leads to misunderstanding of what our programs do, which make it possible for bugs and security exploits to happen.
>> Speaker 4: Inside this function that you've just written, this is the paysub object, right, with its var subscribers, that's its scope, right?
>> Douglas Crockford: No, in this is case, this is the subscribers array.
[00:05:51]
Because this is the method meant. Okay, so here's your function, you pass it in to subscribe. So it gets stored in the subscribers array. And in this loop, it now gets called but it's being called as a method. There are four ways to call a method in this language.
[00:06:13]
I think there should only be one, but there are four. And at least one of the forms is confusing as to which kind of invocation it is.
>> Douglas Crockford: So how would you fix that?
>> Speaker 7: My brain says call, no?
>> Douglas Crockford: I'm sorry?
>> Speaker 7: My brain says using call.
[00:06:38]
>> Douglas Crockford: That would be one way to do it if we say, subscribers[i] dot call and then pass in that. That would be one way to do it.
>> Douglas Crockford: The way I would prefer to do it or the other thing you could do is assign subscriber[i] to a local variable, and then call that variable.
[00:07:00]
Or, what we could do is use forEach. I'm now distrustful of for loops in general and I like forEach much better. So I can pass to forEach a function which will call each element of the function and ignore any exceptions and I really like this. I think this is very, very nice.
[00:07:24]
So I'm not using for loops anymore. I'm doing this stuff instead and because it's passing in each individual element, there's no confusion about how this gets called. It's never gonna be a method invocation. In fact, this function doesn't even see the array. All it sees are the individual elements.
[00:07:45]
>> Speaker 4: Remind us how to escape forEach.
>> Douglas Crockford: I'm sorry?
>> Speaker 4: Remind us, how do you break out of a forEach.
>> Douglas Crockford: You use every instead of forEach. And we would design it so that this function would always return true.
>> Speaker 4: It returns false then it leaves.
>> Douglas Crockford: Then yeah, false is the exit signal.
[00:08:06]
>> Speaker 8: On the previous slide, somebody wants you to clarify why does this refer to the array.
>> Douglas Crockford: Right, so this is the function that is being executed here, okay? And this form of function invocation is the method form. The method form will have a dot in it or a bracket in it.
[00:08:32]
And so, everything to the left of the last dot or last bracket gets bound to this and that's why that happens.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops