Honeypots: better than CAPTCHAs?

[17 January 2008]

As noted earlier, the short period of time between starting a blog and encountering comment spam has now passed, for this blog. And while the volume of comment spam is currently very low by most standards, for once I’d like to get out in front of a problem.

So when not otherwise committed, I spent most of yesterday reading about various comment-spam countermeasures, starting with those recommended by those who commented on my earlier post. (More comments on that post, faster, than on any other post yet: clearly the topic hit a nerve.)

If you’re keeping score, I decided ultimately to install Spam Karma 2, in part because my colleague Dom Hazaël-Massieux uses it, so I hope I can lean on him for support.

But the most interesting idea I encountered was certainly the one mentioned here by Lars Marius Garshol (to whom thanks). The full exposition of the idea by Ned Batchelder is perfectly clear (and to be recommended), but the gist can be sumarized thus:

  • Some comment spam comes from humans hired to create it.
  • Some spam comes from “playback bots” which learn the structure of a comment form once (with human assistance) and then post comments repeatedly, substituting link spam into selected fields.
  • Some comment spam comes from “form-filling bots”, which read the form and put more or less appropriate data into more or less the right fields, apparently guiding their behavior by field type and/or name.

For the first (human) kind of spam, there isn’t much you can do (says Batchelder). You can’t prevent it reliably. You can use rel="nofollow" in an attempt to discourage them, but Michael Hampton has argued in a spirited essay on rel="nofollow" that in fact nofollow doesn’t discourage spammers. By now that claim is more an empirical observation than a prediction. By making it harder to manipulate search engine rankings, rel="nofollow" makes spammers think it even more urgent (says Hampton) to get functional links into other places where people may click on them.

But I can nevertheless understand the inclination to use rel="nofollow": it’s not unreasonable to feel that if people are going to deface your site, you’d at least like to ensure their search engine ranking doesn’t benefit from the vandalism.

And of course, you can also always delete their comments manually when you see them.

For the playback bots, Batchelder uses a clever combination of hashing and a local secret to fight back: if you change the names of fields in the form, by hashing the original names together with a time stamp and possibly the requestor’s IP address, then (a) you can detect comments submitted a suspiciously long time after the comment form was downloaded, and (b) you can prevent the site-specific script from being deployed to an army of robots at different IP addresses.

My colleague Liam Quin has pointed out that this risks some inconvenience to real readers. If someone starts to write a comment on a post, then breaks off to head for the airport, and finally finishes editing their comment and submitting it after reaching their hotel at the other end of a journey, then not only will several hours have passed, but their IP number will have changed. Liam and I both travel a lot, so it may be easy for us to overestimate the frequency with which that happens in the population at large, but it’s an issue. And users behind some proxy servers (including those at hotels) will frequently appear to shift their IP addresses in a quirky and capricious manner.

For form-filling bots, Batchelder uses invisible fields as ‘honeypots’. These aren’t hidden fields (which won’t deceive bots, because they know about them), but fields created in such a way that they are not visible to the sighted human users. Since humans don’t see them, humans won’t fill them out, while a form-filling bot will see them and (in accordance with its nature) will fill them out. This gives the program which handles comment submissions a convenient test: if there’s new data in the honeytrap field, the comment is pretty certain to be spam.

Batchelder proposes a wide variety of methods for making fields invisible: CSS style “display: none” or “font-size: 0”, positioning the field absolutely and then carefully positioning an opaque image or something else opaque over it. And we haven’t even gotten into Javascript yet.

For the sake of users with Javascript turned off and/or CSS-impaired browsers, the field will be labeled “Please leave this field blank; it’s here to catch spambots” or something similar.

In some ways, the invisible-honeypot idea seems to resemble the idea of CAPTCHAs. In both cases, the human + computer system requesting something from a server is requested to perform some unpredictable task which a bot acting alone will find difficult. In the case of CAPTCHAs, the task is typically character-recognition from an image, or answering a simple question in natural language. In the case of the honeypot, the task is calculating whether a reasonably correct browser’s implementation of Javascript and CSS will or will not render a given field in such a way that a human will perceive it. This problem may be soluble, in the general case or in many common cases, by a program acting alone, but by far the simplest way to perform it is to display the page in the usual way and let a human look to see whether the field is visible or not. That is, unlike a conventional CAPTCHA, a honeypot input field demands a task which the browser and human are going to be performing anyway.

The first question that came to my mind was “But wait. What about screen readers? Do typical screen readers do Javascript? CSS?”

My colleagues in the Web Accessibility Initiative tell me the answer is pretty much a firm “Sometimes.” Most screen readers (they tell me) do Javascript; behavior for constructs like CSS display: none apparently varies. (Everyone presumably agrees that a screen reader shouldn’t read material so marked, but some readers do; either their developers disagree or they haven’t yet gotten around to making the right thing happen.) You do want to be sure, if you use this technique, to make sure the “Please leave empty” label is associated with the field in a way that will be clear to screen readers and the like. (Of course, this holds for all field labels, not just labels for invisible fields. See Techniques for WCAG 2.0 and Understanding WCAG 2.0 for more on this topic.)

The upshot appears to be:

  • For sighted or unsighted readers with Javascript and/or CSS processing supported by their software and turned on, a honeypot of this kind is unseen / unheard / unperceived (unless something goes wrong), and incurs no measurable cost to the human. The cost of the extra CSS or Javascript processing by the machine is probably measurable but negligeable.
  • For human readers whose browsers and/or readers don’t do Javascript and/or CSS, the cost incurred by a honeypot of this kind is (a) some clutter on the page and (b) perhaps a moment of distraction while the reader wonders “But why put a field there if you want me to leave it blank?” or “But how can putting a data entry field here help to catch spambots?” For most users, I guess this cost is comparable to that of a CAPTCHA, possibly lower. For users excluded by a CAPTCHA (unsighted users asked to read an image, linguistically hesitant users asked to perform in a language not necessarily their own), the cost of a honeypot seems likely to be either a little lower than that of a CAPTCHA, or a lot lower.

I’m not an accessibility expert, and I haven’t thought about this for very long. But it sure looks like a great idea to me, superior to CAPTCHAs for many users, and no worse than CAPTCHAs (as far as I can now tell) for anyone.

If this blog used homebrew software, I’d surely apply these techniques for resisting comment spam. And I think I can figure out how to modify WordPress to use some of them, if I ever get the time. But I didn’t see any off-the-shelf plugins for WordPress that use them. (It’s possible that Bad Behavior uses these or similar techniques, but I haven’t been able to get a clear idea of what it does, and it has what looks like a misguided affinity for the idea of blacklists, on which I have given up. As Mark Pilgrim points out, when we fight link spam, we might as well try to learn from the experience of fighting spam in other media.)

Is there a catch? Am I missing something?

What’s not to like?

A nicer editing environment

Since starting this worklog, I’ve been experimenting using the screen that WordPress provides for writing blog posts.

It’s good to see every now and then how the other half lives.

And I’m impressed: the blog editing screen WordPress gives you is significantly better than a poke in the eye with a sharp stick, which distinguishes it from some other systems I have experienced.

But, well, not so nice that anyone could plausibly expect me to use it instead of Emacs. So today I decided it was time to get a bit more realistic about how to draft posts, particularly those that are tricky and that I want to get right. That means, I need a way to edit in Xemacs, using psgml.el’s XML mode, and conveniently upload to WordPress.

The editing-in-Xemacs part is easy. All I have to do is stop not doing it. What was needed was a stylesheet to translate from the version of TEI Lite I habitually use for writing, into the odd mix of normal XHTML and blank lines for paragraph breaks that WordPress uses. (I should probably experiment with using normal p elements — will WordPress let me use them?)

Answer: yes. So I don’t have to render paragraphs using just blank lines. And I didn’t really need to do a new stylesheet; I could just have used my existing TEI-to-HTML translation. I’ll comfort myself with the thought that the new stylesheet is smaller and has less cruft.

It’s still a little awkward that I have to cut and paste from my Emacs buffer into the WordPress write-post screen; I notice that David Carlisle seems to be able to edit existing posts from within emacs, using T. V. Raman’s g-client package. This makes me jealous, but not jealous enough to drop everything to work on an emacs mode for posts to WordPress. (Everything I haven’t already dropped in order to play with my tei-to-wordpress stylesheet and to write this post, that is.)

When the cut-and-paste gets annoying enough, I’ll take the time to make the stylesheet generate the post in Web-forms submission format, and write a script to upload to the server. But for now, being back in emacs for editing is enough.

Spam Karma 2 installed

Installed Spam Karma 2, today, and hope it deals well with comments from real readers (who are welcome here) and from spambots and spammers (who are not).

There are a few points that have caused a little concern.

When I ran the filters on the accumulated comments and spam, it took half of the spam comments and approved them as OK.

I’m going to give it the benefit of the doubt for now, assuming that it’s using some sort of Bayesian filtering that needs training. If this is still happening a month from now, it will be harder to be patient.

You can of course review approved comments and say “No! bad choice! that one is spam.” And similarly you can review the spam bucket and say that something is not actually spam.

It was at this point that I almost turned it off again, after ten minutes of use. It’s set up to display the lists of recently harvested spam and approved comments in a concise tabular form, with the admirable goal of getting more data onto the screen, and to expand any cell in the table if you hover over it, so as to show the full entry.

Perhaps my browser is set up to call the hover() method more quickly that the developer expects, but I found it impossible to move my mouse across the table (e.g. to reach the scroll bar, or to reach a cell I wanted to hover over) without one cell after the other exploding, shifting text around on my screen, and then collapsing again. It reminded me of nothing so much as flying as a child in a Cessna or Piper Cub and hitting air pockets that caused the plane to fall precipitously, climb again, and then drop again. I can almost smell that unforgettable stench of high-test fuel in an small enclosed space.

The only way I could reach something I wanted to hover over and look at was to sneak up on it by moving my mouse cautiously down the left or right margin and then into the table. And even then, it only expands one cell at a time, so you don’t get a good overview of any individual comment and its content and karma rating.

Fortunately, you can turn the hover behavior off. You have to turn on ‘Advanced’ options and uncheck the box that says “if using … css-impaired browsers, you should disable this feature”. It doesn’t mention susceptibility to motion-sickness.

The table of recently harvested spam is labeled as including comments with karma lower than -20; the threshold can be changed, and I’m glad to have a clear statement of what’s displayed and what’s not. But I found it confusing to have comments with karma of -6 and whatnot included. Eventually I concluded that the screen meant “higher” than -20.

The beauty of open source is that I was able to correct that typo without any significant effort.

The display of information about recently harvested spam with bad karma is as close to illegible as a mere color scheme can make it. (Well, that’s too harsh; I’ve seen worse, but not in a color scheme intended for actual use.) Dark green and medium-dark red against dark gray.

The beauty of open source is, again, I can change it. I’ve got CSS and I’m not afraid to use it.

And finally, the author has announced that he doesn’t expect to update it, because he’s tired of incompatible changes to WordPress that break plugins.

I can see his point. But any problem caused by his decision is down the road a while; perhaps others will pick up the code, or perhaps I’ll shift to a different tool later, just for educational purposes (the way I change Emacs color themes every few months or so, to see how they wear over time).

On the other hand, despite the concerns, Spam Karma appears quite popular and successful, and to have attracted fewer vehement denunciations than some other anti-spam tools. So the official attitude here is the traditional guarded optimism.

We will learn, as time goes by, whether that optimism is justified.

19 comments in one weekend!

[15 January 2008]

This morning I was a bit surprised to see nineteen comments on various blog posts waiting for moderation here. I hadn’t realized that such a queue had been built up since Friday, or that so many new people had discovered this blog and wanted to comment.

My slight flush of self-congratulation at the success of the blog lasted only a few moments, as long as it took to notice that of the nineteen comments eighteen were clearly spam, and the nineteenth is almost certainly spam (I’m going to sleep on that one).

Dealing with persistent spam attacks could take a lot of the pleasure out of maintaining a blog, just as dealing with spam made email an unbearable drain on my time before I started my white list. Time to spend some time investigating the blog-spam control tools available to me.

NetNews and netnews (and net news)

[11 January 2008]

Clash of Expectations Department

Having incautiously decided to spend a little time this afternoon catching up on the blogs I optimistically subscribed to during the quiet days of the winter holidays, I spent a large part of the afternoon downloading what look like a lot of nifty Mac applications, having been led to a handy list of Mac OS X freeware by Bob Sutor’s link. I then encountered Tim Bray talking about something called NetNewsWire, which some people seem to regard as a pretty slick way to read news feeds.

This got me excited. Mostly, I’m pretty happy with my current setup, but after an afternoon of looking at software sites talking happily about how nice their GUIs are and how they’re better than their competition, I thought “Wow, a modern, up to date app for news? Cool. I should look at it! Maybe it’s better than what I’ve got!”

I looked at it.

And suddenly in a very short time I went from feeling kind of perky and with-it, with all my new apps downloaded (although not installed), to knowing that I am a dinosaur, still alive and kicking but clearly, inalterably different from all these mammals running around here.

You may already be guessing the awful truth. From the name NetNewsWire, and from the comments of Tim and others about reading news, and news feeds, and so on, I had been expecting not a reader for RSS and Atom feeds — I’m sure it’s a very nice one, but as far as I can tell I have three or four pieces of software for reading RSS and Atom already on my system, not counting the one I installed myself — but, well, a reader for netnews. By which any self-respecting dinosaur means, of course: a reader for NNTP feeds.

Fortunately, gnus still works fine for me.

(And for news news over the net, the NY Times daily headlines work fine for me, though actually I still get most of my real news from the Journal and the New Mexican and from National Public Radio.)