Thursday, January 24, 2013

Closures in loops - Javascript Gotchas

When you do enough Javascript programming, it’s difficult to avoid learning about this sooner or later, but I still feel like it’s not well known enough. If you learn about it from a blog post like this, you’re one of the lucky ones. Once upon a time I spent hours going crazy thinking the world didn’t make sense anymore - that or every Javascript implementation had a serious bug. I was trying to figure out why it was that a closure within a for loop seemed to have the same value for every iteration of the loop - it just wasn’t changing even though the loop was iterating properly. I was baffled. Isn’t a closure supposed to capture the current value of variables within it’s accessible scope?

Here’s a simple piece of code you can run to see what I’m talking about:

for(var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 0);
}

If you run that in a Javascript console, it’ll output something like this:

3
3
3

Wait! What? Ok, so maybe I gave it away by wrapping it in a call to setTimeout. What’s happening here? It turns out JavaScript is single threaded so it keeps an event queue where it queues up things to do. The closure created in each loop iteration is queued to run as soon as the rest of the current execution context finishes and CPU time is returned to the event loop. setTimeout here serves to simply defer the execution of each closure until after the loop finishes running. By that point the final value of i is ‘3’. Keep in mind that i was declared before the loop started. It’s scope is external to the loop.

Ok, that makes sense, but what if I do something like this:

for(var i = 0; i < 3; i++) {
    var j = i;
    setTimeout(function() {
        console.log(j);
    });
}

Now we’re declaring a variable j inside the loop that is a copy of i. Well, it turns out that the scope of j here is also external to the loop. It will continue to exist outside the loop and thus only ever has one value which changes as the loop iterates. This in turn means that when a deferred closure runs, the latest value will be the one that all the closures from this loop end up with. In Javascript it is very common practice to pass callbacks around that are deferred until something completes or some event occurs. So like I said, sooner or later you’re likely to run into this problem. It’s gotten me more than once, even though I knew about it.

So what can I do then to make my closures work right in a loop?

I’m glad you asked! There are a few different ways you can handle it, but the basic concept is that you have to capture the value of i in each iteration of the loop. By far the cleanest solution is to just use an iterator function like _.each or $.each from the Underscore or jQuery library:

_.each(_.range(3), function(i) {
    setTimeout(function() {
        console.log(i);
    });
});

If you already have a loop that you don’t want to convert to use an iterator function, all you have to do is wrap your closure in a closure in which you define new variables which capture the current value of the variables that change on each iteration. Got that? The trick to capturing the variables is making sure your outer closure executes immediately during the current iteration of the loop. You can use one of these two similar approaches:

Method 1:

for(var i = 0; i < 3; i++) {
    (function() {
        var num = i;
        setTimeout(function() {
            console.log(num);
        });
    })();
}

Method 2:

for(var i = 0; i < 3; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        });
    })(i);
}

And that’s it! The world makes sense again! Happy coding :)


UPDATE - 10/7/2013

There is now another simpler solution to this problem since the let keyword is now supported in both Firefox and Chrome. The let keyword is used in place of var to scope variables to the block it’s used in. Similar to one of the above examples that does not work, you can swap var for let and it works magically, like so:

for(var i = 0; i < 3; i++) {
    let j = i;
    setTimeout(function() {
        console.log(j);
    });
}

This works because we declare a new variable, j, which we set to the value of i which is captured by the closure within the loop, but it doesn’t continue to exist beyond the end of one iteration of the loop since it’s scoped locally.

Tuesday, January 15, 2013

Password Insanity

I’m going to pick on password security requirements for a bit. I was just forced to change my password for a certain website which requires their users to change it every 90 days. This is a common requirement for a lot of places, but also, potentially a stupid one. Let’s look at this for a minute.

Being a programmer, I consider myself an expert user. I think about security all the time. I have several different randomly generated passwords containing numbers, letters, and in some cases symbols. I have to have a variety because of the various ridiculous password requirements of different websites and services. We’ll get to that in a minute. So I use one of these passwords for a website I signup at. Later I login to discover that I’m now being forced to change my password. It’s not long before I run out of my more secure passwords. At this point I’m frustrated and I resort to far less secure password practices.

I could generate a new password or make one up each time I have to change it and write it down or store it in a password vault. If I weren’t an expert user, I’m more likely to write it down, which is far less secure. Not only is this an inconvenience because I have to lookup my password every time I login if it’s not a place I login to often, but it also means that my password is physically stored somewhere. This will always be less secure than if the only place it was stored was in my head.

What I usually end up doing is using far less secure passwords where I can just increment a number or reverse the password a bit. For example, on one such site I used abcd1234 then when it expired I reversed it to 1234abcd. I also stored it in a file so I didn’t have to go through the whole process of resetting the password when I inevitably forget what I used for that site. I used to have a nice quality password there that was only stored in my head.

Now let’s take a practical look at password restrictions. On this same website they had a list of requirements when setting a password. A lot of administrators implement strict requirements feeling like this leads to better security. Let’s have a look at some of these requirements and what they say to a hacker:

  • Password must be EXACTLY 8 characters

    Really? Ok, so now if I’m a hacker and I’m configuring my password cracking software to brute force a user’s password I now know that I don’t have to bother trying anything less than OR greater than 8 characters. This narrows it down to a VERY small number of passwords that a computer has to try to guess the right password.

  • Password must contain at least 1 letter and 1 number

    Ok, so now I know that I can probably find a large chunk of user’s passwords with a simple dictionary attack with mutations. This means that the program will try adding mutations such as adding common numbers to the beginning and end of a password and adjusting the casing of letters. I don’t need to bother with a plain dictionary attack. And believe it or not, having a number in your password doesn’t magically make it secure, and you can have a very secure password with only letters.

  • Password must NOT contain any symbols

    This is getting ridiculous. The number of passwords that I have to try to successfully guess a user’s password has just been reduced exponentially. If the software/website literally can’t support symbols then it was terribly written by terrible programmers. There is no excuse for this.

These are just a few of the actual requirements that I see still in place around the web. And guess what? If I can get an MD5/SHA-whatever hash of your password, then I can just run it against rainbow tables that are widely available for download and have any user’s password in seconds. Unless, of course, the hash is salted - but we won’t get into that now.

So, you may think you’re doing your user’s a favor by enforcing strict password requirements, but you’re not. I would simply require a minimum of 8 characters and leave it at that. Want to know how to generate an very secure, yet easy to remember password? Check it out! http://xkcd.com/936/

Also, as a side note, if you ever find a website that emails you your password in plain text, I would panic! This means they have it in plain text in their database as well. Never use a password you care about with one of these websites. And make sure you send them many angry emails!