Cody Fendant has asked for the
wisdom of the Perl Monks concerning the following question:

I've written a simple forum, using DBI, HTML::Template and CGI::Session.

It wasn't intended to be a professional product, it was just for a small group of people who can all be trusted. But what if it goes live to a wider audience?

What would you do to harden that application against people who might URL-hack or otherwise try to exploit weaknesses?

To give one example: if I've made a post, I can edit it. The Edit Post URL is foo.com/edit/123. And that's fine because I wrote post 123. What if I change the URL to 122? Can I edit someone else's post? What if I use that URL to edit my own post 123 then change the hidden form field value to 122? Can I save post 123 into post 122?

Now, I'm quoting those because I've thought of them. And I can trivially code for them. If the user id != the user id who made the post, etc. But as they say, everyone is clever enough to invent a code that they can't break themselves...

(I should say by the way that my DBI database calls all use placeholders, no interpolation of variables, so I don't think I'm vulnerable to the Bobby Tables kind of problem. But tell me if that's not enough.)

What principles or procedures should I follow to identify and prevent that kind of exploit?

Addressing "principles" first (but directing this response to your broad question on exploitation, rather than to the specific examples of potential problems): the simplest may be to use existing, well-tested OS forum s/w. Rolling your own with even a glimmer of a possibility of opening its use to other than those who "can all be trusted" is either:

An example of the triumph of hope over experience or

A long-term committment to bug-erradication; hole-plugging; and user-hand-holding

This is off topic from the original post, but I have a slight (hopefully constructive) criticism about your URL structure. Is the editor or the post the resource? In my mind, the post is the resource you are making available, and the editor is an action that you want to do to that resource.

May I suggest that perhaps the URL should be reversed: http://example.com/123/edit? The article ID is the identifier for everything else that happens to that resource.

Whether or not you adhere to REST or some other method of organizing your resources, I posit that having the ID first will make it easier to manage your application in the future.

I have built several applications in which the URLs that are generated for a page consist of a URL consisting simply of GUID=xxxx-xxx-xxxx..... As the page links are generated within the application, they are stored in a hash by GUID – generated on-the-spot for one-time use – and that hash is saved in the session information. This creates an impenetrable href, but also one that cannot be meaningfully “farmed,” either by Google or by the competition. (The Google-unfriendliness can be viewed as either a good thing, or a bad thing, as the business case may be.)

A hybrid technique might use a more “Google friendly” URL structure, e.g. like the one commonly used by WordPress or Moveable Type based forums, but with the addition of such a code. If the code is omitted or is not valid for any reason, the software might present a “sanitized” version of the page. If you generate an XML sitemap file, it would omit all codes, so that Google would not generate any links involving them.

This technique, while not perfect, does reduce the number of times you must do page-access validation. As long as the inbound request has a valid code, and the IP-address has not changed, and the page is not highly sensitive, you can get away with just the code-check. (Naturally, you will use “hardened” session cookies, courtesy of many CPAN modules that will generate them for you, and you will verify that the connection uses HTTPS.)

When putting a smiley right before a closing parenthesis, do you:

Use two parentheses: (Like this: :) )
Use one parenthesis: (Like this: :)
Reverse direction of the smiley: (Like this: (: )
Use angle/square brackets instead of parentheses
Use C-style commenting to set the smiley off from the closing parenthesis
Make the smiley a dunce: (:>
I disapprove of emoticons
Other