Index: third_party/WebKit/Source/core/frame/History.cpp |
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp |
index 30ebcc037c8ef77fc46f2cb63e954175ea56360a..a9cfa0fe790ecec6a4a9257bbb880d45c56476e2 100644 |
--- a/third_party/WebKit/Source/core/frame/History.cpp |
+++ b/third_party/WebKit/Source/core/frame/History.cpp |
@@ -38,6 +38,8 @@ |
#include "platform/bindings/ScriptState.h" |
#include "platform/weborigin/KURL.h" |
#include "platform/weborigin/SecurityOrigin.h" |
+#include "platform/wtf/CurrentTime.h" |
+#include "platform/wtf/HashMap.h" |
#include "platform/wtf/text/StringView.h" |
namespace blink { |
@@ -116,6 +118,26 @@ HistoryScrollRestorationType History::ScrollRestorationInternal() const { |
: kScrollRestorationAuto; |
} |
+// TODO(crbug.com/394296): This is not the long-term fix to IPC flooding that we |
+// need. However, it does mitigate the immediate concern of |pushState| DoS |
+// (assuming the renderer has not been compromised). |
+bool History::IsHostFloodingPushState(const String& hostname) const { |
+ const int kHostPushStateLimit = 50; |
+ const HostLimit& current = host_limits.at(hostname); |
+ |
+ if (current.first > kHostPushStateLimit) { |
+ const double kHostPushStateLimitResetSeconds = 10.0; |
+ double now = MonotonicallyIncreasingTime(); |
+ if (now - current.second > kHostPushStateLimitResetSeconds) { |
+ host_limits.Set(hostname, HostLimit{0, now}); |
+ } |
+ return true; |
+ } |
+ |
+ host_limits.Set(hostname, HostLimit{current.first + 1, current.second}); |
+ return false; |
+} |
+ |
bool History::stateChanged() const { |
return last_state_object_requested_ != StateInternal(); |
} |
@@ -216,6 +238,11 @@ void History::StateObjectAdded(PassRefPtr<SerializedScriptValue> data, |
!GetFrame()->Loader().GetDocumentLoader()) |
return; |
+ if (IsHostFloodingPushState( |
+ GetFrame()->GetDocument()->GetSecurityOrigin()->Host())) { |
+ return; |
+ } |
+ |
KURL full_url = UrlForState(url_string); |
if (!CanChangeToUrl(full_url, GetFrame()->GetDocument()->GetSecurityOrigin(), |
GetFrame()->GetDocument()->Url())) { |