Learning Go with AppEngine

Sat 06 April 2013 by Peter Ward

I’ve been meaning to learn Go for a while, and I had a nice opportunity today to do that. But before I talk about Go, let me explain why I was writing a Go program in the first place.

Last night, I saw that Alex (a friend of mine) had written a little website for unicode faces called textfac.es. At the moment, you need to ask him to add new faces, but there’s a dynamic voting system: every time you click on a face, that’s counted as a vote.

Of course, with such a simple voting system, it’s pretty obvious that it’s going to be exploitable in various ways, so I set out to explore some of them. The first thing to do is to have a look at how clicks translate into votes in the browser. Looking at the JavaScript, I saw (essentially) this:

var faces = $("button.facebtn");

clip.on("mousedown", function(client, args) {
    var id = $(this).attr("face-id")
    $.ajax("/increment?id=" + id);
});

Which means that when you click it, it sends a GET request to a URL like http://textfac.es/increment?id=37.

The attack I didn’t do

The obvious thing to do would be to run a brute-force attack to increment the count as much as possible, like this:

$ while true; do wget -qO - http://textfac.es/increment?id=37 &>/dev/null; done

Bor-ing.

Not only that, it’s also very easy to block with a per-ip rate limit (which was put in place). I wanted to be more subtle about it, and make it more difficult to identify whether it was spam or not.

My first attack

Having voting happen by a GET request is clearly a mistake. According to RFC2616 (Section 9.1.1), GET requests should not change any state on the server:

In particular, the convention has been established that the GET and
HEAD methods SHOULD NOT have the significance of taking an action
other than retrieval. These methods ought to be considered "safe".

What this means is that it’s fairly easy to get a browser to send a GET request for you, since the browser "knows" it’s a harmless request.

And so, I added a little bit of HTML to the bottom of all the pages of my blog:

<img src="http://textfac.es/increment?id=37" style="display:none" />

Then I needed to generate some traffic, so I wrote a blog post (that I had been meaning to write for a while) and posted it to Google+, Twitter and Facebook.

So if you were one of the nice people who visited my blog since last night, your browser helpfully loaded that "image" with a GET request, thus casting a vote using your IP. Why thank you, random stranger!

My second attack, with Go!

Great, this generated some traffic, and I was sitting at #5 for a while. But I wanted to get higher up, and so I had the thought: you know, it would be really nice if I could use Google’s network to spam the voting system for me…

I knew that it was possible to make outbound web requests with AppEngine, and I’d been meaning to write something in Go for a while, so this seemed like a good excuse.

I just needed to write a simple application to take a url and a number, and send that many GET requests to the url. Easy, peasy.

So I wrote that, and then did some testing, and discovered that there was still only a fairly limited number of IPs which it would generate traffic from, though I could vary the IPs by changing where my request to AppEngine came from.

My final variation was to hard-code the url and number, and to use that in an img tag on my blog, so that the requests to AppEngine would be from a diverse IP range. I have no idea if that’s actually working or not!

Finally he gets onto actually talking about Go…

I only ran into two interesting things with Go. The first one was when I was doing authentication: I wanted to restrict it to a set of valid logins, which basically meant testing to see if a list contained a certain item.

I was very surprised that Go doesn’t have a builtin function for this, I don’t really expect to have to write linear search in 2013. I did find someone’s recipe for this on the golang-nuts mailing list, which I shamelessly stole^Wappropriated.

On this topic, it’s quite possible that the Go language does has this built in, and I just didn’t find it: while the documentation does appear to be complete, I didn’t find it anywhere near as readable or searchable as the Python documentation (hmmm, I think Python spoils me).

The other thing which I found interesting was that Go doesn’t have a map() primitive using goroutines. While it’s not overly difficult to express the same thing with channels, I felt that my code would have looked cleaner.

Here’s a contrived example using explicit goroutines and channels:

func square(x int, ch chan int) {
    ch <- x * x
}

func main() {
    n := 10

    ch := make(chan int)

    for i := 0; i < n; i++ {
        go square(i, ch)
    }

    sum := 0
    for i := 0; i < n; i++ {
        sum += <-ch
    }
}

And here’s what the equivalent code would look like with a concurrent map function:

func square(x int) int {
    return x * x
}

func main() {
    values := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

    results := go_map(values, square)

    sum := 0
    for _, v := range results {
        sum += v
    }
}

Of course, I could have left that last example as pseudocode, but I didn’t like that, so I wrote out an implementation of go_map. Unfortunately, my go-fu isn’t at the point where I can write a generic version for any type. Perhaps someone will write one, and leave a note in the comments. Even better, perhaps someone will point out that this already exists in the standard library somewhere?

func go_map_wrap(x int, fn func(int) int, ch chan int) {
    ch <- fn(x)
}

func go_map(values []int, fn func(int) int) []int {
    results := make([]int, len(values))

    ch := make(chan int)

    for _, v := range values {
        go go_map_wrap(v, fn, ch)
    }

    for i := 0; i < len(values); i++ {
        results[i] = <-ch
    }

    return results
}

Epilogue

By the way, that last complaint wasn’t because I’m a functional programming nut or anything, it’s because I wanted to send off N concurrent web requests, and it seemed like a pain to have to manually manage the channel.

On the whole I do like Go, and in my book it’s up with Vala and Scheme as nice languages. Python is still vastly more usable, but it’s likely a language which I’ll use again in the future.

P.S: Alex is not an awful developer! He did realise the hole when he initially coded it, and just didn’t get around to fixing it until I started messing around. So don’t blame him, he’s awesome.


Introducing gst-launch-dynamic

Fri 05 April 2013 by Peter Ward

I thought it would probably be a good idea to write posts about the random projects I do. As it happens, this particular post is about a tool which still could do with more work, but is in a reasonable enough state to present to the world. I’ve got ...

read more

Blackmagic DeckLink, ConsoleKit and TTYs

Tue 19 February 2013 by Peter Ward

Regular readers may skip this blog post, it’s being posted so people find the solution when the google it, not because it’s interesting.

I had a computer with a Blackmagic capture card, and discovered that it wouldn’t shut down properly. After tracing my way through PolicyKit, I ...

read more

Shell startup scripts

Sun 17 February 2013 by Peter Ward

If you’re a regular shell user, you’ve almost certainly got a .bash_profile or .bashrc script in your home folder, which usually contains various tweaks, such as setting environment variables (adding that directory to $PATH), telling your shell to do clever things (like set -o noclobber) and adding various ...

read more

PSA: Hotmail is Borken

Sat 09 February 2013 by Peter Ward

I’ve just debugged an issue where someone was trying to send an email to my domain, and got back an error message, which they took to mean that the email address no longer existed.

Of the very little debugging information I managed to get out, was this snippet (some ...

read more

Controlling Projectors with PJLink

Fri 30 November 2012 by Peter Ward

I regularly need to control a data projector, and previously the only way to do this has been using a web interface created by the manufacturer. Of course the interface is, while usable, poorly designed, and somewhat sluggish.

Fortunately, there’s a protocol for controlling projectors, PJLink, but unfortunately, there ...

read more

Awesome + GNOME Configuration

Wed 28 November 2012 by Peter Ward

I was recently prompted to publish my configuration for integrating GNOME and awesome. At the time I wrote this setup, the awesome wiki was recommending a configuration which didn’t correctly autostart applications, nor integrate well with anything expecting to find a session manager. However, it now contains instructions for ...

read more

Prettify script for PC^2

Sat 17 November 2012 by Peter Ward

When I was doing programming competitions at uni, I wrote this script, which takes the default HTML output from PC^2 and add some colour to it to indicate passed / failed problems. Since it was written / enhanced on the day of the competition, there’s definitely some hacky code in ...

read more

End of Honours

Thu 15 November 2012 by Peter Ward

Well, I’ve handed in my thesis (Providing Useful Feedback to Beginner Programmers), and done a presentation for it (twice, for logistical reasons), so I’ve now finished everything I need to do for uni! I’m very happy about this, and I’ve been enjoying the little bubble of ...

read more

gvfs-gphoto2-volume-monitor Memory Usage

Sun 11 November 2012 by Peter Ward

I’ve noticed over the past few weeks that occasionally there was a gvfs-gphoto2-volume-monitor process taking an unreasonable amount of memory. Since my computer just ran out of memory, I was prompted to investigate why, and here’s what I found.

I’m not sure how much of this is ...

read more