In its current form, the Storage specification makes it very likely for user agents to develop an implementation that allows attackers to leak the size of opaque Responses. There are at least 3 methods that could be used to do this:
Estimate usage and quota
The Fetch standard describes a method (
In case the estimate is used to obscure the resource size, repeat steps (3) and/or (4). E.g. if
Each site has their own fixed quota, and when trying to store something that doesn't fit in storage, this will obviously fail. These features can be abused to leak the response size in the following way:
Similar to the per-site quota, there's also a global quota, and user agents will free up space by first clearing non-persistent boxes. This provides the same properties as above to obtain the exact resource size. An attack looks as follows:
Compared to the previous attacks, this one is slightly harder to exploit (especially since the global quota can be substantial), but given the high storage speeds (especially with SSD) the attack is still very practical.
_Note:_ For all browsers that already implement one of the above (i.e. virtually every browser), we managed to devise an attack that exposes the exact size of any resource.
Being able to determine the resource size of arbitrary
Having a usable solution that completely eradicates all size-exposing vectors seems unlikely. Instead, I think it's best to have a solution that limits the practicability that of to existing attacks (i.e. timing attacks). As such, I'd like to suggest an approach where "virtual padding" is applied on
The text was updated successfully, but these errors were encountered:
When the opaque response is compressed, and the
@annevk HEIST provides the attacker with the response size after compression, this one provides the attacker with the uncompressed response size. Knowing either is bad, knowing both is worse. While I'd much rather see a generic solution such as disabling 3rd-party cookies by default (or something that provides a transition there, as is being done with the transition to HTTPS), this issue is independent from HEIST, and if there's no viable generic solution, the issues should be mitigated one by one. In addition, I'd say this issue is easier to exploit as it's more stable and convenient (especially when
https://bugs.webkit.org/show_bug.cgi?id=177552 Patch by Youenn Fablet <firstname.lastname@example.org> on 2017-10-09 Reviewed by Alex Christensen. Source/WebCore: Tests: http/wpt/cache-storage/cache-quota.any.html Storing padded opaque response body sizes within FetchResponse and CacheStorageConnection. See whatwg/storage#31 for the rationale about this padding. Storing in CacheStorageConnection is needed for handling cloned network fetched created responses. Storing in FetchResponse is needed for handling cloned cache-storage created opaque responses. Adding internals to query and set the fuzzed size of a response. * Modules/cache/CacheStorageConnection.cpp: (WebCore::computeRealBodySize): (WebCore::CacheStorageConnection::computeRecordBodySize): (WebCore::CacheStorageConnection::setResponseBodySizeWithPadding): (WebCore::CacheStorageConnection::responseBodySizeWithPadding const): * Modules/cache/CacheStorageConnection.h: * Modules/cache/DOMCache.cpp: (WebCore::DOMCache::toConnectionRecord): (WebCore::DOMCache::updateRecords): * Modules/cache/DOMCache.h: * Modules/cache/DOMCacheEngine.cpp: (WebCore::DOMCacheEngine::errorToException): (WebCore::DOMCacheEngine::Record::copy const): * Modules/cache/DOMCacheEngine.h: * Modules/cache/WorkerCacheStorageConnection.cpp: (WebCore::toCrossThreadRecordData): (WebCore::fromCrossThreadRecordData): * Modules/fetch/FetchResponse.cpp: (WebCore::FetchResponse::clone): (WebCore::FetchResponse::BodyLoader::didReceiveResponse): * Modules/fetch/FetchResponse.h: * Modules/fetch/FetchResponse.idl: * testing/Internals.cpp: (WebCore::Internals::setResponseSizeWithPadding): (WebCore::Internals::responseSizeWithPadding const): * testing/Internals.h: * testing/Internals.idl: Source/WebKit: Adding support for quota checking in CacheStorage::Caches. It is passed to NetworkProcess at creation time. Default quota size is configured to 400Ko by origin per default. This value is suitable for testing. Future patch should raise this default value and allows configuring it. Quota is computed based on the response body size. This size is padded at WebCore for opaque responses. Size is stored persistently as opaque response padded size should remain stable. See whatwg/storage#31 for the rationale about this padding. In case of putting several records at the same time, the size of all records is computed so that all records will be written or rejected together. Sending QuotaExceeded error when quota is exceeded. Future effort should allow asking UIProcess for quota extension. * NetworkProcess/NetworkProcess.cpp: (WebKit::NetworkProcess::cacheStoragePerOriginQuota const): * NetworkProcess/NetworkProcess.h: * NetworkProcess/NetworkProcessCreationParameters.cpp: (WebKit::NetworkProcessCreationParameters::encode const): (WebKit::NetworkProcessCreationParameters::decode): * NetworkProcess/NetworkProcessCreationParameters.h: * NetworkProcess/cache/CacheStorageEngine.cpp: (WebKit::CacheStorage::Engine::readCachesFromDisk): * NetworkProcess/cache/CacheStorageEngineCache.cpp: (WebKit::CacheStorage::Cache::toRecordInformation): (WebKit::CacheStorage::isolatedCopy): (WebKit::CacheStorage::Cache::open): (WebKit::CacheStorage::Cache::storeRecords): (WebKit::CacheStorage::Cache::put): (WebKit::CacheStorage::Cache::writeRecordToDisk): (WebKit::CacheStorage::Cache::updateRecordToDisk): (WebKit::CacheStorage::Cache::removeRecordFromDisk): (WebKit::CacheStorage::Cache::encode): (WebKit::CacheStorage::Cache::decodeRecordHeader): (WebKit::CacheStorage::Cache::decode): * NetworkProcess/cache/CacheStorageEngineCache.h: * NetworkProcess/cache/CacheStorageEngineCaches.cpp: (WebKit::CacheStorage::Caches::Caches): (WebKit::CacheStorage::Caches::initialize): (WebKit::CacheStorage::Caches::initializeSize): (WebKit::CacheStorage::Caches::requestSpace): (WebKit::CacheStorage::Caches::writeRecord): (WebKit::CacheStorage::Caches::removeRecord): (WebKit::CacheStorage::Caches::removeCacheEntry): * NetworkProcess/cache/CacheStorageEngineCaches.h: (WebKit::CacheStorage::Caches::create): (WebKit::CacheStorage::Caches::hasEnoughSpace const): * NetworkProcess/cache/NetworkCacheStorage.cpp: (WebKit::NetworkCache::Storage::traverse): * NetworkProcess/cocoa/NetworkProcessCocoa.mm: (WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa): * Shared/WebCoreArgumentCoders.cpp: (IPC::ArgumentCoder<DOMCacheEngine::Record>::encode): (IPC::ArgumentCoder<DOMCacheEngine::Record>::decode): * UIProcess/API/APIProcessPoolConfiguration.cpp: (API::ProcessPoolConfiguration::copy): * UIProcess/API/APIProcessPoolConfiguration.h: * UIProcess/WebProcessPool.cpp: (WebKit::WebProcessPool::ensureNetworkProcess): LayoutTests: * http/wpt/cache-storage/cache-quota.https.any-expected.txt: Added. * http/wpt/cache-storage/cache-quota.https.any.html: Added. * http/wpt/cache-storage/cache-quota.https.any.js: Added. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@223073 268f45cc-cd09-0410-ab3c-d52691b4dbfc