My favorites | Sign in
Logo
                
Search
for
Updated Jun 05, 2008 by mikesamuel
Labels: Attack-Vector
TypeofInconsistent  
ES3 allows for arbitrary behavior around typeof

typeof inconsistent for regular expressions and other intrinsics

Effect

See http://javascript.crockford.com/remedial.html.

('function' === typeof o) !== (o instanceof Function)

even ignoring different Functions from different frames.

Background

The typeof operator must return 'function' for anything that is callable.

According to section 11.4.3 of EcmaScript 262

so an callable object is a "function" and a "host object" can have any type it desires.
Type Result
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
String "string"
Object (native and doesn’t implement [[Call]]) "object"
Object (native and implements [[Call]]) "function"
Object (host) Implementation-dependent

A host object is a javascript object that is backed by special browser or operating system code. Most browsers' DOM trees are host objects, and plugins and extensions are often exposed as host objects. The spec allows for

(typeof new ActiveXObject('Crime Fighter')) === 'batman'
&& (typeof new ActiveXObject('ComplexNumber')) === 'number'

so that the host object exemption means that the identity

(x === undefined) === ((typeof x) === 'undefined')

does not hold.

IE allows for some non-function callables. On IE 6 and 7,

'object' === (typeof alert)

and similarly for many other builtins: confirm, prompt, setTimeout, setInterval, clearTimeout, clearInterval, and some of the DOM constructors such as Image.

Assumptions

Runtime checks based on typeof allow access to members of functions that are not allowed on normal Objects.

Versions

On Firefox,

'function' === (typeof /./)
'function' === (typeof alert)

On IE 6,

'object' === (typeof /./)
'object' === (typeof alert)

Some hosted objects return 'unknown' as the typeof value, but I don't have a specific example.


Comment by johnhax, Nov 13, 2007

On IE, assign f from a function from different window or frame. 'object' == typeof f

Comment by mikesamuel, Apr 29, 2008

I can't repeat this with the following test:

t.html

<html> <head></head> <body> <script> function f() {

alert('typeof g is ' + (typeof window.frames0?.g)); var g = window.frames0?.g; alert('typeof g is ' + (typeof g));
} </script> <iframe onload="f()" src="t2.html"></iframe> </body> </html>

t2.html

<html> <head></head> <body><script> function g() {} </script></body> </html>

Comment by davidsarah.hopwood, Jun 05, 2008

If you get a result from typeof that is 'number', 'boolean', 'string' or 'undefined', then you know that the value is of that primitive type. Note that when primitive values are passed across contexts, they turn into a primitive value in the new context, which has well-defined behaviour providing only that the Number, Boolean, and String prototypes in the new context have not been messed about with by untrusted code. (At least, that is my understanding, although I cannot find any good documentation of it.)

If you get any other result, then you have a non-primitive value. There simply is no point in trying to distinguish between different kinds of non-primitive value by this kind of type test (that returns a string representing the type). The reason for that is, the value might be from a different context than the one your TCB is dependent on, so you cannot trust it anyway.

http://javascript.crockford.com/remedial.html falls into the trap of trying to "fix" typeof without changing its interface. Actually, the real problem is that the attempt to distinguish between 'object' and 'function' tends to mislead people into thinking that there could be a test with this interface that reliably distinguishes non-primitive values.

Just treat any return other than 'number', 'boolean', 'string' or 'undefined' as meaning 'non-primitive'. To check for null, use '=== null'. To distinguish other types, implement some kind of trademarking or branding (e.g. by using a hidden property that holds a unique closely held object representing each application-level type). Note that the function types that you want to distinguish for the purpose of implementing a secure JavaScript subset are things like "simple function", "constructor", as determined by the TCB of the current context, not just "any function".

Comment by davidsarah.hopwood, Aug 02, 2008

A partial retraction of the previous comment:

There is some use for a test to determine whether a given value might be a function that refers to 'this'. If we know that it definitely isn't a function that refers to 'this', then we can treat it as a first-class value, even if some operation has been applied to it that would have stuffed up its 'this' binding (as JavaScript is wont to do).

The current Jacaranda spec uses this approach to allow expressions resulting from property accesses to be used in more cases. There is a function $uncallable defined as

function $uncallable(x) {
if (typeof x === 'function') throw ... return x;
}

Now "$uncallable(true && obj.prop)" can be treated as a first-class expression, even though "true && obj.prop" can't. (This is a contrived example; there are more useful cases.)

If this test has some false positives for values that are callable but not functions, that doesn't cause any loss of safety. Note that we do want $uncallable to reject functions from other frames.

Comment by davidsarah.hopwood, Aug 02, 2008

The Wiki formatting messed up the definition of $uncallable above. If it's not clear, $uncallable(x) returns x only if typeof x is not 'function'.

Comment by steveng1, Aug 28, 2008

Can someone explain to me why this line of code does not display "function"?

document.writeln(typeof /abc/);

Comment by steveng1, Aug 28, 2008

Forgot to mention, I am using Firefox 3.0

Comment by kangax, Jan 13, 2009

What about checking for [Class?] of an object?

Object.prototype.toString.call(/a/) === '[object RegExp]';

See my blog post


Sign in to add a comment