diff options
Diffstat (limited to 'WebCore/page/SecurityOrigin.cpp')
| -rw-r--r-- | WebCore/page/SecurityOrigin.cpp | 176 |
1 files changed, 141 insertions, 35 deletions
diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 14a1b59..f53dbf1 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -30,16 +30,23 @@ #include "SecurityOrigin.h" #include "CString.h" -#include "FrameLoader.h" +#include "Document.h" #include "KURL.h" -#include "PlatformString.h" -#include "StringHash.h" -#include <wtf/HashSet.h> +#include "OriginAccessEntry.h" #include <wtf/StdLibExtras.h> namespace WebCore { -typedef HashSet<String, CaseFoldingHash> URLSchemesMap; +static SecurityOrigin::LocalLoadPolicy localLoadPolicy = SecurityOrigin::AllowLocalLoadsForLocalOnly; + +typedef Vector<OriginAccessEntry> OriginAccessWhiteList; +typedef HashMap<String, OriginAccessWhiteList*> OriginAccessMap; + +static OriginAccessMap& originAccessMap() +{ + DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ()); + return originAccessMap; +} static URLSchemesMap& localSchemes() { @@ -68,26 +75,11 @@ static URLSchemesMap& noAccessSchemes() return noAccessSchemes; } -static bool isDefaultPortForProtocol(unsigned short port, const String& protocol) -{ - if (protocol.isEmpty()) - return false; - - typedef HashMap<String, unsigned> DefaultPortsMap; - DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); - if (defaultPorts.isEmpty()) { - defaultPorts.set("http", 80); - defaultPorts.set("https", 443); - defaultPorts.set("ftp", 21); - defaultPorts.set("ftps", 990); - } - return defaultPorts.get(protocol) == port; -} - SecurityOrigin::SecurityOrigin(const KURL& url) : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) , m_host(url.host().isNull() ? "" : url.host().lower()) , m_port(url.port()) + , m_sandboxFlags(SandboxNone) , m_noAccess(false) , m_universalAccess(false) , m_domainWasSetInDOM(false) @@ -105,16 +97,22 @@ SecurityOrigin::SecurityOrigin(const KURL& url) // By default, only local SecurityOrigins can load local resources. m_canLoadLocalResources = isLocal(); + if (m_canLoadLocalResources) { + // Directories should never be readable. + if (!url.hasPath() || url.path().endsWith("/")) + m_noAccess = true; + } if (isDefaultPortForProtocol(m_port, m_protocol)) m_port = 0; } SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) - : m_protocol(other->m_protocol.copy()) - , m_host(other->m_host.copy()) - , m_domain(other->m_domain.copy()) + : m_protocol(other->m_protocol.threadsafeCopy()) + , m_host(other->m_host.threadsafeCopy()) + , m_domain(other->m_domain.threadsafeCopy()) , m_port(other->m_port) + , m_sandboxFlags(other->m_sandboxFlags) , m_noAccess(other->m_noAccess) , m_universalAccess(other->m_universalAccess) , m_domainWasSetInDOM(other->m_domainWasSetInDOM) @@ -139,7 +137,7 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty() return create(KURL()); } -PassRefPtr<SecurityOrigin> SecurityOrigin::copy() +PassRefPtr<SecurityOrigin> SecurityOrigin::threadsafeCopy() { return adoptRef(new SecurityOrigin(this)); } @@ -155,7 +153,7 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const if (m_universalAccess) return true; - if (m_noAccess || other->m_noAccess) + if (m_noAccess || other->m_noAccess || isSandboxed(SandboxOrigin) || other->isSandboxed(SandboxOrigin)) return false; // Here are two cases where we should permit access: @@ -196,14 +194,56 @@ bool SecurityOrigin::canRequest(const KURL& url) const if (m_universalAccess) return true; - if (m_noAccess) + if (m_noAccess || isSandboxed(SandboxOrigin)) return false; RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); + if (targetOrigin->m_noAccess) + return false; // We call isSameSchemeHostPort here instead of canAccess because we want // to ignore document.domain effects. - return isSameSchemeHostPort(targetOrigin.get()); + if (isSameSchemeHostPort(targetOrigin.get())) + return true; + + if (OriginAccessWhiteList* list = originAccessMap().get(toString())) { + for (size_t i = 0; i < list->size(); ++i) { + if (list->at(i).matchesOrigin(*targetOrigin)) + return true; + } + } + + return false; +} + +bool SecurityOrigin::taintsCanvas(const KURL& url) const +{ + if (canRequest(url)) + return false; + + // This method exists because we treat data URLs as noAccess, contrary + // to the current (9/19/2009) draft of the HTML5 specification. We still + // want to let folks paint data URLs onto untainted canvases, so we special + // case data URLs below. If we change to match HTML5 w.r.t. data URL + // security, then we can remove this method in favor of !canRequest. + if (url.protocolIs("data")) + return false; + + return true; +} + +bool SecurityOrigin::canLoad(const KURL& url, const String& referrer, Document* document) +{ + if (!shouldTreatURLAsLocal(url.string())) + return true; + + // If we were provided a document, we let its local file policy dictate the result, + // otherwise we allow local loads only if the supplied referrer is also local. + if (document) + return document->securityOrigin()->canLoadLocalResources(); + if (!referrer.isEmpty()) + return shouldTreatURLAsLocal(referrer); + return false; } void SecurityOrigin::grantLoadLocalResources() @@ -213,7 +253,7 @@ void SecurityOrigin::grantLoadLocalResources() // in a SecurityOrigin is a security hazard because the documents without // the privilege can obtain the privilege by injecting script into the // documents that have been granted the privilege. - ASSERT(FrameLoader::allowSubstituteDataAccessToLocal()); + ASSERT(allowSubstituteDataAccessToLocal()); m_canLoadLocalResources = true; } @@ -242,7 +282,7 @@ String SecurityOrigin::toString() const if (isEmpty()) return "null"; - if (m_noAccess) + if (m_noAccess || isSandboxed(SandboxOrigin)) return "null"; if (m_protocol == "file") @@ -339,13 +379,27 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const return true; } -// static void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme) { localSchemes().add(scheme); } -// static +void SecurityOrigin::removeURLSchemeRegisteredAsLocal(const String& scheme) +{ + if (scheme == "file") + return; +#if PLATFORM(MAC) + if (scheme == "applewebdata") + return; +#endif + localSchemes().remove(scheme); +} + +const URLSchemesMap& SecurityOrigin::localURLSchemes() +{ + return localSchemes(); +} + bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) { // This avoids an allocation of another String and the HashSet contains() @@ -366,7 +420,6 @@ bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) return localSchemes().contains(scheme); } -// static bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) { // This avoids an allocation of another String and the HashSet contains() @@ -385,16 +438,69 @@ bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) return localSchemes().contains(scheme); } -// static void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme) { noAccessSchemes().add(scheme); } -// static bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme) { return noAccessSchemes().contains(scheme); } +bool SecurityOrigin::shouldHideReferrer(const KURL& url, const String& referrer) +{ + bool referrerIsSecureURL = protocolIs(referrer, "https"); + bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); + + if (!referrerIsWebURL) + return true; + + if (!referrerIsSecureURL) + return false; + + bool URLIsSecureURL = url.protocolIs("https"); + + return !URLIsSecureURL; +} + +void SecurityOrigin::setLocalLoadPolicy(LocalLoadPolicy policy) +{ + localLoadPolicy = policy; +} + +bool SecurityOrigin::restrictAccessToLocal() +{ + return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForAll; +} + +bool SecurityOrigin::allowSubstituteDataAccessToLocal() +{ + return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForLocalOnly; +} + +void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) +{ + ASSERT(isMainThread()); + ASSERT(!sourceOrigin.isEmpty()); + if (sourceOrigin.isEmpty()) + return; + + String sourceString = sourceOrigin.toString(); + OriginAccessWhiteList* list = originAccessMap().get(sourceString); + if (!list) { + list = new OriginAccessWhiteList; + originAccessMap().set(sourceString, list); + } + list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains)); +} + +void SecurityOrigin::resetOriginAccessWhiteLists() +{ + ASSERT(isMainThread()); + OriginAccessMap& map = originAccessMap(); + deleteAllValues(map); + map.clear(); +} + } // namespace WebCore |
