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