| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/subresource_filter/content/browser/content_subresource_filt
er_driver_factory.h" | 5 #include "components/subresource_filter/content/browser/content_subresource_filt
er_driver_factory.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
| 9 #include "base/time/time.h" | 9 #include "base/time/time.h" |
| 10 #include "components/subresource_filter/content/browser/content_activation_list_
utils.h" |
| 10 #include "components/subresource_filter/content/browser/subresource_filter_clien
t.h" | 11 #include "components/subresource_filter/content/browser/subresource_filter_clien
t.h" |
| 11 #include "components/subresource_filter/content/common/subresource_filter_messag
es.h" | 12 #include "components/subresource_filter/content/common/subresource_filter_messag
es.h" |
| 12 #include "components/subresource_filter/core/browser/subresource_filter_features
.h" | 13 #include "components/subresource_filter/core/browser/subresource_filter_features
.h" |
| 13 #include "components/subresource_filter/core/common/activation_list.h" | 14 #include "components/subresource_filter/core/common/activation_list.h" |
| 14 #include "components/subresource_filter/core/common/time_measurements.h" | 15 #include "components/subresource_filter/core/common/time_measurements.h" |
| 15 #include "content/public/browser/navigation_handle.h" | 16 #include "content/public/browser/navigation_handle.h" |
| 16 #include "content/public/browser/render_frame_host.h" | 17 #include "content/public/browser/render_frame_host.h" |
| 17 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" |
| 18 #include "ipc/ipc_message_macros.h" | 19 #include "ipc/ipc_message_macros.h" |
| 19 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 34 // ThreadTicks is supported, otherwise returns false. | 35 // ThreadTicks is supported, otherwise returns false. |
| 35 bool ShouldMeasurePerformanceForPageLoad() { | 36 bool ShouldMeasurePerformanceForPageLoad() { |
| 36 if (!base::ThreadTicks::IsSupported()) | 37 if (!base::ThreadTicks::IsSupported()) |
| 37 return false; | 38 return false; |
| 38 // TODO(pkalinnikov): Cache |rate| and other variation params in | 39 // TODO(pkalinnikov): Cache |rate| and other variation params in |
| 39 // ContentSubresourceFilterDriverFactory. | 40 // ContentSubresourceFilterDriverFactory. |
| 40 const double rate = GetPerformanceMeasurementRate(); | 41 const double rate = GetPerformanceMeasurementRate(); |
| 41 return rate == 1 || (rate > 0 && base::RandDouble() < rate); | 42 return rate == 1 || (rate > 0 && base::RandDouble() < rate); |
| 42 } | 43 } |
| 43 | 44 |
| 45 // Records histograms about the length of redirect chains, and about the pattern |
| 46 // of whether each URL in the chain matched the activation list. |
| 47 #define REPORT_REDIRECT_PATTERN_FOR_SUFFIX(suffix, hits_pattern, chain_size) \ |
| 48 do { \ |
| 49 UMA_HISTOGRAM_ENUMERATION( \ |
| 50 "SubresourceFilter.PageLoad.RedirectChainMatchPattern." suffix, \ |
| 51 hits_pattern, 0x10); \ |
| 52 UMA_HISTOGRAM_COUNTS( \ |
| 53 "SubresourceFilter.PageLoad.RedirectChainLength." suffix, chain_size); \ |
| 54 } while (0) |
| 55 |
| 44 } // namespace | 56 } // namespace |
| 45 | 57 |
| 46 // static | 58 // static |
| 47 void ContentSubresourceFilterDriverFactory::CreateForWebContents( | 59 void ContentSubresourceFilterDriverFactory::CreateForWebContents( |
| 48 content::WebContents* web_contents, | 60 content::WebContents* web_contents, |
| 49 std::unique_ptr<SubresourceFilterClient> client) { | 61 std::unique_ptr<SubresourceFilterClient> client) { |
| 50 if (FromWebContents(web_contents)) | 62 if (FromWebContents(web_contents)) |
| 51 return; | 63 return; |
| 52 web_contents->SetUserData(kWebContentsUserDataKey, | 64 web_contents->SetUserData(kWebContentsUserDataKey, |
| 53 new ContentSubresourceFilterDriverFactory( | 65 new ContentSubresourceFilterDriverFactory( |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 const GURL& url) const { | 125 const GURL& url) const { |
| 114 return whitelisted_hosts_.find(url.host()) != whitelisted_hosts_.end(); | 126 return whitelisted_hosts_.find(url.host()) != whitelisted_hosts_.end(); |
| 115 } | 127 } |
| 116 | 128 |
| 117 void ContentSubresourceFilterDriverFactory:: | 129 void ContentSubresourceFilterDriverFactory:: |
| 118 OnMainResourceMatchedSafeBrowsingBlacklist( | 130 OnMainResourceMatchedSafeBrowsingBlacklist( |
| 119 const GURL& url, | 131 const GURL& url, |
| 120 const std::vector<GURL>& redirect_urls, | 132 const std::vector<GURL>& redirect_urls, |
| 121 safe_browsing::SBThreatType threat_type, | 133 safe_browsing::SBThreatType threat_type, |
| 122 safe_browsing::ThreatPatternType threat_type_metadata) { | 134 safe_browsing::ThreatPatternType threat_type_metadata) { |
| 123 bool is_phishing_interstitial = | 135 AddActivationListMatch( |
| 124 (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING); | 136 url, GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata)); |
| 125 bool is_soc_engineering_ads_interstitial = | |
| 126 threat_type_metadata == | |
| 127 safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS; | |
| 128 | |
| 129 if (is_phishing_interstitial) { | |
| 130 if (is_soc_engineering_ads_interstitial) { | |
| 131 AddActivationListMatch(url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL); | |
| 132 } | |
| 133 AddActivationListMatch(url, ActivationList::PHISHING_INTERSTITIAL); | |
| 134 } | |
| 135 } | 137 } |
| 136 | 138 |
| 137 void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet( | 139 void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet( |
| 138 const GURL& url) { | 140 const GURL& url) { |
| 139 if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) | 141 if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) |
| 140 whitelisted_hosts_.insert(url.host()); | 142 whitelisted_hosts_.insert(url.host()); |
| 141 } | 143 } |
| 142 | 144 |
| 143 ContentSubresourceFilterDriverFactory::ActivationDecision | 145 ContentSubresourceFilterDriverFactory::ActivationDecision |
| 144 ContentSubresourceFilterDriverFactory::ComputeActivationDecisionForMainFrameURL( | 146 ContentSubresourceFilterDriverFactory::ComputeActivationDecisionForMainFrameURL( |
| 145 const GURL& url) const { | 147 const GURL& url) const { |
| 146 if (GetMaximumActivationLevel() == ActivationLevel::DISABLED) | 148 if (GetMaximumActivationLevel() == ActivationLevel::DISABLED) |
| 147 return ActivationDecision::ACTIVATION_DISABLED; | 149 return ActivationDecision::ACTIVATION_DISABLED; |
| 148 | 150 |
| 149 ActivationScope scope = GetCurrentActivationScope(); | 151 ActivationScope scope = GetCurrentActivationScope(); |
| 150 if (scope == ActivationScope::NO_SITES) | 152 if (scope == ActivationScope::NO_SITES) |
| 151 return ActivationDecision::ACTIVATION_DISABLED; | 153 return ActivationDecision::ACTIVATION_DISABLED; |
| 152 | 154 |
| 153 if (!url.SchemeIsHTTPOrHTTPS()) | 155 if (!url.SchemeIsHTTPOrHTTPS()) |
| 154 return ActivationDecision::UNSUPPORTED_SCHEME; | 156 return ActivationDecision::UNSUPPORTED_SCHEME; |
| 155 if (IsWhitelisted(url)) | 157 if (IsWhitelisted(url)) |
| 156 return ActivationDecision::URL_WHITELISTED; | 158 return ActivationDecision::URL_WHITELISTED; |
| 157 | 159 |
| 158 switch (scope) { | 160 switch (scope) { |
| 159 case ActivationScope::ALL_SITES: | 161 case ActivationScope::ALL_SITES: |
| 160 return ActivationDecision::ACTIVATED; | 162 return ActivationDecision::ACTIVATED; |
| 161 case ActivationScope::ACTIVATION_LIST: | 163 case ActivationScope::ACTIVATION_LIST: { |
| 162 // The logic to ensure only http/https URLs are activated lives in | 164 // The logic to ensure only http/https URLs are activated lives in |
| 163 // AddActivationListMatch to ensure the activation list only has relevant | 165 // AddActivationListMatch to ensure the activation list only has relevant |
| 164 // entries. | 166 // entries. |
| 165 DCHECK(url.SchemeIsHTTPOrHTTPS() || | 167 DCHECK(url.SchemeIsHTTPOrHTTPS() || |
| 166 !DidURLMatchCurrentActivationList(url)); | 168 !DidURLMatchActivationList(url, GetCurrentActivationList())); |
| 167 return DidURLMatchCurrentActivationList(url) | 169 bool should_activate = |
| 168 ? ActivationDecision::ACTIVATED | 170 DidURLMatchActivationList(url, GetCurrentActivationList()); |
| 169 : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED; | 171 if (GetCurrentActivationList() == ActivationList::PHISHING_INTERSTITIAL) { |
| 172 // Handling special case, where activation on the phishing sites also |
| 173 // mean the activation on the sites with social engineering metadata. |
| 174 should_activate |= DidURLMatchActivationList( |
| 175 url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL); |
| 176 } |
| 177 return should_activate ? ActivationDecision::ACTIVATED |
| 178 : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED; |
| 179 } |
| 170 default: | 180 default: |
| 171 return ActivationDecision::ACTIVATION_DISABLED; | 181 return ActivationDecision::ACTIVATION_DISABLED; |
| 172 } | 182 } |
| 173 } | 183 } |
| 174 | 184 |
| 175 void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded( | 185 void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded( |
| 176 content::RenderFrameHost* render_frame_host, | 186 content::RenderFrameHost* render_frame_host, |
| 177 const GURL& url) { | 187 const GURL& url) { |
| 178 if (activation_level_ != ActivationLevel::DISABLED) { | 188 if (activation_level_ != ActivationLevel::DISABLED) { |
| 179 render_frame_host->Send( | 189 render_frame_host->Send( |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 ResetActivationState(); | 324 ResetActivationState(); |
| 315 return; | 325 return; |
| 316 } | 326 } |
| 317 | 327 |
| 318 activation_level_ = GetMaximumActivationLevel(); | 328 activation_level_ = GetMaximumActivationLevel(); |
| 319 measure_performance_ = activation_level_ != ActivationLevel::DISABLED && | 329 measure_performance_ = activation_level_ != ActivationLevel::DISABLED && |
| 320 ShouldMeasurePerformanceForPageLoad(); | 330 ShouldMeasurePerformanceForPageLoad(); |
| 321 ActivateForFrameHostIfNeeded(render_frame_host, url); | 331 ActivateForFrameHostIfNeeded(render_frame_host, url); |
| 322 } | 332 } |
| 323 | 333 |
| 324 bool ContentSubresourceFilterDriverFactory::DidURLMatchCurrentActivationList( | 334 bool ContentSubresourceFilterDriverFactory::DidURLMatchActivationList( |
| 325 const GURL& url) const { | 335 const GURL& url, |
| 336 ActivationList activation_list) const { |
| 326 auto match_types = | 337 auto match_types = |
| 327 activation_list_matches_.find(DistillURLToHostAndPath(url)); | 338 activation_list_matches_.find(DistillURLToHostAndPath(url)); |
| 328 return match_types != activation_list_matches_.end() && | 339 return match_types != activation_list_matches_.end() && |
| 329 match_types->second.find(GetCurrentActivationList()) != | 340 match_types->second.find(activation_list) != match_types->second.end(); |
| 330 match_types->second.end(); | |
| 331 } | 341 } |
| 332 | 342 |
| 333 void ContentSubresourceFilterDriverFactory::AddActivationListMatch( | 343 void ContentSubresourceFilterDriverFactory::AddActivationListMatch( |
| 334 const GURL& url, | 344 const GURL& url, |
| 335 ActivationList match_type) { | 345 ActivationList match_type) { |
| 346 if (match_type == ActivationList::NONE) |
| 347 return; |
| 336 if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) | 348 if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) |
| 337 activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type); | 349 activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type); |
| 338 } | 350 } |
| 339 | 351 |
| 340 void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern() | 352 int ContentSubresourceFilterDriverFactory::CalculateHitPatternForActivationList( |
| 341 const { | 353 ActivationList activation_list) const { |
| 342 int hits_pattern = 0; | 354 int hits_pattern = 0; |
| 343 const int kInitialURLHitMask = 0x4; | 355 const int kInitialURLHitMask = 0x4; |
| 344 const int kRedirectURLHitMask = 0x2; | 356 const int kRedirectURLHitMask = 0x2; |
| 345 const int kFinalURLHitMask = 0x1; | 357 const int kFinalURLHitMask = 0x1; |
| 346 if (navigation_chain_.size() > 1) { | 358 if (navigation_chain_.size() > 1) { |
| 347 if (DidURLMatchCurrentActivationList(navigation_chain_.back())) | 359 if (DidURLMatchActivationList(navigation_chain_.back(), activation_list)) |
| 348 hits_pattern |= kFinalURLHitMask; | 360 hits_pattern |= kFinalURLHitMask; |
| 349 if (DidURLMatchCurrentActivationList(navigation_chain_.front())) | 361 if (DidURLMatchActivationList(navigation_chain_.front(), activation_list)) |
| 350 hits_pattern |= kInitialURLHitMask; | 362 hits_pattern |= kInitialURLHitMask; |
| 351 | 363 |
| 352 // Examine redirects. | 364 // Examine redirects. |
| 353 for (size_t i = 1; i < navigation_chain_.size() - 1; ++i) { | 365 for (size_t i = 1; i < navigation_chain_.size() - 1; ++i) { |
| 354 if (DidURLMatchCurrentActivationList(navigation_chain_[i])) { | 366 if (DidURLMatchActivationList(navigation_chain_[i], activation_list)) { |
| 355 hits_pattern |= kRedirectURLHitMask; | 367 hits_pattern |= kRedirectURLHitMask; |
| 356 break; | 368 break; |
| 357 } | 369 } |
| 358 } | 370 } |
| 359 } else { | 371 } else { |
| 360 if (navigation_chain_.size() && | 372 if (navigation_chain_.size() && |
| 361 DidURLMatchCurrentActivationList(navigation_chain_.front())) { | 373 DidURLMatchActivationList(navigation_chain_.front(), activation_list)) { |
| 362 hits_pattern = 0x8; // One url hit. | 374 hits_pattern = 0x8; // One url hit. |
| 363 } | 375 } |
| 364 } | 376 } |
| 377 return hits_pattern; |
| 378 } |
| 379 |
| 380 void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern() |
| 381 const { |
| 382 RecordRedirectChainMatchPatternForList( |
| 383 ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL); |
| 384 RecordRedirectChainMatchPatternForList(ActivationList::PHISHING_INTERSTITIAL); |
| 385 } |
| 386 |
| 387 void ContentSubresourceFilterDriverFactory:: |
| 388 RecordRedirectChainMatchPatternForList( |
| 389 ActivationList activation_list) const { |
| 390 int hits_pattern = CalculateHitPatternForActivationList(activation_list); |
| 365 if (!hits_pattern) | 391 if (!hits_pattern) |
| 366 return; | 392 return; |
| 367 UMA_HISTOGRAM_ENUMERATION( | 393 size_t chain_size = navigation_chain_.size(); |
| 368 "SubresourceFilter.PageLoad.RedirectChainMatchPattern", hits_pattern, | 394 switch (activation_list) { |
| 369 0x10 /* max value */); | 395 case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL: |
| 370 UMA_HISTOGRAM_COUNTS("SubresourceFilter.PageLoad.RedirectChainLength", | 396 REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SocialEngineeringAdsInterstitial", |
| 371 navigation_chain_.size()); | 397 hits_pattern, chain_size); |
| 398 break; |
| 399 case ActivationList::PHISHING_INTERSTITIAL: |
| 400 REPORT_REDIRECT_PATTERN_FOR_SUFFIX("PhishingInterstital", hits_pattern, |
| 401 chain_size); |
| 402 break; |
| 403 default: |
| 404 NOTREACHED(); |
| 405 break; |
| 406 } |
| 372 } | 407 } |
| 373 | 408 |
| 374 } // namespace subresource_filter | 409 } // namespace subresource_filter |
| OLD | NEW |