“Security Suite” Subscriptions are the Dumbest Idea in Computer Security

I recently came across a 2005 essay by Marcus Ranum entitled “The Six Dumbest Ideas in Computer Security”. #1 on Ranum’s list is “Default Permit”.

Another place where "Default Permit" crops up is in how we typically approach code execution on our systems. The default is to permit anything on your machine to execute if you click on it, unless its execution is denied by something like an antivirus program or a spyware blocker. If you think about that for a few seconds, you’ll realize what a dumb idea that is. On my computer here I run about 15 different applications on a regular basis. There are probably another 20 or 30 installed that I use every couple of months or so. I still don’t understand why operating systems are so dumb that they let any old virus or piece of spyware execute without even asking me. That’s "Default Permit."

#2 on Ranum’s list is a special case of #1 which he calls “Enumerating Badness”. Basically what that boils down to is keeping a running list of “bad” stuff and preventing that from happening.

"Enumerating Badness" is the idea behind a huge number of security products and systems, from anti-virus to intrusion detection, intrusion prevention, application security, and "deep packet inspection" firewalls. What these programs and devices do is outsource your process of knowing what’s good. Instead of you taking the time to list the 30 or so legitimate things you need to do, it’s easier to pay $29.95/year to someone else who will try to maintain an exhaustive list of all the evil in the world. Except, unfortunately, your badness expert will get $29.95/year for the antivirus list, another $29.95/year for the spyware list, and you’ll buy a $19.95 "personal firewall" that has application control for network applications. By the time you’re done paying other people to enumerate all the malware your system could come in contact with, you’ll more than double the cost of your "inexpensive" desktop operating system.

The prices have gone up a bit with inflation:

  • Norton Internet Security Suite $70/year
  • Kaspersky PURE Total Security $90/year
  • McAfee Total Protection $90/year

Basically what you get for your $60-90/year is a system that double-checks everything that you try to do isn’t something bad that it knows about and if it is tries to stop it and if it lets something nasty happen tries to fix it later. You have no guarantee that something bad won’t happen because your computer still defaults to executing all code and, as a bonus, your expensive new computer now runs like molasses.

Default Deny is an Available Option in Windows 7 (but not by default)

Windows 7 ships with a semi-obscure enterprise feature called AppLocker. What AppLocker can do is deny execution to all programs, scripts, installers and DLLs by default. Instead of the normal situation where everything runs, only the code that matches ApplLockers known-good rules is allowed to execute. It works in conjunction with non-administrator user accounts to ensure that the only code executing on your system is code you want executing. This sleeper that nobody has ever heard of is more effective at stopping malware than any security suite on the market can ever be.

Why does this work? Your every day account has limited rights so it can’t write files into protected parts of the operating system but only software installed into protected parts of the operating system are allowed to execute. That means its impossible to execute downloads, email attachments, files on USB drives or whatever. Even if your browser or a plugin like Flash is exploited by malicious code in a web page, it is severely limited in the damage it can do. The usual end game of browser exploit code is to download malware onto your computer, install it somewhere and execute it. With an AppLocker default deny policy the end game can’t happen. This makes an anti-malware system something of an afterthought. Antimalware software becomes nothing more than good hygiene rather than the beachhead of your computer security, so make sure to use something that is free, lightweight and unobtrusive.

The catch is that AppLocker is an “Enterprise” feature that is only available in Windows 7 Enterprise or Ultimate editions. Also, there is configured through the Group Policy enterprise management tool which is targeted at professional systems administrators rather than normal people.

It turns out to also be cheaper to upgrade to Windows 7 Ultimate than to pay for 3 years of anti-malware. Let’s assume that your computer has a 3-year life.

Windows Anytime Upgrade Price List

  • Windows 7 Starter to Windows 7 Ultimate: $164.99 or $55/year amortized over 3 years
  • Windows 7 Home Premium to Windows 7 Ultimate: $139.99 or $47/year amortized over 3 years
  • Windows 7 Professional to Windows 7 Ultimate: $129.99 or $43/year amortized over 3 years

Even if it weren’t cheaper than massive security suites, enabling a default deny execution policy is so fundamentally right it is crazy not to do it. Any corporate IT department deploying Windows 7 without enabling AppLocker is either incompetent or the organization places no value on information security. For home users, the configuration is doable but it is “enterprisey” which means the configuration interface is too daunting for most people.

If Microsoft cares about protecting its users, it should enhance AppLocker so that it has a consumer-friendly configuration interface and it should turn on AppLocker by default in all SKUs, just like the Windows Firewall is on by default.

The day can’t come soon enough that Windows ships with a default deny firewall and a default deny execution policy and limited rights users by default. Maybe it will all come together in Windows 8.

Submitting an MVC Ajax.BeginForm Using JavaScript and jQuery

The Ajax.BeginForm() helper method in ASP.Net MVC generates a bit of inline JavaScript attached to the onsubmit event of the form. When the form is submitted in the usual manner with a submit button the request is sent using XMLHttpRequest and the result is returned into the <DIV /> of your choice. However, if you want try to submit the form using JavaScript things are less tidy.

For my example, imagine a user account management tool that displays a grid of accounts and has a number batch of operations that you can perform against the grid data in an Ajax-y manner.account-mgmt

The idea here is that you could, for example, check a number of accounts and then click disable and those accounts would be disabled. The result of your operation gets written into a notification <DIV />.

Here’s the naïve implementation for submitting an MVC Ajax form.

jQuery().ready(function () {
	//other stuff including jqGrid initialization here...

	//'grid' is the id of the jqGrid table element
	//'disableKeys' is the id of the Ajax form we are submitting.
	$('form#disableAccounts').find('a.submit-link').click(function () {
	    //work to set the state of the form before sending it to the server here...
	    $('form#disableAccounts').submit();
	});
)};

Unfortunately, this doesn’t do at all what we want. What you end up with is the text that was intended for the notification <DIV /> replacing the entire window contents. In other words, a classic POST. But wait, there’s more.

debug-double-post

What actually happens is that the request is submitted twice! The first version is Ajax and the second is classic POST, interrupting the Ajax response.

The First Solution

My initial approach to solving this double-submit problem hinged on leveraging the fact that Ajax.BeginForm() generates a <FORM /> tag with some JavaScript attached to the onsubmit event to handle the Ajax behavior. Why not just trigger the onsubmit event directly?

jQuery().ready(function () {
	//other stuff including jqGrid initialization here...

	//'grid' is the id of the jqGrid table element
	//'disableKeys' is the id of the Ajax form we are submitting.
	$('form#disableAccounts').find('a.submit-link').click(function () {
	    //work to set the state of the form before sending it to the server here...
	    $('form#disableAccounts').trigger('onsubmit');
	});
)};

This works great except in Safari where nothing happens at all.

The Final Solution

I tried a number of different techniques to suppress the default form POST behavior. The one that worked in IE, Firefox, Chrome and Safari is to attach a new event handler to the submit event that always returns false.

jQuery().ready(function () {
	//other stuff including jqGrid initialization here...

	//prevent the form from submitting in a non-Ajax manner for all browsers
	$('form#disableAccounts').submit(function (event) { eval($(this).attr("submit")); return false; });

	//'grid' is the id of the jqGrid table element
	//'disableKeys' is the id of the Ajax form we are submitting.
	$('form#disableAccounts').find('a.submit-link').click(function () {
	    //work to set the state of the form before sending it to the server here...
	    $('form#disableAccounts').submit();
	});
)};

This works to suppress the second standard POST and allow the ASP.Net Ajax behavior to complete as expected.

%d bloggers like this: