Article Author: Henrik Ingo
Introduction
If you read The Christmas 2004 ASP Today Special Story, you’ll recall that Otro C. Oder’s, coding practices were so bad that he was paid a visit by the first two Ghosts of Christmas, who taught Otro a little about how to take advantage of VS features to improve his coding. Well a few days ago it was another year on, Christmas Day 2005, and while Otro might have become more adept at things like documentation, consistent variable names, and using his web.config correctly, he’s still causing not only other developers but also his clients a lot of problems by forgetting some basic web usability and security issues. Rumour has it that a couple of the websites he developed have even gone down because things were so bad, though Otro hasn’t yet heard those rumours. At any rate, the third ghost has decided it’s time to come visit Otro, and he will teach Otro a few things. So I hope you are all sitting comfortable, perhaps with some coffee or hot chocolate at your side, and now we can go and rejoin Otro where we left him, another year on.
In particular, the third ghost will take Otro to places where he’ll learn about
- Basic usability. Why a "back" link is unnecessary and why breadcrumbs (SiteMapPath in ASP.NET 2.0) are a good thing
- What problems may arise from putting everything on your page into the same form element
- A reminder of the basic security practises in being a Windows administrator
- What might happen if you neglect to pay attention to usability and security
But now, let me give the stage to the third ghost, who is soon going to visit Otro, once he wakes up.
System Requirements
This story discusses usability and security on a rather general level, but some of the features discussed are in respect to ASP.NET 2.0. The example code provided was done with Visual Web Developer 2005 Express Edition, but should work in any ASP.NET environment.
The examples are in C#, but the things taught here are actually important in all languages, even outside the .NET world.
Installing and Compiling the Sample Code
The zip-file attached contains a simple ASP.NET website, with the two pages you’ll see in this story. You can use it if you want to see for yourself that what is being said is true. The files are simple aspx files to be dropped into a directory on your website and there are no other requirements than the web server supporting ASP.NET 2.0. If you want to see the Feedback form actually being sent, you should also have a mail server configured and running.
Stave 3. The Last of the Spirits
Otro woke up very early on Christmas morning, with the teachings of the two spirits from last year still clearly in his mind. Surely, with all the things they had shown him, coding had been so different. Otro had made a solemn decision to better his ways, and he was in fact now always looking forward to getting back to the office to put in practice everything he had learned. He was a changed man, and to have that feeling on a bright Christmas morning, well, that’s something, I can tell you.
There was one little thing still troubling Otro – why had there been only two spirits, when everyone knows there are three ghosts of Christmas. After some thought he decided that obviously he’d taken his lessons in a lot better than that – whassisname – Ebeneezer guy, and so there was no need for a third spirit. Feeling comforted at this thought – and if I might say so, I personally felt the expression on Otro’s face was just a teensy bit too smug – he strolled towards the window to witness the clear and crisp weather and the small spirals of smoke rising from the chimneys outside. From his apartment window he could see the ice glittering on the ground below.
And sure enough – because as you’ve probably guessed already, since these kinds of Christmas stories are often quite easy to predict, – that’s when a big garbage truck floated down from the sky, stopping to hover right outside Otro’s recently installed windows! And having parked his truck, the driver opened the door and floated out slowly, gravely, and silently. He (it?) was shrouded in a deep black garment, which concealed its head, its face, its form, and left nothing of it visible save one outstretched arm with a memory pointer at the end of it. The very air through which this Spirit moved seemed to scatter gloom and mystery. But for this it would have been difficult to detach its figure from the night, and separate it from the darkness by which it was surrounded.
It was the Garbage Collector.
Now if you have ever met a ghost yourself, you’ll know how scared Otro felt right now. It doesn’t even help if you’ve already met two nice ghosts who have taught you so many wonderful things and put you in a nice Christmas mood, it’s still frightening the third time. So that’s why Otro just stood there, unable to move and unable say anything at all. He did notice though that the Spirit was carrying a metallic trash can under his left arm – the bit bucket, where the Garbage Collector would put all freed memory he collected. Meanwhile the Spirit floated away from the hovering truck, opened up a dialog box in one of Otro’s apartment windows, and stepped through it into Otro’s bedroom.
"I am in the presence of the Ghost of Christmas Yet To Come?" Otro finally got out of his mouth. The Spirit didn’t talk, but just pointed at his truck.
"Ehh… You have come here to show me something more I must learn. And it’s in your truck?" Otro spoke in a doubtful voice, confused and waiting for an explanation. But the Garbage Collector just silently and steadfastly pointed at the truck, and although the place where his eyes would have been was just two empty hollows, it was like he was staring demandingly at Otro.
So without really seeing any logic to it, Otro started walking towards the truck, out through the dialog box, floated in the air and finally sat in the passenger seat. The Garbage Collector quickly reclaimed some memory that was ready to be freed on Otro’s laptop, then followed and sat on the driver’s seat. And off they went, accelerating along the information superhighway out into cyberspace.
Basic Usability,: Breadcrumbs and "back"-links
"So I know as the third ghost, you won’t talk to me, but I just want to say, I’m already thankful for the advice I hope you will give me, just as I am for the useful things your predecessors taught me. So are you going to show me things that have not yet happened, but that might happen if I don’t change my ways? Because believe me, your friends The Spirit of Christmas Past and The Spirit of Christmas Present already did a good job, and I have already decided to change my coding practices. What is it that you still wish to teach me?"
While Otro was nervously babbling to the spirit, the truck slowed down and drove through the wall of some office complex with workers sitting in their cubicles, and the spirit beckoned Otro out of the truck and along to a particular cubicle occupied by one worker. Along the way Otro just managed to catch some glimpses of some computer screens with Visual Studio 2005 running – which made it clear these people must be developers. The person they finally stopped behind was engaged in a Microsoft Messenger chat, apparently talking about an e-commerce site that had suddenly had to shut down and go offline:
Simon says: No, I heard it’s offline for good.
Bill says: When did that happen?
Simon says: Don’t know exactly, I just heard about it. ‘Bout time too if you ask me. I was starting to wonder if it was ever going to die.
Bill says: Me too. I always thought it was terribly badly designed.
Simon says: Hey Doc, you still there? You should write something about it for your useit.com site – classic example of how not to create a website?
DrNielsen says: It was a good example of all the usability mistakes you should never do. For instance, it was one of the few websites still insisting on providing a "back" link at the bottom of each page.
Simon says: Yeah I meant put the lecture on your site, you don’t need to tell us.
Bill says: No go on Doc. You never know who might come and read this chat. LOL!
DrNielsen says: :-)
DrNielsen says: It’s a small thing really, but so unnecessary. And it’s confusing, because often the link is implemented such, that it doesn’t at all take you back to your previous page, but instead to something that in the site developer’s personal logic is a preceding page.
Bill says: True. It always confused me. I would often come to that site following an external link from some other website. Of course when I clicked "Back" I didn’t get back to the page I came from, but "back" to some starting page of the site itself.
DrNielsen says: And even if the link actually would take you back to the same page as the browsers back button (for instance, as implemented by a simple JavaScript history.go(-1); ) it’s still unnecessary. Usability studies have shown, that the back button is probably the second best known computer function right after the act of clicking a link itself, it’s the one thing everybody knows how to use.
Simon says: That statistic of our dear Dr is probably quite true. I know I never use those links ever. The browser has a back button, and I know how to use that when needed.
Bill says: But that was not the real problem really. I mean, it’s just a link, it doesn’t by itself explain why I would always get lost on the site. Somehow I always lost track of where I was.
Simon says: Put your hands in the air, Simple Simon says, Shake them all about, Simple Simon says,
At this point the Spirit suddenly moved closer to the screen, studying it closely and with its outstretched memory pointer hovering threateningly. After a few moments it gave up, frustrated. The problem was an invalid pointer variable in some unmanaged code, so there was nothing the Garbage Collector could do to help.
DrNielsen says: My favorite quote: "users don’t understand where they are in a website’s information architecture." (http://www.useit.com/alertbox/20000109.html)
DrNielsen says: It would have helped you, if the developer had used breadcrumbs . You know, a trail of links that show you where you are in the site hierarchy. Like: Home >> Programming >> ASP.NET
Simon says: He really should have just upgraded to ASP.NET 2.0 a long time ago. There you get breadcrumbs simply by inserting the SiteMapPath control from the Navigation category in the Toolbox .
Simon says: I just recently read an article about that in ASP Today: http://www.asptoday.com/Content.aspx?id=2316
Bill says: Do you ever miss an opportunity to promote that site of yours?
Simon says: No. Do you ever miss an opportunity to tie people into your products by not quite following the standards?
DrNielsen says: Children!
DrNielsen says: Breadcrumbs, in all their simplicity, are really one of the most ingenious navigational enhancements a site can have. They are simple, don’t need a lot of space and give the user some perspective on "where" he is. If you can get it with that little effort, there is really no excuse for not using them.
Problems with Enclosing the Whole Page in One Big Form Element
Otro’s attention was briefly distracted by a couple of emails floating down. The Spirit carefully examined them, and placed the genuine ones in the bit bucket, but allowing the spam ones to continue on their way. Then the Spirit motioned to Otro to keep following the conversation.
DrNielsen says: I’m sorry, now I’m ranting about usability again. What can I do, it’s me you know…
Bill says: That’s ok. It’s always interesting to hear from you.
Simon says: And, it’s wise to learn from others mistakes. Maybe it’s the one good thing we’ll get from that site.
DrNielsen says: Well I have to admit, I bought some Christmas presents from there myself last year. Am I really the only one of us who actually used that site?
Bill says: Hey! For all we know, you might have been their only paying customer :-)
DrNielsen says: LOL :-D
DrNielsen says: But I understand your sentiments. Apart from usability, the site really had some other serious bugs too. I remember I used to get logged out sometimes, even if I had just logged in, so it wasn’t a session timeout or anything. That was really annoying.
Simon says: Ahh… I think I know why that was. It’s actually kind of a usability thing too. I’ve seen it happen in other places as well.
Simon says: You see, in ASP.NET, a developer often just throws various controls onto the page, maybe writing some action handlers, and then leaving the rest to the system. Typically he lets Visual Studio just enclose everything on the page into one form element.
Simon says: The problem is then, that within that one big form, you might have controls that actually don’t belong together at all. For instance, you might have a field for searching, and then again, you often have a logout button.
DrNielsen says: I think I see where this is heading. Do they really do websites like that still… ?
Simon says: Oh shut up :-)
Simon says: Well, in one way it’s understandable that it happens, because ASP.NET kind of indirectly encourages you to do so. Let me guess, you use Firefox?
DrNielsen says: I do.
Simon says: Now, as long as the user uses the mouse to click on the right buttons, let’s say Search or Logout, everything works fine. Typically a developer will have coded some action into the Click event handler for those buttons, because that’s what you get in Visual Studio when you double click on the button. But many users just hit enter to submit a form, especially for simple forms like a search query.
Simon says: And that’s were it get’s interesting. The three major browsers (Internet Explorer, Firefox, Opera) all work differently on this one. Internet Explorer sends the data for all the fields, the text in the search field in this case, but not the values of any of the buttons.
DrNielsen says: In my opinion this is what I’d expect a browser to do. If I didn’t click the button I didn’t click the button.
Simon says: I agree. But as I said, and especially due to the way VS.NET guides you to do things, a novice web developer might easily end up placing the functionality into the Click event handler of the button. Now the button was never clicked, so nothing happens.
Bill says: But surely, every ASP.NET developer will test their site at least with Internet Explorer?
Simon says: Probably true, but they might just click on the button during the test, and never notice this problem. On the other hand, you’re right. Many will notice this problem and do something about it.
DrNielsen says: But that still leaves us with the other browsers. Boy, could I give you a sermon about the importance of testing with ALL browsers!
Simon says: Yes I know you could :-) So next in line is Firefox. If you press enter, Firefox for reasons I don’t understand, includes the value of the submit button in the posted data, whether it actually was clicked or not. If there are more than one submit button (which is allowed in HTML), it pretends you clicked the one that appears first in the HTML code for that individual form.
DrNielsen says: That makes sense, that’s why it kept logging me out, it always happened when I had submitted a form with pressing enter.
Simon says: Right. It’s pretty common to place the logout function somewhere in the header of the page, so that button will then be the first and Firefox generates a click on it.
Simon says: It’s an issue we’ve wrestled with ourselves on ASP Today but still haven’t quite solved for our logout button thanks to some legacy code.
Simon says: Opera is pretty interesting. Clearly they have noticed and thought about this problem, but it’s beyond me why they decided to go their own way. As you said, the Internet Explorer approach is probably to be deemed the correct one. They should have copied that one.
Simon says: So what Opera does is, it tries to intelligently deduce which of the submit buttons is closest to wherever you are pressing Enter, and sends that submit button together with the form data.
DrNielsen says: And most of the time that probably "does the right thing", but regrettably, it’s a very unpredictable approach.
Simon says: Actually talking about that, you might enjoy this. I was researching this a while back and I came up with a short demonstration. Let me see if I can find it and show you. brb.
Simon says: Got it. I’ll share my browser window for you to see…

Figure 1. Web page with two submit buttons in one form element.
Simon says: In case you are interested, here is the code for that page. This is what you get when you just toss in the controls into the visual ASP.NET developer…
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"> <title>Untitled Page</title>
</head>
<body> <form id="form1" runat="server"> <div> <asp:Button ID="ButtonLogout" runat="server" Text="Logout" OnClick="ButtonLogout_Click" /><br /> Some content here…<br /> <hr /> You can search our site here:<br /> Search: <asp:TextBox ID="TextSearch" runat="server" /> <asp:Button ID="ButtonSearch" runat="server" Text="Search" OnClick="ButtonSearch_Click" /> <br /> <br /> <asp:Label ID="LabelSearchResults" runat="server"></asp:Label><br /> <br /> Write something into the search box, and press enter.<br />
[…]
</div>
</form>
</body>
</html>
Simon says: And the event handlers are in the code behind page…
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
{ protected void Page_Load(object sender, EventArgs e) { } protected void ButtonLogout_Click(object sender, EventArgs e) { Button b = (Button)sender; if (b.Text.Equals("Logout")) { b.Text = "Login"; } else { b.Text = "Logout"; } } protected void ButtonSearch_Click(object sender, EventArgs e) { LabelSearchResults.Text = "Search results for ‘" + TextSearch.Text + "’:<br /><br />Result1<br />Result2"; }
}
Bill says: Okay then, I should be going now, but now I really want to know, what is the solution to all this? What should a developer like me do?
DrNielsen says: Well, of course the correct solution is to use more than one form on each page. You should only put things that belong together into the same form element. To have only one form per page is a completely artificial limitation.
Simon says: The sad thing is, ASP.NET’s elegance kind of relies on the server-side processing of many things, and for that you need to have everything inside that one form. For some reason, you cannot have two server-side forms, that results in an error. Thanks for that limitation btw, not looking at anyone here in particualar.
Simon looks at Bill
Simon says: Of course you can have more than one form on the page, but only one of them can be server-side. So for the other ones you have to process the POST data yourself, like in old style ASP.
Bill says: Hmm… I always preferred the ASP.NET way. So there is no trick I could use to keep me from falling back to old-style ASP?
Simon says: Not really. Of course, there are things you can do, but… In this particular example, you could move the code inside the Search button event handler to the Page_Load() method. In fact, you probably should do that anyway because after that Internet Explorer works as expected. But that’s just this particular example, it’s not a real solution. And you’d still have a problem with Firefox logging you out all the time.
Simon says: And to solve that, you’d have to move the Logout button so it’s not the first one on the page. In order for "Search" to be the default when enter is used, it should be the first Submit button on the page. And that’s kind of backwards don’t you think? Deciding your layout based on some quirk of your framework…
DrNielsen says: Stop, stop! Such a horrendeous thought! Don’t you dare ever suggest something like that again!!!
Simon says :-)
DrNielsen says: So it seems we have found an unfortunate effect that is the result of a) that the browser developers of days gone by have decided to pretend a button is clicked when it is not, and Firefox is sticking to this behaviour and Opera on the other hand is being too clever about it and b) this weird obsession on the part of ASP.NET to only have one (server-side) form per page.
Simon says: In fact, it is a very artificial limitation of ASP.NET. I blame people at Microsoft for this! I don’t think there is a really good reason why I couldn’t have more than one server side form.
Bill says: But hey, who’s to say the Logout has to be a button? Couldn’t it be just a regular link, and you’d be safe from all this trouble?
Simon says: Maybe so. But, as I said, the real solution is, that you can and maybe it’s safe to say you should always have more than one form element per page if needed. And sadly only one of them can be server-side. For the others you need to use the traditional HTML controls and process the form data yourself.
Bill says: So maybe I’ll do that from now on then. But now I really have to go. Thanks for the lesson and Merry Christmas to both of you!
DrNielsen says: Likewise, Merry Christmas indeed!!!
Simon says: See you <:-)
The Spirit motioned a now thoughtful Otro back into the truck and they sped off again.
The Very Basic Security Advice We All Tend to Forget
While Otro was still reflecting on the dialogue he had just witnessed, the truck again slowed down and the Spirit pointed to Otro to get out. There was an IRC (Internet Relay Chat, the earliest form of realtime Internet chat and the predecessor to instant messaging) chat going on between two Debian Linux users. Otro supposed this was what the Garbage Collector wanted him to see and settled down to watch.. Meanwhile the GC Spirit moved off to examine a couple of stray bits of memory.
<Ian> Yeah, I heard about it too. Broken into by crackers. Apparently they had neglected to install security updates on their servers.
<LNXNerd> Hah. Those Windows servers are always plagued by worms.
<Ian> I’ve hardened my Debian box myself, and made a script that apt-get upgrade ‘s automatically each night, so the system is always up to date and secure.
<LNXNerd> Another reason why Linux is more secure, is that you don’t run as root unless you have to do some administrative job. Part of the Linux culture – I’ve never understood why Windows devs don’t make more effort in that regard. Windows users make it too easy for viruses to spread by using the Administrator account as the main user account!
<Ian> Sure, that too. But anyway, who cares… it’s not my problem :-)
<LNXNerd> Mine neither! Still stupid though, from what I’ve heard it’s so easy to work more sensibly even in Windows. Despite even Microsoft advises you not to do it, people still work as administrator. I’ve heard Windows guys complain it’s hard to keep logging out and back in again when you need admin rights for something and that’s why they always keep themselves permanently logged in as administrators, but that’s rubbish. Apparently if you ight click on any shortcut on the desktop or Start menu, you’d find the Run as command, which allows you to easily start programs as the administrator when you need to. That way you can spend most of your time running as an ordinary user with just the privileges you need to do your job. (On some systems you might need to hold down SHIFT while right clicking).
<Ian> Anyway, now I have to go skating, Deb is already ready to go and waiting for me. Wanna join us?
<LNXNerd> You live near a skating rink that’s open on Christmas day????
<LNXNerd> But nah, I’m not much of a skater.
* LNXNerd has to go and compile the newest kernel.
<Ian> Ok. Cu later.
<LNXNerd> cu
"That’s dialog wasn’t fair!" Otro exclaimed to the ghost. "Windows has had automatic security updates for years already. You don’t even need to write any scripts to get them, it’s an automatic function in Windows itself!"
Well I can tell you at that point, if it was possible for the air around the Spirit to get even colder and more tense, it did. The Spirit abruptly gestured and Otro found they’d instantly moved to another location. Another featureless office with a couple of suits clustered around the computer, evidently flustered. Otro thought the office looked a bit familiar but he couldn’t place it. Perhaps he’d been there a while ago on one of his visits to clients he’d written websites for.
"How the F*** did that worm get on to this server?" one of the suits was demanding angrily. I thought Microsoft released that patch that fixed that over a year ago?" There was a pause. Otro couldn’t see what he was doing but heard various mouse clicks and keys being pressed. Then "This machine’s got automatic updates disabled. When did it last have an update?" More clicks. "I know I shouldn’t moan, after all we’re still getting paid our 2000 bucks an hour to fix this but I can’t believe they’d call us out for something so silly." More clicks then a different voice. "Look, there’s something in the readme.txt file here. Ummmm- Disabled automatic updates temporarily because OtrosUtilities2.1.dll doesn’t work with latest Windows update. TODO: Fix this soon. Otro, 5 August 2002"
There was a silence. Otro glanced around the room, evidently trying to find anywhere to look that didn’t involve looking at the spirit. He eventually settled for looking at his feet, but even that couldn’t stop the feeling of the Spirit’s eyes on him. Finally he spoke, a little defensively. "Well look, at least I left a note about it in the documentation file. You can’t fault me on that."
The icy silence from the Spirit was only broken when the Spirit suddenly noticed a big pile of data structures lying around. Seeing that they were not used anymore, He jumped out of the truck to do his duty and shoveled the data into the back of the truck, after which he continued their journey with Otro.
The Crackers and Their Nasty Tricks, and How to Guard Against Them
The Garbage Collector now steered his truck right into the most obscure parts of cyberspace. This was the place Otro had heard about, but certainly had and wanted nothing to do with: virus writers, internet worms, crackers and their spambots, which they used to controll zombie PC’s taken over by the vorms. The Garbage Collector parked right by another ongoing IRC chat. Would they have anything to say about the unfortunate server the other characters had been talking about?
*** K3EPItCl,an has joined #the_den
*** LaundryS3rvIcE has joined #the_den
*** The_Undertak3r has joined #the_den
<Joe> Was expecting you. Welcome.
<K3EPItCl,an> I put out the newest Ice Girls album as mp3 files on p2p last night. You can download it from me if you want.
<LaundryS3rvIcE> But that album isn’t out in another 2 weeks?
<K3EPItCl,an> I know, but I found it in the database of MyTunes.com. They already had it there although it was not made public yet.
<The_Undertak3r> So how did you break in?
<K3EPItCl,an> Quite easily really. It’s so simple it’s not even worth calling a break in. I just wrote http://mytunes.com/secureDirectory%5Cicegirls.aspx into the address bar instead of the normal http://mytunes.com/secureDirectory/icegirls.aspx. And there it was, I was in, despite the page being blocked.
<K3EPItCl,an> This was posted on securityfocus.com ages ago: http://www.securityfocus.com/bid/11342/discuss But hey, if you don’t update your systems, what can a cracker do…
<Joe> Good work K3!
* LaundryS3rvIcE goes and downloads Ice Girls unreleased album
<LaundryS3rvIcE> Hey, small world! I broke in at that same site too. I used a simple SQL injection attack.
<Joe> They were vulnerable to that as well!!!?
<LaundryS3rvIcE> Sure they were. I just typed ‘ OR 1=1; —
<LaundryS3rvIcE> …into the username field and that got me in.
<Joe> Hah. Here we have been making websites for over a decade, and people still haven’t learned to use parameterised SQL queries!
<The_Undertak3r> The funniest thing is, in all of the educational material I see, especially the reference material on MSDN, they always teach people to use SqlCommand and SqlParameter classes to do proper parameterized queries.
<Joe> Just wait till the LINQ project and C# 3.0/VB9 come out – Microsoft are going to make it even easier and more tempting for people to write non-parameterized queries. Boy am I looking forward to that!
<LaundryS3rvIcE> …but then people just read it and think: "This looks unnecessary complex, I’ll just do what I always do and toss together the string with a simple string concatenation like
<LaundryS3rvIcE> "SELECT * FROM Users WHERE username=’" + username.Text + "’ AND password=’" + password.Text + "’;";
<The_Undertak3r> Now you’re just showing off.
<LaundryS3rvIcE> Of couse it didn’t stop there. Once I got in, I discovered they had not encrypted the passwords at all, they were all stored as plaintext in the database.
<LaundryS3rvIcE> So I looked up the site administrator’s password, and sure enough, he uses the same password everywhere, so I visited his online bank account and…
<K3EPItCl,an> …Merry Xmas to Laundryservice then!
<Joe> And imagine that only one line of code would have been needed to add FormsAuthentication.HashPasswordForStoringInConfigFile() and he would still have his savings in the bank.
<LaundryS3rvIcE> Yeah. I’ve always loved the name of that function by the way. With such a long name, no wonder nobody is using it. Especially since the "InConfigFile" part may lead you to believe you can’t use it to hash passwords stored in the database!
<The_Undertak3r> I made a few bucks out of that site too you know.
<The_Undertak3r> Not that I had to even break in at all. I just made a little script that uses their feedback form to send spam, and then I sold that script to some friends I have in Nigeria.
<Joe> So they can now send a lot of spam to the webmaster? What’s the point of that…
<The_Undertak3r> Don’t be silly :-) Of course it can be used to send spam to anyone.
<The_Undertak3r> You see, I realised that the feedback form, in addition to the field for the message itself, also contained a hidden field for the To: address, where the feedback is supposed to be sent.
<The_Undertak3r> Although this is completely unnecessary – and stupid, of course – some sites do that, because then you can change that address from the html or the Visual Studio graphical layout, instead of having to go to the C# code or your Web.config file, which would be the right place to store that.
<The_Undertak3r> But when they unnecessarily put the address into the browser like that, it’s easy for me to change it if I want to. Using <input type="hidden"> for the field doesn’t help much, I can easily make a script to change that.
<The_Undertak3r> I’ll just send
POST /Feedback.aspx HTTP/1.1 Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6 Accept: text/html
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.example.com/Feedback.aspx
Content-Type: application/x-www-form-urlencoded Content-Length: 255
to=someonesaddress@wherever.com&message=Message%20here…&Send=Send
<The_Undertak3r> In fact I don’t even need a script, I can just save the page from my broswer and edit it by hand if I want to. And of course the same goes for select , checkbox and radio elements as well.
<The_Undertak3r> So lately I’ve been scanning the net for feedback forms implemented badly like that. Spammers pay good money for them actually.
<LaundryS3rvIcE> Oh you are so mean. At least I didn’t take money from anyone else but the site’s administrator. I’m sure many of the other passwords could have been used at the bank as well, but I didn’t want to harm any innocent bystanders for the programmers’ stupidity!
<The_Undertak3r> What harm is there in a little spam each day? And don’t blame me, I’m not the one developing websites with so many gaping holes in them…
<The_Undertak3r> Anyway, I’ve uploaded a simple Feedback.aspx to the zip file accompanying this story, just in case you want to test this.

Figure 2. A Feedback form with the recipient address in a hidden form.
protected void Send_Click(object sender, EventArgs e)
{
//This innocent looking code can be used to spew spam
// out on the internet.
//You should be very careful in accepting mail recipients
//from the user.
//Often it’s better to have them specified on the server side
//just hardcoded as a variable or more elegantly in Web.config
//In no case should unauthenticated users be allowed to do that!
//And remember, a hidden field is not really a secret!
System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage();
msg.To = to.Value;
msg.Body = message.Text;
//Here the mail goes, if you have an SMTP server running that is
System.Web.Mail.SmtpMail.Send(msg);
}
<LaundryS3rvIcE> OK So who’s doing the showing off now eh?
Otro was now witnessing the crackers’ chat in cold sweat. He realised, the crackers might be talking about a site he himself had developed. Thus he would be guilty not of having put the site’s data in jeopardy, not to mention his customer’s passwords and worst of all, it seemed he might be partly to blame for the Internet’s spam problem as well. And that might actually also explain, why this server had had to be taken offline by its internet service provider.
The Garbage Dump
"Spectre" Otro said, "something informs me that our parting moment is at hand. I don’t know how I know that, but I feel it. Before that, please tell me, was that really my website these people were talking about? I need to know, because I feel I might be the one to be blamed for all of the faults they are talking about."
Again the Garbage Collector said nothing. He just continued driving, until the truck finally stopped again. They had now reached… the garbage dump.
After unloading all the bits from the back of the truck, the Garbage Collector made a gesture for Otro to follow him, and started walking right across.
They passed a big heap of code that looked like the old Netscape browser. "That figures" Otro mumbled to himself "here’s where software comes to die I guess." He then wondered, how the Netscape code actually got there, since being an application from the first half of the 90’s, it surely wasn’t written in a managed language, so the Garbage Collector certainly hadn’t automatically brought it here. But maybe old C++ applications got to the garbage dump by calling delete themselves and maybe those that forgot to do so were doomed to leak out into cyberspace, producing all kinds of mysterious unexplained phenomena in people’s computers. Then Otro realised, that this was probably not why the Ghost had taken him here, and walked on, fearing the worst…
The Garbage Collector had now stopped at the far away corner of the garbage dump, and was pointing at a small pile of what seemed to be some dead spaghetti code.
"So I see you are showing me exactly what I was fearing: It is my own code that has ended up here in the graveyard of software and I now see it was completely unmaintainable, ugly to use and full of holes. This is the website those crackers broke into and those others found to be buggy and lacking in usability."
"So tell me Ghost, please, before you leave, answer me one question. Are these the shadows of the things that will be, or are they shadows of things that may be, only?"
The Spirit was as immovable as ever.
Good Spirit," Otro pursued, "Assure me that I yet may change these shadows you have shown me, by an altered life! I will honour good coding practises in my heart, and learn to make more secure websites. I will learn from the Past, the Present, and the Future. The Spirits of all Three shall strive within me. I will not shut out the lessons that they teach. Oh, tell me that I still have a chance of writing software that will not end up here!"
He was down on his knees, crying in front of the ghost, anxiously pulling at the leg of his black overall. Crying and praying the spirit to give him one more change, the Garbage Collector suddenly started fading in his eyes, and the garbage dump around them disappeared…
The End of It
…and as he looked up again, he was back home, cold sweat running from his forehead and tears on his cheeks, lying on his bedroom floor and pulling vigorously at the window curtains. "YES!" Otro shouted, "I’m home again."
As he pulled the curtains to the side and opened windows, he looked out at the bright Christmas morning and inhaled the crisp cool winter air. He also thought, slightly nervously, that if the Spirit had been showing him a future that could be avoided, then he, Otro, had a few things to do. He took a deep breath, put on his headphones, and opened Skype. A few seconds later, he was leaving a message. "Hi, Otro here . Yeah it’s about your MyTunes.com site I was working on. I was just checking something today and noticed a couple of issues with it that need updating. Can you give me a ring and let me know when it’ll be convenient to call round? Thanks! There’s no charge." A few minutes later he hung up the call and sat back trying to figure out which of his former clients would need to be checked out again in the light of what the Spirit had shown him.
"And next year," Otro thought, "when my friends and collagues get back to work, I’m going to tell them of my adventures with the three spirits, for I now understand that the security of the Internet is a task we must bear collectively, helping and educating each other, every day of the year."
Because it being Christmas and all, it is good to remember that we are not alone in the world, and anything we do, good or bad, affects many other people as well.
Conclusion
In this second part of this Virtual Christmas Carol series, the Third Ghost of Christmas taught Otro some basic things about usability and security. Otro learned that a "back" link is an unnecessary duplication of a function the browser is better at, and that breadcrumbs really help a user in navigating a site. He also learned that putting everything on a page into the same form element, as he was used to doing, might lead to strange problems, which are different in different browsers.
Otro was then shortly reminded of two very simple but often neglected things: That it really is important to keep installing those security updates and that you really mustn’t use the Administrator account for your daily work, but only starting applications as Administrator with the Run as command when needed.
Then he was terrified to learn how easy it is to break into a site that has not been duly updated. He also learned from the crackers how much damage can be done with an SQL injection attack, and that using parameterised SQL queries is a good defense against that. Now he also knows, why you really should not store passwords as plaintext, but rather use a hash function to encrypt them. Finally he learned that you should be careful when coding feedback forms or other forms that are sent by mail, because spammers are looking for ways to misuse such forms.
The most important thing about security was the realisation, that neglecting to pay attention to security might hurt other people more than yourself. So as web developers we should all be responsible citizens of the net, and take security seriously.
Note: The characters in this story are entirely fictional. Any similarity in the names to the names of any real people is entirely coincidental. Well OK it might have been a deliberate coincidence.The dialog in this article is by ASP Today and not necessarily approved by any individuals with similar names.

