Sunday, August 14, 2022

A Security Hole

In the '90s I was a QA tester at Macromedia, and one thing I tested was Shockwave. Shockwave was Macromedia's proprietary web browser plug-in for playing interactive multimedia. That was one of the very first plug-ins for Netscape Navigator (and for that matter, one of the first ActiveX controls for Internet Explorer, but let's not get bogged down).

One day we added a new feature to probe the keyboard, so you could figure out which keys were currently being held down. This is very useful for arcade-style games, when you need to know (for instance) if the left shift key and the left function key and the right control key are being held down at the same time. This was new; Shockwave couldn't do that before.

Anyway, I was assigned to test this thing. Which I did, and it passed with flying colors. It definitely worked as advertised. So it was included in the next rev of the plug-in / ActiveX control.

But at some point, after we had already shipped the feature, something nagged at me. I had a worrisome thought that maybe I missed something big.

So I came to work and verified my fear -- any piece of Shockwave content currently running in your web browser was capable of probing the keyboard even if the keyboard focus was somewhere else.

This meant that your little Shockwave game where you click on the kittens (or whatever) could be a nefarious keylogger, capturing everything you typed anywhere in the browser, whether that window had the current focus or not.

I was, of course, horrified that I missed this huge, gaping security hole. So I reported the issue immediately. And then engineering asked me for a user scenario to illustrate how bad it really was. In other words, they needed an explanation as to how a keylogger could pose a problem for our users.

Eventually I managed to convince management that this bug had to be fixed ASAP. So they threw some engineering time at it, and the fix got merged into the codebase. But there it languished, because they decided to roll it out with the next scheduled update.

For weeks I arrived at work each morning, checking the external mailing lists to see if any of our customers had noticed the aforementioned huge, gaping security hole.

Eventually, I saw one post from a user who noticed the situation but hadn't grasped its security implications. And when no other user replied to that message, it seemed to disappear with only a shrug.

I think we shipped a dot release about a week later, which included the bugfix. And then I could finally relax about it.

Thursday, August 13, 2020

EULA bugs

Time was, most days you’d get an installer to test. Sometimes even two or three installers in a single day. And you had to run those installers on lots of lab machines. Which means, over time you clicked a lot of Install buttons.

The very first thing every installer did was brandish its End User License Agreement to the customer, which was a company’s carefully-written, bacon-saving liturgy. Whereupon you had to click the checkbox or radio button to indicate that, yes, you had indeed just read and digested the entire document and determined it to be not only satisfactory but also legally binding.

One day at the big security vendor for which you were working, it occurs to you that there could be bugs hiding in that EULA — that is, in the text itself. It being your job to find bugs, you start reading the thing. Well, skimming really. But you’re at least running your eyes over the sentences.

Which is when you notice that the postal address for customer service in the European Union is munged, along with some of the surrounding text. So you file a bug report, which wends its way through the Legal department and eventually emerges some days later along with a new installer sporting a regulation EULA which contains the correct address. As it turns out, it had been a copy & paste error by someone in between the lawyers and the person who built the installer.

Some time later, your department’s test plans are changed to incorporate diffing the installer EULA against the one blessed by Legal.

Lessons:

1. Bugs are hiding anywhere that people don’t look.

2. Never assume that business-critical issues belong to someone above your pay grade — like someone in, say, the Legal department.

3. It’s safest when responsibility for deliverables is shared. Either you have overlaps, or gaps. Your choice.

Tuesday, July 14, 2020

There Is But One Prod

There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton

Let's say that whenever your software company ships its product to actual customers, it is promoted to a branch named "Prod" or something like that.

Let's also say your team builds software whose users are all internal to the company. That is to say, it is never publicly released. None of your company's customers are ever going to see it.

In such a situation, don't let your team name their own release branch Prod also. Prod (or its equivalent) should always mean one thing and one thing only: this software is available to actual customers.

If your internal dev team is releasing its internal tool on a branch called "Prod", it gets confusing for other people. It happens. And this confusion is totally avoidable. It's an unforced error. Call your branch something else.

There is but one Prod, and thou shalt have no other Prods before it.

Tuesday, September 19, 2017

Welcome to the Interview

Job interviews are inherently stressful, because the stakes are so high. After all, getting a job is a life-changing event.

For some reason, a lot of interviewers seem to believe that the stress is somehow beneficial to the process, so they go out of their way to make things even more stressful.

I disagree. I find it counterproductive for both parties because it interferes with memory and reasoning skills, making it harder to answer questions.

That said, let me explain a few things:
  1. I am going to interrupt you. It doesn't mean that things are going poorly. It's just that our time is finite. So don't let the interruptions bother you.
  2. If something isn't totally clear, ask me to repeat the question or rephrase it. Make sure that you understand my questions. Sometimes I can misspeak, or choose the wrong words. Also, different companies can use different names to refer to the same things. It could be that I'm using an unfamiliar term for something that you know by a different name.
  3. If I ask you to write code, it doesn't have to compile. I don't care about syntax, like braces or semicolons. You can use any programming language that you want. You can even write pseudocode. I just want to understand your program's logic.
  4. You don't have to answer right away. It's okay to think before answering. And it's okay to pause in the middle of an answer. It's even okay to pause in the middle of a sentence.
  5. If you get stuck, it's okay to ask for hints. Sometimes you might need a little push in the right direction.
  6. Sometimes your best answer might actually be "I don't know." I may be asking a series of questions to probe the perimeter of your knowledge. It's okay not to know every answer.
  7. If a better answer pops into your head later on, go ahead and tell me. We can rewind to a previous question.
  8. I don't have a secret question which you must answer correctly. Some interviewers have a pet question that everyone has to get right. If you totally bomb on a question, don't worry. It's not an automatic fail.
  9. You're not required to ask me questions. Every interview website suggests that you ask your interviewer questions to show interest. I don't care if you have questions. If you do, that's fine. But let's save them until the end.

Friday, April 25, 2014

Feature Idea for Blogging Software

When presenting the user with the list of tags applied to a post, how about you omit any tag that has only 1 member (i.e. the post you just read)?

Clicking on such a tag is a total waste of time.

Calling the patent attorney now...

Friday, April 18, 2014

Python speech synthesis on OS X

I know, this is cheating. But it's fun.

def speak(*args):
    from subprocess import Popen, PIPE
    
    cmd = ["/usr/bin/say"]
    cmd.extend(args)
    
    Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()