Tuesday, 27 January 2015

Overcoming Developer's Block

You know how it is - however brilliant you are, however experienced, sometimes your code just doesn't work the way it's supposed to. You trawl through your code, looking for a syntax or logical error. You find nothing. But you know it has to be there.

The dreaded Developer's Block. It's not quite the same as Writer's Block. With Writer's Block, the writer has no idea what to write, or how to proceed. With Developer's Block, the developer already has the specifications (and if you don't, boy, your problems are far bigger) but midway through coding, something went wrong. Not only do you not know how to fix it, you may not even know what the problem is!

We're not going to address debugging techniques here, or common rules of thumb. Everyone's got their own rules, and I'm sure, on their day, they're very effective.

But the rule I'm going to present here may just be the most important of all. The last resort.

Walk Away

That's it? "Walk away"? I can imagine some of you snickering right now.

No kidding! Well it's certainly the simplest way I can put it, so allow me to elaborate with examples. Below is a paraphrased conversation between me and a fellow developer colleague. He was experiencing the dreaded Developer's Block and tearing his hair out.

Him: I don't know what's wrong. This output looks weird! But no error message!

Me: Hmmm. Let me have a look.

(a minute passes)

Me: Abang, this is a nested For Loop. How come inner and outer loop are using the same variable?

Him: Oh my God. You're a genius! I've been looking at this for hours. You come in for five minutes and find the problem right away!

Me: I'm not a genius, and I'm not better than you. I just haven't been looking at this damn thing for hours.

And that's the simple truth. Focus is good, but when you concentrate too hard and too long, you risk getting tunnel vision, or, more poetically, "missing the forest for the trees". Walking away, or taking a break, helps your brain reboot. Of course, the best way to reboot would be a nice 8 hour nap, but failing that, 10 to 15 minutes potentially works just as well.


Take a break

Take a walk. Have a smoke. Go cake the porcelain. Or take a walk to the loo and have a smoke while caking the porcelain. Whatever you do, keep your eyes away from the computer screen. The answer, or at least a path to that answer, will arrive when you least expect it. Many times I gave up in frustration and left the office for dinner, only to have the answer pop, unbidden, in my head through my first mouthful!

Tackling the mental wall

Think of your problem as a concrete wall. At the risk of sounding cliched, you don't need to keep banging your head against the wall, hoping to break through. You can just as easily go over, around, or under it. Or you could think about it further and realize that you don't actually have to deal with that wall in the first place!

That's enough for now! I'm gonna take a walk and... cake the porcelain.
T___T

Monday, 19 January 2015

Film Review: Blackhat

I caught Blackhat over the weekend, because the title promised to be a film about hackers. And because the producers cleverly used a hacking term as the title, I badly wanted to like this film. Instead, I left the theater with mixed feelings.


It turned out not so much to be a film about hackers, but an action film involving hackers.

The Premise

A power plant in China is hacked into and destroyed. Agent Chen Dawai (played with a mixture of sternness and elegance by Wang Leehom) is sent to investigate, and deduces that the code that opened the backdoor for the hackers was written by him and his then-roommate, Nick Hathaway (an incredibly buff Chris Hemsworth), who is currently doing time for some cybercrime. He pulls some strings to get Hathaway out of jail to help in the investigation.

Warning: Possible spoilers ahead!

And thus you have been warned. Let's get on with the review, shall we?

The Characters

Wang Leehom is stoic and serious as Chen Dawai. Came across as intelligent and a stand-up guy. But somehow very stiff. He looked uncomfortable being in the movie.

Chris Hemsworth as Nick Hathaway, the bad-ass genius hacker, is just a little too unbelievably awesome. Fine, I can buy him being one hell of a programmer. I can buy him being impossibly gorgeous and oozing machismo, with a body that could only be described as "godlike". (Oh wait...)  Slick fighting skills? Could have picked those up in prison. Knowing how to use a gun? Still plausible. But using it with enough skill to single-handedly dispatch all the bad guys who had gunned down his entire team? Er....

Tang Wei played Chen Lien, Chen Dawai's sister. I felt it was a waste of screen time. Undeniably eye candy, but her role didn't extend beyond giving Hemsworth's character someone to sleep with and carrying out certain plot points which could just as easily have been executed by Wang Leehom's character. And seriously, for crying out loud, if you're going to turn her into a sex object anyway, why's she fully clothed in every sex scene? Where is the smoking hot body that made her so famous in Lust, Caution?

Adrian Pang and Andy On had short-lived cameos here. The presence of Andy On, in particular, raised an eyebrow from me. Didn't I last see him in True Legend and Special ID as the main villain?

The Mood

It alternated between The Matrix and The Bourne Identity. Slick and sophisticated with the techie scenes, grim and gritty with the fight scenes. Not that I'm complaining, really. But at one point, I'd had enough with the whole fetish the filmmakers seemed to have with zooming up close whenever a hack was made, past the screen and into the inner circuitry. Were those guys aiming to show the entire 7 layers of the OSI Model or something?

What I liked

The dialogue had some gems. Nick Hathaway's method of negotiation speaks to me. Here are some examples:

Agent: This isn't a negotiation.
Hathaway: Well, I just made it one!

Mook: You want to speak with the boss? This is not possible.
Hathaway: I'm holding all of his money. Make it possible.

I also liked the way the characters were uneasy allies at first, suspicious of each other, and eventually grew on each other. Enough for Hathaway to feel bad when the woman constantly busting his balls early in the film, gets gunned down later.

And the locations! Oh, the locations! The languages! Going from China, to USA, then to Hong Kong and finally Malaysia. Mandarin, English, Cantonese and Malay. This felt like such a cultural experience.

Hathaway also pulls off some nifty identity theft in the movie. Nicely done.

What I didn't

The bad guys had bullets that could pierce through steel and kill Andy On's character, and Hathaway somehow thinks wearing some magazines and newspapers as body armor will help? What the hell?

Conclusion

Nice idea. Had its flaws. Could've been done better. And sure as hell didn't require the presence of Tang Wei's character. Kept me entertained, but not a show I'd watch again.

My Rating

5.5 / 10

Ah well, what the hack.
T___T

Friday, 16 January 2015

Web Tutorial: Google Blog HTML/JavaScript Random Quotes Gadget (Part 2/2)

You'll have noticed by now that the gadget title always shows the current day of the week, along with a funky description. That's no coincidence, and we'll be tinkering more with arrays - this time multi-dimensional arrays. We'll also be messing about with the JavaScript date function.

Date functions: (http://www.w3schools.com/js/js_date_methods.asp)
Multi-dimensional arrays: (http://www.quackit.com/javascript/tutorial/two_dimensional_arrays.cfm)

Now what we need to do first, is get the id of your JavaScript gadget div. Right click and view source on your blog's main page, and do a search for the title of your gadget (in my case, it's "RandomQuote").

Screenshot


Found it? OK, in this case, the id is HTML1. Your mileage may vary. We'll need the id for some Document Object Model (DOM) manipulation later. Firstly, we get today's date and retrieve the day from it, like so.
<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";

document.getElementById("txtQuote").innerHTML=quotes[Math.floor(Math.random() * (quotes.length-1))];

var d = new Date();
var day=d.getDay();

</script> 

Next, we define an array weekdays that stores the names of the days. Sunday starts from 0, all the way to Saturday, which is 7.
<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";
document.getElementById("txtQuote").innerHTML=quotes[Math.floor(Math.random() * (quotes.length-1))];

var d = new Date();
var day=d.getDay();

var daynames=new Array();
daynames[0]="Sunday";
daynames[1]="Monday";
daynames[2]="Tuesday";
daynames[3]="Wednesday";
daynames[4]="Thursday";
daynames[5]="Friday";
daynames[6]="Saturday";
</script> 

Now, we're going to define another array, descriptors, which has the same number of elements as the array weekdays. But with a difference. It's a multi-dimensional array. Each weekday has different descriptors, right? So do the following (this is just an example, make your own descriptors!).
<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";

document.getElementById("txtQuote").innerHTML=quotes[Math.floor(Math.random() * (quotes.length-1))];

var d = new Date();
var day=d.getDay();

var daynames=new Array();
daynames[0]="Sunday";
daynames[1]="Monday";
daynames[2]="Tuesday";
daynames[3]="Wednesday";
daynames[4]="Thursday";
daynames[5]="Friday";
daynames[6]="Saturday";

var descriptors=new Array();
descriptors[0]=new Array("Serene","Supreme","Sonorous","Silent","Sleepy");
descriptors[1]=new Array("Manic","Majestic","Monstrous","Mysterious","Magical");
descriptors[2]=new Array("Twitchy","Twisted","Tenacious","Tempestous","Terse");
descriptors[3]=new Array("Wicked","Wonderful","Whimsical","Whirlwind","Wishful");
descriptors[4]=new Array("Terrific","Thunderous","Torrid","Tepid","Tingly");
descriptors[5]=new Array("Fantastic","Friendly","Furious","Freaky","Frenetic");
descriptors[6]=new Array("Sizzling","Salacious","Sinister","Silky","Scintillating");

</script>

You'll see that each element in the descriptors array is also an array, and stores all the different descriptors for that particular weekday. So now you add in this line.
<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";

document.getElementById("txtQuote").innerHTML=quotes[Math.floor(Math.random() * (quotes.length-1))];

var d = new Date();
var day=d.getDay();

var daynames=new Array();
daynames[0]="Sunday";
daynames[1]="Monday";
daynames[2]="Tuesday";
daynames[3]="Wednesday";
daynames[4]="Thursday";
daynames[5]="Friday";
daynames[6]="Saturday";

var descriptors=new Array();
descriptors[0]=new Array("Serene","Supreme","Sonorous","Silent","Sleepy");
descriptors[1]=new Array("Manic","Majestic","Monstrous","Mysterious","Magical");
descriptors[2]=new Array("Twitchy","Twisted","Tenacious","Tempestous","Terse");
descriptors[3]=new Array("Wicked","Wonderful","Whimsical","Whirlwind","Wishful");
descriptors[4]=new Array("Terrific","Thunderous","Torrid","Tepid","Tingly");
descriptors[5]=new Array("Fantastic","Friendly","Furious","Freaky","Frenetic");
descriptors[6]=new Array("Sizzling","Salacious","Sinister","Silky","Scintillating");

var textdiv=document.getElementById("HTML1");

var replacetext=textdiv.innerHTML;
replacetext=replacetext.replace("RandomQuote",descriptors[day][Math.floor(Math.random() * (descriptors[day].length-1))]+" "+daynames[day]);
textdiv.innerHTML=replacetext;
</script>

This creates a string based on a randomly-selected descriptor descriptors[day][Math.floor(Math.random() * (descriptors[day].length-1))] and pairs it with the weekday daynames[day]. Then the innerHTML value of your entire gadget is extracted (using the id HTML1) and the word RandomQuote is replaced by the entire composite string using the replace() method!

For more on the replace() function, click here. (http://www.w3schools.com/jsref/jsref_replace.asp)

And there you go. Click Save, and you should be set. I know the code's not very friendly to read, but you're a smart chap (well, you are reading this blog, so you definitely have good taste), you'll figure it out eventually. This method is definitely hackish though, so I wouldn't recommend it if you're skittish about possibly breaking something. In fact, extrapolating from what we did, you'll have a good idea of how to deface a website using an XSS attack.

That's it! Hope you had a ball.
T___T

Thursday, 15 January 2015

Web Tutorial: Google Blog HTML/JavaScript Random Quotes Gadget (Part 1/2)

Howdy, folks.

Today, we're going to mess around with Google's blog gadgets. In particular, the HTML/JavaScript gadget.

Some of you may have noticed that every time you refresh this blog, the quote changes!

The HTML/JavaScript
gadget on this blog
It takes a certain amount of maneuvering, but ultimately it's nothing extremely fancy. Those of you with a Google blog may want to try this.

First, create a HTML/JavaScript gadget using the interface.

The gadget creation interface


Now, in the content, enter the following HTML tags.
<div id="txtQuote">

</div> 

The txtQuote div is meant to store the quote. Now, we're going to prepare the JavaScript, like so.
<div id="txtQuote">

</div>

<script>

</script>

This script uses arrays and randomizer functions, so if you're not familiar with either, go do some reading at the links below.

Arrays: (http://www.w3schools.com/js/js_arrays.asp)
Randomizer: (http://www.w3schools.com/jsref/jsref_random.asp)

First, we declare an array quotes.
<div id="txtQuote">

</div>

<script>
var quotes=new Array();
</script>

Then we populate the array.
<div id="txtQuote">

</div>

<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";   
</script>

Fill it up with whatever you like. I'm primarily using quotes from footballers. (Because I'm a football nut. Shut up.) So now, are we done? No, we've just finished filling up the depository which the script will use to populate the txtQuote div. Now we're going to write the code that randomly picks one of these quotes.
<script>
var quotes=new Array();
quotes[0]="\"In 1969 I gave up women and alcohol. It was the worst 20 minutes of my life.\" - George Best";
quotes[1]="\"Some people believe football is a matter of life and death. I am very disappointed with that attitude. I can assure you it is much, much more important than that.\" - Bill Shankly";
quotes[2]="\"They say 'go with the flow', but you know what else goes with the flow? Dead fish.\" - Roy Keane";
quotes[3]="\"Behind every kick of the ball there has to be a thought.\" - Dennis Bergkamp";
quotes[4]="\"Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do.\" - Pele";

document.getElementById("txtQuote").innerHTML=quotes[Math.floor(Math.random() * (quotes.length-1))]; 
</script>

The code Math.floor(Math.random() * x) gets a random number from 0 to the number of items in the array quotes, minus 1. In this case, x is 4 (you have five quotes, yes, but programmers tend to count from zero!). So when you say Math.floor(Math.random() * (quotes.length-1)), you're referring to a random element within the quotes array.

document.getElementById("txtQuote").innerHTML= assigns the innerHTML value of txtQuotes to the randomly selected quote.

Save, and we're done. Refresh the page any number of times you'd like, and watch the quote change!

Next 

Changing the gadget title.

Friday, 9 January 2015

The Bowline Bend Analogy

Following the web tutorial for the Wayang Progress Bar posted last year, I received some feedback from a reader. And because I take all feedback seriously (OK fine, I take some feedback seriously) I've decided to dedicate a blog post to this.

The reader stated that she did not bother with the tutorial because the end result wasn't something she would use anyway - if a page takes more than 10 seconds to load, she'd consider it a failure. That point of view is valid; however, she may be approaching this from the wrong angle.

To explain my statement, I'm going to use what I call the Bowline Bend Analogy.

The What?

Back in 1999, I was a crew member on board a warship in the Republic of Singapore Navy. The Executive Officer (XO) decided to test one of the Junior Officers (JO).

XO: What's the Bowline used for?
JO: To make a non-slip loop, Sir.
XO: Can the Bowline be used to join two lines?
JO: Er...
XO: Corporal, can the Bowline be used to join two lines?
Me: Yes Sir.

This is a Bowline

Later, the Junior Officer pressed me for details for the question he was tested with earlier.

JO: How can the Bowline be used to join two lines? It's not a joining knot, it's a loop knot!
Me: You just tie two Bowlines and interlock them, Sir.
JO: What the hell?! That's a trick question!
Me: Well, yes and no. Yes in the sense that it tests your knowledge of the Bowline and all other loop knots, and no in the sense that there actually is such a knot...
JO: Yes, fine, whatever.


This is a Bowline Bend


Two interlocking Bowlines, otherwise known as the Bowline Bend, was actually a valid way to join two lines. It leveraged on the excellent breaking strength of the Bowline to create a knot with similar breaking strength. Its use has been somewhat deprecated as there have been found equally sound ways of joining lines without using that much rope. But, in order to understand the use of the Bowline Bend, first, one has to have a pretty good grasp of the Bowline! In other words, you can't tie a Bowline Bend without first knowing how to tie a Bowline. And while the Bowline Bend isn't that useful, the Bowline certainly is.

The Junior Officer wasn't being tested on his ability to tie a Bowline. Any crewman, right down to the lowliest Private, can tie a crummy Bowline. He was being tested on his understanding of how the Bowline worked. He didn't need to learn how to tie a Bowline Bend. He only needed to know that such a thing was possible.

And back to the Wayang Progress Bar...

That's where the web tutorial comes in.

You may not think you need a Wayang Progress Bar. In fact, you may never need a Wayang Progress Bar. But the whole point wasn't about the Wayang Progress Bar. The Wayang Progress Bar leveraged on several smaller building blocks that were combined in a certain way for the final product, much the same way that two Bowlines were combined to give you the Bowline Bend!

Therefore, the whole point here was to learn all the little snippets (HTML, CSS, JavaScript) that made up the final product. In future, these building blocks can be used to make something else altogether. And that, again, was the real point of the exercise.

Keep your feedback coming. I will knot turn you away!
T___T

Saturday, 3 January 2015

The Great Widget Falsification

For the past week, Singapore's internet space has been abuzz with the entire war between blogger Xiaxue and various Gushcloud bloggers. To go into the whys and wherefores would take up way too much of my valuable time; plus it's not really what I want to talk about today.

Some Background

An entity known as SMRT Feedback  - not, to my knowledge, associated with Gushcloud - has accused Xiaxue of falsifying her web-counter.

I quote:
Firstly, the stats counter has been rigged to increase +1 per second. Any web developer will be able to tell you that, based on the JavaScript coding that was used to deliver that function.

This accusation was followed rapidly by a defence by ThemissingA. In the blogpost is this:
This is the coding on Xiaxue’s blog. If anyone else would like to see for themselves, you can go to her page, right-click, and select “view page source” (confirmed for Chrome, not sure how to do this on other browsers). This is the section that contains her counter. Notice that the widget’s source is blogger.com. So, using this information, I deduce that the counter is more than likely a tool supplied by blogger.com. Anyways, I set up my own blog to see how it’s done.

This was preceded and followed by screenshots of the blogger viewing the source. And the source looked fairly harmless without actually going into the JavaScript behind the widget.

And he concluded with this:
1. Xiaxue did not create the coding for her counter. It was supplied to her by blogger.com, which is owned by Google Inc.
2. Blogger.com (and, by extension, Google) supplies this widget to ALL of its bloggers.
3. If the counter is rigged, that rests entirely on the shoulders of GOOGLE, NOT XIAXUE. It also means that ANYONE using blogger (which, if I’m not wrong, comprises of the majority of Singapore’s blogging community) is also at fault for “rigging” their counters.


ThemissingA claims that since the source of the page doesn't show any funny business at the HTML level, Xiaxue must be innocent. He's totally missing the point. And, given that he set up a blog just to defend Xiaxue, possibly his marbles.

Let's assume that the widget's code is untouched. Yes that's a fairly big assumption as these go, but bear with me. It is still possible to manipulate it without directly interfering with the widget.

Challenge accepted!

This isn't a web tutorial, so I'm not going to delve into the code. I'm just going to give you an idea of what I attempted. First, I created a web-counter for this blog using Google's gadget creation interface. Next, I created a HTML/JavaScript gadget, input some innocuous text message followed by a JavaScript segment.

Preparing some hacky goodness

See the code I put in there? Here's the entire chunk.

<script>

setInterval(function () {
var totalcountbox=document.getElementById("Stats1_totalCount");
var totalcount=totalcountbox.innerHTML;
for (i=1;i<=10;i++)
{
totalcount=totalcount.replace("<span class=\"digit stage-0\">","");
totalcount=totalcount.replace("<span class=\"blind-plate\">","");
totalcount=totalcount.replace("<strong>","");
totalcount=totalcount.replace("</strong>","");
totalcount=totalcount.replace("</span>","");
}

if (totalcount!="")
{
totalcount=parseInt(totalcount)+1;
totalcount=totalcount+"";

var newcount="";
for (i=0;i<totalcount.length;i++)
{
newcount=newcount+"<span class=\"digit stage-0\"><strong>"+totalcount.charAt(i)+"</strong><span class=\"blind-plate\"></span></span>";
}
totalcountbox.innerHTML=newcount;
}
}, 60000);
</script>

I refreshed my blog, and viola! I had a web-counter that increased by 1 every minute.

What does this prove?

No, it doesn't prove Xiaxue's guilt. It just puts a huge dent in ThemissingA's defence. Looking at the HTML source tells you nothing.

Disclaimer

Xiaxue fans who are preparing to lynch me for this, you can un-bunch your knickers. I never said she was guilty. I only said it was possible. And I wasn't even trying particularly hard. This is just a surface-level hack and won't stand up to scrutiny after refreshing the page. The code was clunky and cobbled together in 15 minutes. I'm sure any programmer worth his salt can do better, given time.

So what?

Precisely. Let's assume (again with the assumptions!) that Xiaxue is indeed guilty of falsifying her web-counter. So what? Do people actually believe web-counters nowadays, given that I've just demonstrated how ridiculously easy it is to manipulate them? The 90s called, dude. They want their cutesy vanity widgets back.

Now how's that for a counter-argument?
T___T

Thursday, 1 January 2015

Thoughts on the Website Defacements in 2013

Happy 2015! Wishing you happiness safety and health! In whichever order of preference!

Last month, a Singaporean by the name of Mohammad Azhar bin Tahir was jailed for defacing the Prime Minister's official website. in 2013. This was in addition to the case of Delson Moo, who was fined SGD 8000 for a similar offense, this one concerning the Istana.

This is what happened to the PM's official website:

Screenshot 1


This is what happened to the Istana website:

Screenshot 2


The Singapore Police Force website was also defaced with an overlay of an image of two men engaging in explicit buttsex having an intense bonding moment. No, I'm not going to show you a screencap, pervert.

The Technical Specifics 

The attacks were classified as a kind of Cross-Site Scripting (XSS) attack, where the attacker used the Search bar of the website to input codes that would overlay an image on top of the website, thus defacing it.

More about XSS: http://en.wikipedia.org/wiki/Cross-site_scripting

Infocomm Development Authority of Singapore (IDA) claimed that the web sites were not hacked as both the Prime Minister's Office and Istana main sites were still working. Technically, they are correct - server data was not compromised and any damage done was on a superficial level. But it would be a mistake to say that the damage done was only on a superficial level. These were Government websites, and the Government (particularly those responsible for the website) was made to look like a bunch of rank amateurs. There is no "only" superficial damage.

Especially when you consider that the Prime Minister's official website was compromised not long after Prime Minister Lee Hsien Loong famously issued a warning to would-be attackers.

"It is not just anything goes and you are anonymous, therefore there is no responsibility. You may think you are anonymous. We will make that extra effort to find out who you are."

What did the attackers suffer? Some jail time, perhaps a fine of a few thousand bucks. And the government? A huge foot-in-mouth moment and a tremendous loss in credibility.

Yes, no data was lost, altered or stolen.

Yes, the damage was restricted to the visual aspect of the sites.

Yes, it could be worse. Way worse.

No, all this does not make it OK.

The average web-user is visual creature - he judges with his eyes. And since he can't see the database (which is intact) and can only see the front-end layout (which is not), he can hardly be blamed for assuming the worst. Loss of public confidence is not a small matter for those in authority.

But I'm glad these attacks were carried out. If nothing else, this has driven home a valuable point to the public, one which the average web developer would have known by now: Government websites are not extra-safe just because they are Government websites. In other words, don't trust the Government blindly, and don't place them on a pedestal. They're as fallible as the next man.

That's not to say I think that Government websites should be bulletproof. No site in the world is bulletproof - it is merely a matter of time and effort. What is appalling is that these websites could have been defaced using such a schoolboy method. All the attackers had to do was manipulate the search bar function, and in certain cases, just the URL. XSS Attacks come in countless forms - and the types of XSS attacks used to deface these websites were among the most unsophisticated.

Contrast this with what happened to the Swedish Government, also last month. Hackers broke into the email accounts of the Swedes. I'm sure I don't have to tell you that's a different class altogether from a crummy surface-level XSS attack.

A possible cause of the problem 

To be fair though, it's not just these websites which have such vulnerabilities to exploit. Plenty of others do.

In my time as a vendor-based developer, I've seen projects being outsourced to smaller companies, and even to outfits in India and Malaysia who would do the work for a fraction of the price quoted to the original customer. By the time the project went down the chain, what was originally a 10k project would likely have become a 1k project. These "factories" might churn out something resembling the specifications using off-the-shelf software. Visually the final product would be satisfactory, but what about security? Oh, you wanted your site to be watertight, too? Then maybe you should have paid for that, you cheap shit.

For those at the bottom rung of the outsourcing ladder, there are very few consequences for failure. I mean, can you see yourself suing some tiny firm in Timbuktu for botching a job you should have done yourself?

I didn't think so.

Stay vigilant. There's no such thing as XXS-ive security!
T___T