Changeset 51757 in webkit


Ignore:
Timestamp:
Dec 7, 2009 5:06:18 AM (14 years ago)
Author:
oliver@apple.com
Message:

Object.getOwnPropertyDescriptor() allows cross-frame access
https://bugs.webkit.org/show_bug.cgi?id=32119

Reviewed by Maciej Stachowiak.

Make all implementations of getOwnPropertyDescriptor that have
cross domain restrictions simply fail immediately on cross domain
access, rather than trying to mimic the behaviour of normal
property access.

Test: http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html

Location:
trunk
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r51744 r51757  
     12009-12-06  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Maciej Stachowiak.
     4
     5        Object.getOwnPropertyDescriptor() allows cross-frame access
     6        https://bugs.webkit.org/show_bug.cgi?id=32119
     7
     8        Add cross domain tests for getOwnPropertyDescriptor
     9
     10        * http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html: Added.
     11        * http/tests/security/resources/cross-frame-access.js:
     12        (canGetDescriptor.set get catch):
     13        (canGetDescriptor):
     14        * http/tests/security/resources/cross-frame-iframe-for-get-test.html:
     15        * http/tests/security/xss-DENIED-defineProperty.html:
     16
    1172009-12-06  Kent Tamura  <tkent@chromium.org>
    218
  • trunk/LayoutTests/http/tests/security/resources/cross-frame-access.js

    r41826 r51757  
    5454    try {
    5555        return eval("window." + keyPath) !== undefined;
     56    } catch(e) {
     57        return false;
     58    }
     59}
     60
     61function canGetDescriptor(target, property)
     62{
     63    try {
     64        var desc = Object.getOwnPropertyDescriptor(target, property);
     65        // To deal with an idiosyncrasy in how binding objects work in conjunction with
     66        // slot and descriptor delegates we also allow descriptor with undefined value/getter/setter
     67        return  desc !== undefined && (desc.value !== undefined || desc.get !== undefined || desc.set !== undefined);
    5668    } catch(e) {
    5769        return false;
  • trunk/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-get-test.html

    r30157 r51757  
    55        window.__proto__.windowPrototypeCustomProperty = 1;
    66        window.Object.prototype.objectPrototypeCustomProperty = 1;
     7        window.location.customProperty = 1;
     8        window.history.customProperty = 1;
    79
    810        window.onload = function()
  • trunk/LayoutTests/http/tests/security/xss-DENIED-defineProperty.html

    r48542 r51757  
    1717        document.getElementById("console").innerHTML += "FAIL: cross-site assignment of new property was allowed!<br/>";
    1818
    19     if (Object.getOwnPropertyDescriptor(location, "hash").value.length == 0)
     19    if (location.hash.length == 0)
    2020        document.getElementById("console").innerHTML += "PASS: cross-site assignment of location.hash not allowed<br/>";
    2121    else
    2222        document.getElementById("console").innerHTML += "FAIL: cross-site assignment of location.hash was allowed!<br/>";
    2323
    24     if (Object.getOwnPropertyDescriptor(location, "hash").value.length == 0)
     24    if (location.search.length == 0)
    2525        document.getElementById("console").innerHTML += "PASS: cross-site assignment of location.search not allowed<br/>";
    2626    else
  • trunk/WebCore/ChangeLog

    r51756 r51757  
     12009-12-06  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Maciej Stachowiak.
     4
     5        Object.getOwnPropertyDescriptor() allows cross-frame access
     6        https://bugs.webkit.org/show_bug.cgi?id=32119
     7
     8        Make all implementations of getOwnPropertyDescriptor that have
     9        cross domain restrictions simply fail immediately on cross domain
     10        access, rather than trying to mimic the behaviour of normal
     11        property access.
     12
     13        Test: http/tests/security/cross-frame-access-getOwnPropertyDescriptor.html
     14
     15        * bindings/js/JSDOMWindowCustom.cpp:
     16        (WebCore::JSDOMWindow::getOwnPropertyDescriptor):
     17        * bindings/js/JSHistoryCustom.cpp:
     18        (WebCore::JSHistory::getOwnPropertyDescriptorDelegate):
     19        * bindings/js/JSLocationCustom.cpp:
     20        (WebCore::JSLocation::getOwnPropertyDescriptorDelegate):
     21        * bindings/scripts/CodeGeneratorJS.pm:
     22
    1232009-12-07  Steve Block  <steveblock@google.com>
    224
  • trunk/WebCore/bindings/js/JSDOMWindowCustom.cpp

    r51577 r51757  
    298298bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    299299{
    300     // When accessing a Window cross-domain, functions are always the native built-in ones, and they
    301     // are not affected by properties changed on the Window or anything in its prototype chain.
    302     // This is consistent with the behavior of Firefox.
    303    
     300    // Never allow cross-domain getOwnPropertyDescriptor
     301    if (!allowsAccessFrom(exec))
     302        return false;
     303
    304304    const HashEntry* entry;
    305305   
     
    324324    }
    325325
    326     String errorMessage;
    327     bool allowsAccess = allowsAccessFrom(exec, errorMessage);
    328     if (allowsAccess && JSGlobalObject::getOwnPropertyDescriptor(exec, propertyName, descriptor))
    329         return true;
    330 
    331326    // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the
    332327    // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot.
     
    336331    if (entry) {
    337332        if (entry->attributes() & Function) {
    338             if (entry->function() == jsDOMWindowPrototypeFunctionBlur) {
    339                 if (!allowsAccess) {
    340                     PropertySlot slot;
    341                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
    342                     descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    343                     return true;
    344                 }
    345             } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) {
    346                 if (!allowsAccess) {
    347                     PropertySlot slot;
    348                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
    349                     descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    350                     return true;
    351                 }
    352             } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) {
    353                 if (!allowsAccess) {
    354                     PropertySlot slot;
    355                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
    356                     descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    357                     return true;
    358                 }
    359             } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) {
    360                 if (!allowsAccess) {
    361                     PropertySlot slot;
    362                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
    363                     descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    364                     return true;
    365                 }
    366             } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
     333            if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
    367334                if (!DOMWindow::canShowModalDialog(impl()->frame())) {
    368335                    descriptor.setUndefined();
    369336                    return true;
    370337                }
    371             }
    372         }
    373     } else {
    374         // Allow access to toString() cross-domain, but always Object.prototype.toString.
    375         if (propertyName == exec->propertyNames().toString) {
    376             if (!allowsAccess) {
    377                 PropertySlot slot;
    378                 slot.setCustom(this, objectToStringFunctionGetter);
    379                 descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    380                 return true;
    381338            }
    382339        }
     
    407364    JSValue proto = prototype();
    408365    if (proto.isObject()) {
    409         if (asObject(proto)->getPropertyDescriptor(exec, propertyName, descriptor)) {
    410             if (!allowsAccess) {
    411                 printErrorMessage(errorMessage);
    412                 descriptor.setUndefined();
    413             }
     366        if (asObject(proto)->getPropertyDescriptor(exec, propertyName, descriptor))
    414367            return true;
    415         }
    416368    }
    417369
  • trunk/WebCore/bindings/js/JSHistoryCustom.cpp

    r51644 r51757  
    9696bool JSHistory::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    9797{
    98     // When accessing History cross-domain, functions are always the native built-in ones.
    99     // See JSDOMWindow::getOwnPropertySlotDelegate for additional details.
    100    
    101     // Our custom code is only needed to implement the Window cross-domain scheme, so if access is
    102     // allowed, return false so the normal lookup will take place.
    103     String message;
    104     if (allowsAccessFromFrame(exec, impl()->frame(), message))
    105         return false;
    106    
     98    if (!impl()->frame()) {
     99        descriptor.setUndefined();
     100        return true;
     101    }
     102
     103    // Throw out all cross domain access
     104    if (!allowsAccessFromFrame(exec, impl()->frame()))
     105        return true;
     106
    107107    // Check for the few functions that we allow, even when called cross-domain.
    108108    const HashEntry* entry = JSHistoryPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
     
    134134        }
    135135    }
    136    
    137     printErrorMessageForFrame(impl()->frame(), message);
     136
    138137    descriptor.setUndefined();
    139138    return true;
  • trunk/WebCore/bindings/js/JSLocationCustom.cpp

    r50784 r51757  
    103103    }
    104104   
    105     // When accessing Location cross-domain, functions are always the native built-in ones.
    106     // See JSDOMWindow::getOwnPropertySlotDelegate for additional details.
    107    
    108     // Our custom code is only needed to implement the Window cross-domain scheme, so if access is
    109     // allowed, return false so the normal lookup will take place.
    110     String message;
    111     if (allowsAccessFromFrame(exec, frame, message))
    112         return false;
     105    // throw out all cross domain access
     106    if (!allowsAccessFromFrame(exec, frame))
     107        return true;
    113108   
    114109    // Check for the few functions that we allow, even when called cross-domain.
     
    134129    // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in
    135130    // such cases when normally the string form of Location would be the URL.
    136    
    137     printErrorMessageForFrame(frame, message);
     131
    138132    descriptor.setUndefined();
    139133    return true;
  • trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r51326 r51757  
    376376   
    377377    my @getOwnPropertyDescriptorImpl = ();
     378    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
     379        if ($interfaceName eq "DOMWindow") {
     380            push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
     381        } else {
     382            push(@implContent, "    if (!allowsAccessFromFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
     383        }
     384        push(@implContent, "        return false;\n");
     385    }
    378386   
    379387    if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
Note: See TracChangeset for help on using the changeset viewer.