Sunday, October 26, 2008

Comcast's Incompetence Puts You at Risk

I'm moving soon and I'm trying to get Comcast setup at the new location. I went through their online ordering process, and aside from the fact that there was no useful information given to differentiate one "package" from another, the process wasn't too painful... until the last step.

At the end of the process, they require that you chat with a representative online in this shoddy Java applet. I assumed the representative would simply verify some information, then wrap things up. But actually, she said that she needed my SSN. She also reassured me numerous times that "COMCAST is all about protecting customer confidentiality", and that my "information is secured and cannot be viewed by anyone else." Hmm, I thought to myself, I do see that this applet was loaded on a page fetched using https, but how do I know that the applet itself is communicating with the server securely?

So, of course I immediately started tcpdumping the session.

$ sudo tcpdump -s0 -i en1 -A 

And sure enough, I started seeing unencrypted communication between the applet and the server.

(applet -> server)
21:54:36.590164 IP > P 26477:27264(787) ack 37992 win 65535
...B..,...P...0.6..P...,e..GET /sdccommon/lachat/poll/send_msg.asp?fmt=sst&dtype=msg&Msg=... HTTP/1.1
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/4.0 (Mac OS X 10.5.5) Java/1.5.0_16
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

(server -> applet)
21:55:54.626048 IP > P 54493:55606(1113) ack 39154 win 65535
....P...6......P..._...HTTP/1.1 200 OK
Date: Mon, 27 Oct 2008 04:55:55 GMT
Server: Microsoft-IIS/6.0
X-Server: sg-ec-ch05
X-Powered-By: ASP.NET
Pragma: no-cache
Content-Length: 842
Content-Type: text/xml; Charset=utf-8
Expires: Mon, 27 Oct 2008 04:54:55 GMT
Cache-control: no-cache

EMAIL_ADDR=Auto Invitation
PROBLEM <Order Information>PROBLEM
PROBLEM<Order Information>PROBLEM
TEXT<Okay, no problem then. If you really think that this chat is not secure, you can call...>TEXT
TIME<10/27/2008 12:55:52 AM>TIME

In the end, the chat channel clearly was not encrypted. And during the conversation they send your name, address, phone, and SSN through this chat session, and they claim that the information is secured.

I would advise everyone to NOT trust online orders with Comcast, especially ones that use the Java applet pictured here. Or perhaps the better advice is to just not trust anything with the word "Comcast" on it (except for this blog post).

I don't know why I'm still amazed by their consistent incompetence.

Monday, September 29, 2008

Update Engine

Today we announced a new open source project called Update Engine. Update Engine is a framework to help developers keep their software up-to-date. See the Google Mac blog post for a quick overview and a link to some demo movies explaining Update Engine [and yes, I knew I sounded like kermit when I recorded the video—I even told my wife but she didn't think so... oh well ;-)].

Also, we did not build Update Engine to compete with Sparkle. We built Update Engine to solve different problems. If you're interested, here's my reply about this in the Google Group for the project.

Saturday, April 26, 2008

Gcalc Update

I updated gcalc to fix an issue caused by Google changing the HTML around the Google calculator answers (they added an extra h2 tag). No biggie, but gcalc now works again. You can get the new version here.

Also, I made gcalc a (small) project. So you can now check it out at

Thursday, April 10, 2008

Locating Apps from the Command Line

The other day I needed to find the location of an application using its bundle ID. Easy, just use LaunchServices. But I needed to do this from a script. Here are a couple perl one-liners to do it.

$ perl -MMac::Processes -e 'printf "%s\n", LSFindApplicationForInfo(undef, "")'

$ mv /Applications/ ~/Desktop/
$ perl -MMac::Processes -e 'printf "%s\n", LSFindApplicationForInfo(undef, "")'

$ mv ~/Desktop/ /Applications/
$ perl -MMac::Processes -e 'printf "%s\n", LSFindApplicationForInfo(undef, undef, "")'

(Yes, I know mdfind could do something similar. But it wouldn't necessarily return the one that LaunchServices thinks is the "preferred" one if there were multiple applications with the same bundle ID.)

Saturday, March 15, 2008

id vs NSObject* vs id<NSObject>

There's often confusion about the difference between the following three declarations in Objective-C:

  1. id foo1;

  2. NSObject *foo2;

  3. id<NSObject> foo3;

The first one is the most common. It simply declares a pointer to some Objective-C object (see /usr/include/objc/objc.h). id gives the compiler no information about the actual type of the object, so the compiler cannot do compile-time type checking for you. Thus, the compiler will let you send any (*) message to objects declared id. Actually, this is why the common idiom of [[Foo alloc] init] doesn't cause the compiler to complain. +alloc is declared to return type id, so the compiler won't yell when you then send the returned object the message init (or even initWithMyFoo:blah).

So, objects declared using id are just dynamically typed at runtime. The compiler has no useful information about the object's real type, so it can't warn you if you send it a message that it may not respond to.

Just because we know that an id is an Objective-C object does not mean that it points to an object that derives from NSObject, or that it even has common methods like retain and release. One solution is to statically type our variable using NSObject* as shown in number 2 above. This gives the compiler information about the class of the object pointed to by foo2 so the compiler can warn if you send a message to foo2 that an NSObject doesn't respond to. This means you can safely call retain, release, description, etc., but the compiler will warn if you call length or count or anything that an NSObject doesn't respond to.

So, declaring a generic pointer of type NSObject* is very similar to what you would do in other languages, like Java, but it's really a bit too restrictive for a language as flexible as Objective-C. Despite what you may have learned at one point, not all Foundation/Cocoa objects derive from NSObject. As an example, NSProxy is not derived from NSObject, so the foo2 pointer above would not be able to hold an NSProxy subclass, even though NSProxy does implement common methods like retain and release. What you really want is a pointer to any object that behaves like an NSObject. And that's exactly what the third case does.

Declaring an object as id<NSObject> tells the compiler that you don't care what type the object is, but you do care that it conforms to the specified NSObject protocol**. The compiler will ensure that all objects you assign to that pointer conform to the required protocol. A pointer typed like this can safely hold any NSObject (because NSObject conforms to the NSObject protocol), but it could also hold any NSProxy, because NSProxy also conforms to the NSObject protocol. In english, the declaration id<NSObject> foo3; says "foo3 is a pointer to an object of any type that behaves like an NSObject". This is very powerful, convenient, and expressive. In reality, we often don't care what type an object is, we just care that it responds to the messages that we want to send it (e.g., retain, release).

So how do you decide which form you want to use? It's pretty easy. If you don't want (or can't have) any type checking, then use a plain id. This is very common for return types on methods that don't know the type of object they're returning (e.g., +alloc). It is also common to declare delegates to be type id, because delegates are generally checked at runtime with respondsToSelector:, and they usually aren't retained.

However, if you do want compile-time type checking, you must decide between the second and third cases. Well, let me just help you out—you want the third case! :-) I've very, very, VERY rarely seen a situation where NSObject * worked but id<NSObject> would not. And using the protocol form has the advantage that it will work with NSProxys. You may think that you never use NSProxys, but Cocoa's distributed objects system makes heavy use of NSProxy subclasses. Additionally, the common case is that you simply want to ensure that an object can be retained or released, and in that case the protocol form conveys that intent better; you really don't care what class the object is, you only care that it behaves like an NSObject.

* Well, not "any" message. If you send a message using a selector that the compiler has never seen, it may warn that it has never seen that selector. This is nice in the event that you mistype init as inti.

** Now, when I say "NSObject" here I'm talking about the protocol (@protocol) named NSObject. There is also a class named NSObject that does indeed conform to the NSObject protocol, but they are two different things.

Wednesday, January 16, 2008

Great Macworld Pics

Markd over at the Borkware Miniblog posted some great pictures—and hilarious captions—of Macworld '08.