Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/safe_browsing/client_side_detection_host.h" | 5 #include "chrome/browser/safe_browsing/client_side_detection_host.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/prefs/pref_service.h" | 13 #include "base/prefs/pref_service.h" |
| 14 #include "base/sequenced_task_runner_helpers.h" | 14 #include "base/sequenced_task_runner_helpers.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/browser/safe_browsing/browser_feature_extractor.h" | 18 #include "chrome/browser/safe_browsing/browser_feature_extractor.h" |
| 19 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | 19 #include "chrome/browser/safe_browsing/client_side_detection_service.h" |
| 20 #include "chrome/browser/safe_browsing/database_manager.h" | 20 #include "chrome/browser/safe_browsing/database_manager.h" |
| 21 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 21 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| 22 #include "chrome/common/chrome_switches.h" | |
| 23 #include "chrome/common/chrome_version_info.h" | |
| 24 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
| 25 #include "chrome/common/safe_browsing/csd.pb.h" | 23 #include "chrome/common/safe_browsing/csd.pb.h" |
| 26 #include "chrome/common/safe_browsing/safebrowsing_messages.h" | 24 #include "chrome/common/safe_browsing/safebrowsing_messages.h" |
| 27 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 28 #include "content/public/browser/navigation_controller.h" | 26 #include "content/public/browser/navigation_controller.h" |
| 29 #include "content/public/browser/navigation_details.h" | 27 #include "content/public/browser/navigation_details.h" |
| 30 #include "content/public/browser/navigation_entry.h" | 28 #include "content/public/browser/navigation_entry.h" |
| 31 #include "content/public/browser/notification_details.h" | 29 #include "content/public/browser/notification_details.h" |
| 32 #include "content/public/browser/notification_source.h" | 30 #include "content/public/browser/notification_source.h" |
| 33 #include "content/public/browser/notification_types.h" | 31 #include "content/public/browser/notification_types.h" |
| 34 #include "content/public/browser/render_process_host.h" | 32 #include "content/public/browser/render_process_host.h" |
| 35 #include "content/public/browser/render_view_host.h" | 33 #include "content/public/browser/render_view_host.h" |
| 36 #include "content/public/browser/resource_request_details.h" | 34 #include "content/public/browser/resource_request_details.h" |
| 37 #include "content/public/browser/web_contents.h" | 35 #include "content/public/browser/web_contents.h" |
| 38 #include "content/public/common/frame_navigate_params.h" | 36 #include "content/public/common/frame_navigate_params.h" |
| 37 #include "content/public/common/url_constants.h" | |
| 39 #include "url/gurl.h" | 38 #include "url/gurl.h" |
| 40 | 39 |
| 41 using content::BrowserThread; | 40 using content::BrowserThread; |
| 42 using content::NavigationEntry; | 41 using content::NavigationEntry; |
| 43 using content::ResourceRequestDetails; | 42 using content::ResourceRequestDetails; |
| 44 using content::WebContents; | 43 using content::WebContents; |
| 45 | 44 |
| 46 namespace safe_browsing { | 45 namespace safe_browsing { |
| 47 | 46 |
| 48 const int ClientSideDetectionHost::kMaxUrlsPerIP = 20; | 47 const int ClientSideDetectionHost::kMaxUrlsPerIP = 20; |
| 49 const int ClientSideDetectionHost::kMaxIPsPerBrowse = 200; | 48 const int ClientSideDetectionHost::kMaxIPsPerBrowse = 200; |
| 50 | 49 |
| 51 const char kSafeBrowsingMatchKey[] = "safe_browsing_match"; | 50 const char kSafeBrowsingMatchKey[] = "safe_browsing_match"; |
| 52 | 51 |
| 52 typedef base::Callback<void(bool)> ShouldClassifyUrlCallback; | |
| 53 | |
| 53 // This class is instantiated each time a new toplevel URL loads, and | 54 // This class is instantiated each time a new toplevel URL loads, and |
| 54 // asynchronously checks whether the phishing classifier should run for this | 55 // asynchronously checks whether the malware and phishing classifiers should run |
| 55 // URL. If so, it notifies the renderer with a StartPhishingDetection IPC. | 56 // for this URL. If so, it notifies the host class by calling the provided |
| 56 // Objects of this class are ref-counted and will be destroyed once nobody | 57 // callback form the UI thread. Objects of this class are ref-counted and will |
| 57 // uses it anymore. If |web_contents|, |csd_service| or |host| go away you need | 58 // be destroyed once nobody uses it anymore. If |web_contents|, |csd_service| |
| 58 // to call Cancel(). We keep the |database_manager| alive in a ref pointer for | 59 // or |host| go away you need to call Cancel(). We keep the |database_manager| |
| 59 // as long as it takes. | 60 // alive in a ref pointer for as long as it takes. |
| 60 class ClientSideDetectionHost::ShouldClassifyUrlRequest | 61 class ClientSideDetectionHost::ShouldClassifyUrlRequest |
| 61 : public base::RefCountedThreadSafe< | 62 : public base::RefCountedThreadSafe< |
| 62 ClientSideDetectionHost::ShouldClassifyUrlRequest> { | 63 ClientSideDetectionHost::ShouldClassifyUrlRequest> { |
| 63 public: | 64 public: |
| 64 ShouldClassifyUrlRequest(const content::FrameNavigateParams& params, | 65 ShouldClassifyUrlRequest( |
| 65 WebContents* web_contents, | 66 const content::FrameNavigateParams& params, |
| 66 ClientSideDetectionService* csd_service, | 67 const ShouldClassifyUrlCallback& start_phishing_classification, |
| 67 SafeBrowsingDatabaseManager* database_manager, | 68 const ShouldClassifyUrlCallback& start_malware_classification, |
| 68 ClientSideDetectionHost* host) | 69 WebContents* web_contents, |
| 69 : canceled_(false), | 70 ClientSideDetectionService* csd_service, |
| 70 params_(params), | 71 SafeBrowsingDatabaseManager* database_manager, |
| 72 ClientSideDetectionHost* host) | |
| 73 : params_(params), | |
| 71 web_contents_(web_contents), | 74 web_contents_(web_contents), |
| 72 csd_service_(csd_service), | 75 csd_service_(csd_service), |
| 73 database_manager_(database_manager), | 76 database_manager_(database_manager), |
| 74 host_(host) { | 77 host_(host), |
| 78 start_phishing_classification_cb_(start_phishing_classification), | |
| 79 start_malware_classification_cb_(start_malware_classification) { | |
| 75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 76 DCHECK(web_contents_); | 81 DCHECK(web_contents_); |
| 77 DCHECK(csd_service_); | 82 DCHECK(csd_service_); |
| 78 DCHECK(database_manager_.get()); | 83 DCHECK(database_manager_.get()); |
| 79 DCHECK(host_); | 84 DCHECK(host_); |
| 80 } | 85 } |
| 81 | 86 |
| 82 void Start() { | 87 void Start() { |
| 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 84 | 89 |
| 85 // We start by doing some simple checks that can run on the UI thread. | 90 // We start by doing some simple checks that can run on the UI thread. |
| 86 UMA_HISTOGRAM_COUNTS("SBClientPhishing.ClassificationStart", 1); | 91 UMA_HISTOGRAM_COUNTS("SBClientPhishing.ClassificationStart", 1); |
| 92 UMA_HISTOGRAM_COUNTS("SBClientMalware.ClassificationStart", 1); | |
|
Alexei Svitkine (slow)
2014/03/25 13:51:39
Is there a plan for this to eventually be somethin
noé
2014/03/25 15:54:25
Mostly copy & paste from the other histogram above
Alexei Svitkine (slow)
2014/03/25 16:43:03
I suggest UMA_HISTOGRAM_BOOLEAN().
If you look at
noé
2014/03/25 20:23:11
Thanks for the tip. I changed a handful of histog
| |
| 87 | 93 |
| 88 // Only classify [X]HTML documents. | 94 // Only classify [X]HTML documents. |
| 89 if (params_.contents_mime_type != "text/html" && | 95 if (params_.contents_mime_type != "text/html" && |
| 90 params_.contents_mime_type != "application/xhtml+xml") { | 96 params_.contents_mime_type != "application/xhtml+xml") { |
| 91 VLOG(1) << "Skipping phishing classification for URL: " << params_.url | 97 VLOG(1) << "Skipping phishing classification for URL: " << params_.url |
| 92 << " because it has an unsupported MIME type: " | 98 << " because it has an unsupported MIME type: " |
| 93 << params_.contents_mime_type; | 99 << params_.contents_mime_type; |
| 94 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | 100 DontClassifyForPhishing(NO_CLASSIFY_UNSUPPORTED_MIME_TYPE); |
| 95 NO_CLASSIFY_UNSUPPORTED_MIME_TYPE, | |
| 96 NO_CLASSIFY_MAX); | |
| 97 return; | |
| 98 } | 101 } |
| 99 | 102 |
| 100 if (csd_service_->IsPrivateIPAddress(params_.socket_address.host())) { | 103 if (csd_service_->IsPrivateIPAddress(params_.socket_address.host())) { |
| 101 VLOG(1) << "Skipping phishing classification for URL: " << params_.url | 104 VLOG(1) << "Skipping phishing classification for URL: " << params_.url |
| 102 << " because of hosting on private IP: " | 105 << " because of hosting on private IP: " |
| 103 << params_.socket_address.host(); | 106 << params_.socket_address.host(); |
| 104 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | 107 DontClassifyForPhishing(NO_CLASSIFY_PRIVATE_IP); |
| 105 NO_CLASSIFY_PRIVATE_IP, | 108 DontClassifyForMalware(NO_CLASSIFY_PRIVATE_IP); |
| 106 NO_CLASSIFY_MAX); | |
| 107 return; | |
| 108 } | 109 } |
| 109 | 110 |
| 110 // Don't run the phishing classifier if the tab is incognito. | 111 // For phishing we only classify HTTP pages. |
| 112 if (!params_.url.SchemeIs(content::kHttpScheme)) { | |
| 113 VLOG(1) << "Skipping phishing classification for URL: " << params_.url | |
| 114 << " because it is not HTTP: " | |
| 115 << params_.socket_address.host(); | |
| 116 DontClassifyForPhishing(NO_CLASSIFY_NOT_HTTP_URL); | |
| 117 } | |
| 118 | |
| 119 // Don't run any classifier if the tab is incognito. | |
| 111 if (web_contents_->GetBrowserContext()->IsOffTheRecord()) { | 120 if (web_contents_->GetBrowserContext()->IsOffTheRecord()) { |
| 112 VLOG(1) << "Skipping phishing classification for URL: " << params_.url | 121 VLOG(1) << "Skipping phishing and malware classification for URL: " |
| 113 << " because we're browsing incognito."; | 122 << params_.url << " because we're browsing incognito."; |
| 114 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | 123 DontClassifyForPhishing(NO_CLASSIFY_OFF_THE_RECORD); |
| 115 NO_CLASSIFY_OFF_THE_RECORD, | 124 DontClassifyForMalware(NO_CLASSIFY_OFF_THE_RECORD); |
| 116 NO_CLASSIFY_MAX); | |
| 117 | |
| 118 return; | |
| 119 } | 125 } |
| 120 | 126 |
| 121 // We lookup the csd-whitelist before we lookup the cache because | 127 // We lookup the csd-whitelist before we lookup the cache because |
| 122 // a URL may have recently been whitelisted. If the URL matches | 128 // a URL may have recently been whitelisted. If the URL matches |
| 123 // the csd-whitelist we won't start classification. The | 129 // the csd-whitelist we won't start phishing classification. The |
| 124 // csd-whitelist check has to be done on the IO thread because it | 130 // csd-whitelist check has to be done on the IO thread because it |
| 125 // uses the SafeBrowsing service class. | 131 // uses the SafeBrowsing service class. |
| 126 BrowserThread::PostTask( | 132 if (ShouldClassifyForPhishing() || ShouldClassifyForMalware()) { |
| 127 BrowserThread::IO, | 133 BrowserThread::PostTask( |
| 128 FROM_HERE, | 134 BrowserThread::IO, |
| 129 base::Bind(&ShouldClassifyUrlRequest::CheckCsdWhitelist, | 135 FROM_HERE, |
| 130 this, params_.url)); | 136 base::Bind(&ShouldClassifyUrlRequest::CheckSafeBrowsingDatabase, |
| 137 this, params_.url)); | |
| 138 } | |
| 131 } | 139 } |
| 132 | 140 |
| 133 void Cancel() { | 141 void Cancel() { |
| 134 canceled_ = true; | 142 DontClassifyForPhishing(NO_CLASSIFY_CANCEL); |
| 143 DontClassifyForMalware(NO_CLASSIFY_CANCEL); | |
| 135 // Just to make sure we don't do anything stupid we reset all these | 144 // Just to make sure we don't do anything stupid we reset all these |
| 136 // pointers except for the safebrowsing service class which may be | 145 // pointers except for the safebrowsing service class which may be |
| 137 // accessed by CheckCsdWhitelist(). | 146 // accessed by CheckSafeBrowsingDatabase(). |
| 138 web_contents_ = NULL; | 147 web_contents_ = NULL; |
| 139 csd_service_ = NULL; | 148 csd_service_ = NULL; |
| 140 host_ = NULL; | 149 host_ = NULL; |
| 141 } | 150 } |
| 142 | 151 |
| 143 private: | 152 private: |
| 144 friend class base::RefCountedThreadSafe< | 153 friend class base::RefCountedThreadSafe< |
| 145 ClientSideDetectionHost::ShouldClassifyUrlRequest>; | 154 ClientSideDetectionHost::ShouldClassifyUrlRequest>; |
| 146 | 155 |
| 147 // Enum used to keep stats about why the pre-classification check failed. | 156 // Enum used to keep stats about why the pre-classification check failed. |
| 148 enum PreClassificationCheckFailures { | 157 enum PreClassificationCheckFailures { |
| 149 OBSOLETE_NO_CLASSIFY_PROXY_FETCH, | 158 OBSOLETE_NO_CLASSIFY_PROXY_FETCH, |
| 150 NO_CLASSIFY_PRIVATE_IP, | 159 NO_CLASSIFY_PRIVATE_IP, |
| 151 NO_CLASSIFY_OFF_THE_RECORD, | 160 NO_CLASSIFY_OFF_THE_RECORD, |
| 152 NO_CLASSIFY_MATCH_CSD_WHITELIST, | 161 NO_CLASSIFY_MATCH_CSD_WHITELIST, |
| 153 NO_CLASSIFY_TOO_MANY_REPORTS, | 162 NO_CLASSIFY_TOO_MANY_REPORTS, |
| 154 NO_CLASSIFY_UNSUPPORTED_MIME_TYPE, | 163 NO_CLASSIFY_UNSUPPORTED_MIME_TYPE, |
| 164 NO_CLASSIFY_NO_DATABASE_MANAGER, | |
| 165 NO_CLASSIFY_KILLSWITCH, | |
| 166 NO_CLASSIFY_CANCEL, | |
| 167 NO_CLASSIFY_RESULT_FROM_CACHE, | |
| 168 NO_CLASSIFY_NOT_HTTP_URL, | |
| 155 | 169 |
| 156 NO_CLASSIFY_MAX // Always add new values before this one. | 170 NO_CLASSIFY_MAX // Always add new values before this one. |
| 157 }; | 171 }; |
| 158 | 172 |
| 159 // The destructor can be called either from the UI or the IO thread. | 173 // The destructor can be called either from the UI or the IO thread. |
| 160 virtual ~ShouldClassifyUrlRequest() { } | 174 virtual ~ShouldClassifyUrlRequest() { } |
| 161 | 175 |
| 162 void CheckCsdWhitelist(const GURL& url) { | 176 bool ShouldClassifyForPhishing() const { |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 178 return !start_phishing_classification_cb_.is_null(); | |
| 179 } | |
| 180 | |
| 181 bool ShouldClassifyForMalware() const { | |
| 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 183 return !start_malware_classification_cb_.is_null(); | |
| 184 } | |
| 185 | |
| 186 void DontClassifyForPhishing(PreClassificationCheckFailures reason) { | |
| 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 188 if (ShouldClassifyForPhishing()) { | |
| 189 // Track the first reason why we stopped classifying for phishing. | |
| 190 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | |
| 191 reason, NO_CLASSIFY_MAX); | |
| 192 DVLOG(2) << "Failed phishing pre-classification checks. Reason: " | |
| 193 << reason; | |
| 194 start_phishing_classification_cb_.Run(false); | |
| 195 } | |
| 196 start_phishing_classification_cb_.Reset(); | |
| 197 } | |
| 198 | |
| 199 void DontClassifyForMalware(PreClassificationCheckFailures reason) { | |
| 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 201 if (ShouldClassifyForMalware()) { | |
| 202 // Track the first reason why we stopped classifying for malware. | |
| 203 UMA_HISTOGRAM_ENUMERATION("SBClientMalware.PreClassificationCheckFail", | |
| 204 reason, NO_CLASSIFY_MAX); | |
| 205 DVLOG(2) << "Failed malware pre-classification checks. Reason: " | |
| 206 << reason; | |
| 207 start_malware_classification_cb_.Run(false); | |
| 208 } | |
| 209 start_malware_classification_cb_.Reset(); | |
| 210 } | |
| 211 | |
| 212 void CheckSafeBrowsingDatabase(const GURL& url) { | |
| 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 164 if (!database_manager_.get() || | 214 // We don't want to call the classification callbacks from the IO |
| 165 database_manager_->MatchCsdWhitelistUrl(url)) { | 215 // thread so we simply pass the results of this method to CheckCache() |
| 166 // We're done. There is no point in going back to the UI thread. | 216 // which is called on the UI thread; |
| 167 VLOG(1) << "Skipping phishing classification for URL: " << url | 217 PreClassificationCheckFailures phishing_reason = NO_CLASSIFY_MAX; |
| 168 << " because it matches the csd whitelist"; | 218 PreClassificationCheckFailures malware_reason = NO_CLASSIFY_MAX; |
| 169 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | 219 if (!database_manager_.get()) { |
| 170 NO_CLASSIFY_MATCH_CSD_WHITELIST, | 220 // We cannot check the Safe Browsing whitelists so we stop here |
| 171 NO_CLASSIFY_MAX); | 221 // for safety. |
| 172 return; | 222 malware_reason = phishing_reason = NO_CLASSIFY_NO_DATABASE_MANAGER; |
| 223 } else { | |
| 224 if (database_manager_->MatchCsdWhitelistUrl(url)) { | |
| 225 VLOG(1) << "Skipping phishing classification for URL: " << url | |
| 226 << " because it matches the csd whitelist"; | |
| 227 phishing_reason = NO_CLASSIFY_MATCH_CSD_WHITELIST; | |
| 228 } | |
| 229 if (database_manager_->IsMalwareKillSwitchOn()) { | |
| 230 malware_reason = NO_CLASSIFY_KILLSWITCH; | |
| 231 } | |
| 173 } | 232 } |
| 174 | |
| 175 bool malware_killswitch_on = database_manager_->IsMalwareKillSwitchOn(); | |
| 176 | |
| 177 BrowserThread::PostTask( | 233 BrowserThread::PostTask( |
| 178 BrowserThread::UI, | 234 BrowserThread::UI, |
| 179 FROM_HERE, | 235 FROM_HERE, |
| 180 base::Bind(&ShouldClassifyUrlRequest::CheckCache, this, | 236 base::Bind(&ShouldClassifyUrlRequest::CheckCache, |
| 181 malware_killswitch_on)); | 237 this, |
| 238 phishing_reason, | |
| 239 malware_reason)); | |
| 182 } | 240 } |
| 183 | 241 |
| 184 void CheckCache(bool malware_killswitch_on) { | 242 void CheckCache(PreClassificationCheckFailures phishing_reason, |
| 243 PreClassificationCheckFailures malware_reason) { | |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 186 if (canceled_) { | 245 if (phishing_reason != NO_CLASSIFY_MAX) |
| 187 return; | 246 DontClassifyForPhishing(phishing_reason); |
| 247 if (malware_reason != NO_CLASSIFY_MAX) | |
| 248 DontClassifyForMalware(malware_reason); | |
| 249 if (!ShouldClassifyForMalware() && !ShouldClassifyForPhishing()) { | |
| 250 return; // No point in doing anything else. | |
| 188 } | 251 } |
| 189 | 252 // If result is cached, we don't want to run classification again. |
| 190 host_->SetMalwareKillSwitch(malware_killswitch_on); | 253 // In that case we're just trying to show the warning. |
| 191 // If result is cached, we don't want to run classification again | |
| 192 bool is_phishing; | 254 bool is_phishing; |
| 193 if (csd_service_->GetValidCachedResult(params_.url, &is_phishing)) { | 255 if (csd_service_->GetValidCachedResult(params_.url, &is_phishing)) { |
| 194 VLOG(1) << "Satisfying request for " << params_.url << " from cache"; | 256 VLOG(1) << "Satisfying request for " << params_.url << " from cache"; |
| 195 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestSatisfiedFromCache", 1); | 257 UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestSatisfiedFromCache", 1); |
| 196 // Since we are already on the UI thread, this is safe. | 258 // Since we are already on the UI thread, this is safe. |
| 197 host_->MaybeShowPhishingWarning(params_.url, is_phishing); | 259 host_->MaybeShowPhishingWarning(params_.url, is_phishing); |
| 198 return; | 260 DontClassifyForPhishing(NO_CLASSIFY_RESULT_FROM_CACHE); |
| 199 } | 261 } |
| 200 | 262 |
| 201 // We want to limit the number of requests, though we will ignore the | 263 // We want to limit the number of requests, though we will ignore the |
| 202 // limit for urls in the cache. We don't want to start classifying | 264 // limit for urls in the cache. We don't want to start classifying |
| 203 // too many pages as phishing, but for those that we already think are | 265 // too many pages as phishing, but for those that we already think are |
| 204 // phishing we want to give ourselves a chance to fix false positives. | 266 // phishing we want to send a request to the server to give ourselves |
| 267 // a chance to fix misclassifications. | |
| 205 if (csd_service_->IsInCache(params_.url)) { | 268 if (csd_service_->IsInCache(params_.url)) { |
| 206 VLOG(1) << "Reporting limit skipped for " << params_.url | 269 VLOG(1) << "Reporting limit skipped for " << params_.url |
| 207 << " as it was in the cache."; | 270 << " as it was in the cache."; |
| 208 UMA_HISTOGRAM_COUNTS("SBClientPhishing.ReportLimitSkipped", 1); | 271 UMA_HISTOGRAM_COUNTS("SBClientPhishing.ReportLimitSkipped", 1); |
| 209 } else if (csd_service_->OverPhishingReportLimit()) { | 272 } else if (csd_service_->OverPhishingReportLimit()) { |
| 210 VLOG(1) << "Too many report phishing requests sent recently, " | 273 VLOG(1) << "Too many report phishing requests sent recently, " |
| 211 << "not running classification for " << params_.url; | 274 << "not running classification for " << params_.url; |
| 212 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.PreClassificationCheckFail", | 275 DontClassifyForPhishing(NO_CLASSIFY_TOO_MANY_REPORTS); |
| 213 NO_CLASSIFY_TOO_MANY_REPORTS, | 276 } |
| 214 NO_CLASSIFY_MAX); | 277 if (csd_service_->OverMalwareReportLimit()) { |
| 215 return; | 278 DontClassifyForMalware(NO_CLASSIFY_TOO_MANY_REPORTS); |
| 216 } | 279 } |
| 217 | 280 |
| 218 // Everything checks out, so start classification. | 281 // Everything checks out, so start classification. |
| 219 // |web_contents_| is safe to call as we will be destructed | 282 // |web_contents_| is safe to call as we will be destructed |
| 220 // before it is. | 283 // before it is. |
| 221 VLOG(1) << "Instruct renderer to start phishing detection for URL: " | 284 if (ShouldClassifyForPhishing()) |
| 222 << params_.url; | 285 start_phishing_classification_cb_.Run(true); |
| 223 content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); | 286 if (ShouldClassifyForMalware()) |
| 224 rvh->Send(new SafeBrowsingMsg_StartPhishingDetection( | 287 start_malware_classification_cb_.Run(true); |
| 225 rvh->GetRoutingID(), params_.url)); | |
| 226 } | 288 } |
| 227 | 289 |
| 228 // No need to protect |canceled_| with a lock because it is only read and | |
| 229 // written by the UI thread. | |
| 230 bool canceled_; | |
| 231 content::FrameNavigateParams params_; | 290 content::FrameNavigateParams params_; |
| 232 WebContents* web_contents_; | 291 WebContents* web_contents_; |
| 233 ClientSideDetectionService* csd_service_; | 292 ClientSideDetectionService* csd_service_; |
| 234 // We keep a ref pointer here just to make sure the safe browsing | 293 // We keep a ref pointer here just to make sure the safe browsing |
| 235 // database manager stays alive long enough. | 294 // database manager stays alive long enough. |
| 236 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; | 295 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; |
| 237 ClientSideDetectionHost* host_; | 296 ClientSideDetectionHost* host_; |
| 238 | 297 |
| 298 ShouldClassifyUrlCallback start_phishing_classification_cb_; | |
| 299 ShouldClassifyUrlCallback start_malware_classification_cb_; | |
| 300 | |
| 239 DISALLOW_COPY_AND_ASSIGN(ShouldClassifyUrlRequest); | 301 DISALLOW_COPY_AND_ASSIGN(ShouldClassifyUrlRequest); |
| 240 }; | 302 }; |
| 241 | 303 |
| 242 // static | 304 // static |
| 243 ClientSideDetectionHost* ClientSideDetectionHost::Create( | 305 ClientSideDetectionHost* ClientSideDetectionHost::Create( |
| 244 WebContents* tab) { | 306 WebContents* tab) { |
| 245 return new ClientSideDetectionHost(tab); | 307 return new ClientSideDetectionHost(tab); |
| 246 } | 308 } |
| 247 | 309 |
| 248 ClientSideDetectionHost::ClientSideDetectionHost(WebContents* tab) | 310 ClientSideDetectionHost::ClientSideDetectionHost(WebContents* tab) |
| 249 : content::WebContentsObserver(tab), | 311 : content::WebContentsObserver(tab), |
| 250 csd_service_(NULL), | 312 csd_service_(NULL), |
| 313 classification_request_(NULL), | |
| 314 should_extract_malware_features_(true), | |
| 315 should_classify_for_malware_(false), | |
| 316 onload_complete_(false), | |
| 251 weak_factory_(this), | 317 weak_factory_(this), |
| 252 unsafe_unique_page_id_(-1), | 318 unsafe_unique_page_id_(-1) { |
| 253 malware_killswitch_on_(false), | |
| 254 malware_report_enabled_(false) { | |
| 255 DCHECK(tab); | 319 DCHECK(tab); |
| 256 // Note: csd_service_ and sb_service will be NULL here in testing. | 320 // Note: csd_service_ and sb_service will be NULL here in testing. |
| 257 csd_service_ = g_browser_process->safe_browsing_detection_service(); | 321 csd_service_ = g_browser_process->safe_browsing_detection_service(); |
| 258 feature_extractor_.reset(new BrowserFeatureExtractor(tab, this)); | 322 feature_extractor_.reset(new BrowserFeatureExtractor(tab, this)); |
| 259 registrar_.Add(this, content::NOTIFICATION_RESOURCE_RESPONSE_STARTED, | 323 registrar_.Add(this, content::NOTIFICATION_RESOURCE_RESPONSE_STARTED, |
| 260 content::Source<WebContents>(tab)); | 324 content::Source<WebContents>(tab)); |
| 261 | 325 |
| 262 scoped_refptr<SafeBrowsingService> sb_service = | 326 scoped_refptr<SafeBrowsingService> sb_service = |
| 263 g_browser_process->safe_browsing_service(); | 327 g_browser_process->safe_browsing_service(); |
| 264 if (sb_service.get()) { | 328 if (sb_service.get()) { |
| 265 ui_manager_ = sb_service->ui_manager(); | 329 ui_manager_ = sb_service->ui_manager(); |
| 266 database_manager_ = sb_service->database_manager(); | 330 database_manager_ = sb_service->database_manager(); |
| 267 ui_manager_->AddObserver(this); | 331 ui_manager_->AddObserver(this); |
| 268 } | 332 } |
| 269 | |
| 270 // Only enable the malware bad IP matching and report feature for canary | |
| 271 // and dev channel. | |
| 272 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | |
| 273 malware_report_enabled_ = ( | |
| 274 channel == chrome::VersionInfo::CHANNEL_DEV || | |
| 275 channel == chrome::VersionInfo::CHANNEL_CANARY); | |
| 276 } | 333 } |
| 277 | 334 |
| 278 ClientSideDetectionHost::~ClientSideDetectionHost() { | 335 ClientSideDetectionHost::~ClientSideDetectionHost() { |
| 279 if (ui_manager_.get()) | 336 if (ui_manager_.get()) |
| 280 ui_manager_->RemoveObserver(this); | 337 ui_manager_->RemoveObserver(this); |
| 281 } | 338 } |
| 282 | 339 |
| 283 bool ClientSideDetectionHost::OnMessageReceived(const IPC::Message& message) { | 340 bool ClientSideDetectionHost::OnMessageReceived(const IPC::Message& message) { |
| 284 bool handled = true; | 341 bool handled = true; |
| 285 IPC_BEGIN_MESSAGE_MAP(ClientSideDetectionHost, message) | 342 IPC_BEGIN_MESSAGE_MAP(ClientSideDetectionHost, message) |
| 286 IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_PhishingDetectionDone, | 343 IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_PhishingDetectionDone, |
| 287 OnPhishingDetectionDone) | 344 OnPhishingDetectionDone) |
| 288 IPC_MESSAGE_UNHANDLED(handled = false) | 345 IPC_MESSAGE_UNHANDLED(handled = false) |
| 289 IPC_END_MESSAGE_MAP() | 346 IPC_END_MESSAGE_MAP() |
| 290 return handled; | 347 return handled; |
| 291 } | 348 } |
| 292 | 349 |
| 293 void ClientSideDetectionHost::DidNavigateMainFrame( | 350 void ClientSideDetectionHost::DidNavigateMainFrame( |
| 294 const content::LoadCommittedDetails& details, | 351 const content::LoadCommittedDetails& details, |
| 295 const content::FrameNavigateParams& params) { | 352 const content::FrameNavigateParams& params) { |
| 296 // TODO(noelutz): move this DCHECK to WebContents and fix all the unit tests | 353 // TODO(noelutz): move this DCHECK to WebContents and fix all the unit tests |
| 297 // that don't call this method on the UI thread. | 354 // that don't call this method on the UI thread. |
| 298 // DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 355 // DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 299 if (details.is_in_page) { | 356 if (details.is_in_page) { |
| 300 // If the navigation is within the same page, the user isn't really | 357 // If the navigation is within the same page, the user isn't really |
| 301 // navigating away. We don't need to cancel a pending callback or | 358 // navigating away. We don't need to cancel a pending callback or |
| 302 // begin a new classification. | 359 // begin a new classification. |
| 303 return; | 360 return; |
| 304 } | 361 } |
| 362 // Cancel any pending classification request. | |
| 363 if (classification_request_.get()) { | |
| 364 classification_request_->Cancel(); | |
| 365 } | |
| 305 // If we navigate away and there currently is a pending phishing | 366 // If we navigate away and there currently is a pending phishing |
| 306 // report request we have to cancel it to make sure we don't display | 367 // report request we have to cancel it to make sure we don't display |
| 307 // an interstitial for the wrong page. Note that this won't cancel | 368 // an interstitial for the wrong page. Note that this won't cancel |
| 308 // the server ping back but only cancel the showing of the | 369 // the server ping back but only cancel the showing of the |
| 309 // interstial. | 370 // interstial. |
| 310 weak_factory_.InvalidateWeakPtrs(); | 371 weak_factory_.InvalidateWeakPtrs(); |
| 311 | 372 |
| 312 if (!csd_service_) { | 373 if (!csd_service_) { |
| 313 return; | 374 return; |
| 314 } | 375 } |
| 315 | |
| 316 // Cancel any pending classification request. | |
| 317 if (classification_request_.get()) { | |
| 318 classification_request_->Cancel(); | |
| 319 } | |
| 320 browse_info_.reset(new BrowseInfo); | 376 browse_info_.reset(new BrowseInfo); |
| 321 | 377 |
| 322 // Store redirect chain information. | 378 // Store redirect chain information. |
| 323 if (params.url.host() != cur_host_) { | 379 if (params.url.host() != cur_host_) { |
| 324 cur_host_ = params.url.host(); | 380 cur_host_ = params.url.host(); |
| 325 cur_host_redirects_ = params.redirects; | 381 cur_host_redirects_ = params.redirects; |
| 326 } | 382 } |
| 383 browse_info_->url = params.url; | |
| 327 browse_info_->host_redirects = cur_host_redirects_; | 384 browse_info_->host_redirects = cur_host_redirects_; |
| 328 browse_info_->url_redirects = params.redirects; | 385 browse_info_->url_redirects = params.redirects; |
| 329 browse_info_->referrer = params.referrer.url; | 386 browse_info_->referrer = params.referrer.url; |
| 330 browse_info_->http_status_code = details.http_status_code; | 387 browse_info_->http_status_code = details.http_status_code; |
| 388 browse_info_->page_id = params.page_id; | |
| 331 | 389 |
| 332 // Notify the renderer if it should classify this URL. | 390 should_extract_malware_features_ = true; |
| 391 should_classify_for_malware_ = false; | |
| 392 onload_complete_ = false; | |
| 393 | |
| 394 // Check whether we can cassify the current URL for phishing or malware. | |
| 333 classification_request_ = new ShouldClassifyUrlRequest( | 395 classification_request_ = new ShouldClassifyUrlRequest( |
| 334 params, web_contents(), csd_service_, database_manager_.get(), this); | 396 params, |
| 397 base::Bind(&ClientSideDetectionHost::OnPhishingPreClassificationDone, | |
| 398 weak_factory_.GetWeakPtr()), | |
| 399 base::Bind(&ClientSideDetectionHost::OnMalwarePreClassificationDone, | |
| 400 weak_factory_.GetWeakPtr()), | |
| 401 web_contents(), csd_service_, database_manager_.get(), this); | |
| 335 classification_request_->Start(); | 402 classification_request_->Start(); |
| 336 } | 403 } |
| 337 | 404 |
| 338 void ClientSideDetectionHost::OnSafeBrowsingHit( | 405 void ClientSideDetectionHost::OnSafeBrowsingHit( |
| 339 const SafeBrowsingUIManager::UnsafeResource& resource) { | 406 const SafeBrowsingUIManager::UnsafeResource& resource) { |
| 340 if (!web_contents() || !web_contents()->GetController().GetActiveEntry()) | 407 if (!web_contents() || !web_contents()->GetController().GetActiveEntry()) |
| 341 return; | 408 return; |
| 342 | 409 |
| 343 // Check that the hit is either malware or phishing. | 410 // Check that the hit is either malware or phishing. |
| 344 if (resource.threat_type != SB_THREAT_TYPE_URL_PHISHING && | 411 if (resource.threat_type != SB_THREAT_TYPE_URL_PHISHING && |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 407 void ClientSideDetectionHost::WebContentsDestroyed(WebContents* tab) { | 474 void ClientSideDetectionHost::WebContentsDestroyed(WebContents* tab) { |
| 408 DCHECK(tab); | 475 DCHECK(tab); |
| 409 // Tell any pending classification request that it is being canceled. | 476 // Tell any pending classification request that it is being canceled. |
| 410 if (classification_request_.get()) { | 477 if (classification_request_.get()) { |
| 411 classification_request_->Cancel(); | 478 classification_request_->Cancel(); |
| 412 } | 479 } |
| 413 // Cancel all pending feature extractions. | 480 // Cancel all pending feature extractions. |
| 414 feature_extractor_.reset(); | 481 feature_extractor_.reset(); |
| 415 } | 482 } |
| 416 | 483 |
| 484 void ClientSideDetectionHost::OnPhishingPreClassificationDone( | |
| 485 bool should_classify) { | |
| 486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 487 if (browse_info_.get() && should_classify) { | |
| 488 VLOG(1) << "Instruct renderer to start phishing detection for URL: " | |
| 489 << browse_info_->url; | |
| 490 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); | |
| 491 rvh->Send(new SafeBrowsingMsg_StartPhishingDetection( | |
| 492 rvh->GetRoutingID(), browse_info_->url)); | |
| 493 } | |
| 494 } | |
| 495 | |
| 496 void ClientSideDetectionHost::OnMalwarePreClassificationDone( | |
| 497 bool should_classify) { | |
| 498 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 499 // If classification checks failed we should stop extracting malware features. | |
| 500 DVLOG(2) << "Malware pre-classification checks done. Should classify: " | |
| 501 << should_classify; | |
| 502 should_extract_malware_features_ = should_classify; | |
| 503 should_classify_for_malware_ = should_classify; | |
| 504 MaybeStartMalwareFeatureExtraction(); | |
| 505 } | |
| 506 | |
| 507 void ClientSideDetectionHost::DocumentOnLoadCompletedInMainFrame( | |
| 508 int32 page_id) { | |
| 509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 510 if (!csd_service_ || !browse_info_.get()) | |
| 511 return; | |
| 512 DVLOG(2) << "Main frame onload hander called."; | |
| 513 if (browse_info_->page_id != page_id) { | |
| 514 // Something weird is happening here. The BrowseInfo page ID | |
| 515 // should always be the same as the most recent load. | |
| 516 UMA_HISTOGRAM_COUNTS("SBClientMalware.UnexpectedPageId", 1); | |
|
Alexei Svitkine (slow)
2014/03/25 13:51:39
Are you missing a histograms.xml entry for this on
noé
2014/03/25 15:54:25
Done.
| |
| 517 return; | |
| 518 } | |
| 519 onload_complete_ = true; | |
| 520 MaybeStartMalwareFeatureExtraction(); | |
| 521 } | |
| 522 | |
| 523 void ClientSideDetectionHost::MaybeStartMalwareFeatureExtraction() { | |
| 524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 525 if (csd_service_ && browse_info_.get() && | |
| 526 should_classify_for_malware_ && | |
| 527 onload_complete_) { | |
| 528 scoped_ptr<ClientMalwareRequest> malware_request( | |
| 529 new ClientMalwareRequest); | |
| 530 // Start browser-side malware feature extraction. Once we're done it will | |
| 531 // send the malware client verdict request. | |
| 532 malware_request->set_url(browse_info_->url.spec()); | |
| 533 const GURL& referrer = browse_info_->referrer; | |
| 534 if (referrer.SchemeIs("http")) { // Only send http urls. | |
| 535 malware_request->set_referrer_url(referrer.spec()); | |
| 536 } | |
| 537 // This function doesn't expect browse_info_ to stay around after this | |
| 538 // function returns. | |
| 539 feature_extractor_->ExtractMalwareFeatures( | |
| 540 browse_info_.get(), | |
| 541 malware_request.release(), | |
| 542 base::Bind(&ClientSideDetectionHost::MalwareFeatureExtractionDone, | |
| 543 weak_factory_.GetWeakPtr())); | |
| 544 should_classify_for_malware_ = false; | |
| 545 } | |
| 546 } | |
| 547 | |
| 417 void ClientSideDetectionHost::OnPhishingDetectionDone( | 548 void ClientSideDetectionHost::OnPhishingDetectionDone( |
| 418 const std::string& verdict_str) { | 549 const std::string& verdict_str) { |
| 419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 420 // There is something seriously wrong if there is no service class but | 551 // There is something seriously wrong if there is no service class but |
| 421 // this method is called. The renderer should not start phishing detection | 552 // this method is called. The renderer should not start phishing detection |
| 422 // if there isn't any service class in the browser. | 553 // if there isn't any service class in the browser. |
| 423 DCHECK(csd_service_); | 554 DCHECK(csd_service_); |
| 424 // There shouldn't be any pending requests because we revoke them everytime | |
| 425 // we navigate away. | |
| 426 DCHECK(!weak_factory_.HasWeakPtrs()); | |
| 427 DCHECK(browse_info_.get()); | 555 DCHECK(browse_info_.get()); |
| 428 | 556 |
| 429 // We parse the protocol buffer here. If we're unable to parse it we won't | 557 // We parse the protocol buffer here. If we're unable to parse it we won't |
| 430 // send the verdict further. | 558 // send the verdict further. |
| 431 scoped_ptr<ClientPhishingRequest> verdict(new ClientPhishingRequest); | 559 scoped_ptr<ClientPhishingRequest> verdict(new ClientPhishingRequest); |
| 432 if (csd_service_ && | 560 if (csd_service_ && |
| 433 !weak_factory_.HasWeakPtrs() && | |
| 434 browse_info_.get() && | 561 browse_info_.get() && |
| 435 verdict->ParseFromString(verdict_str) && | 562 verdict->ParseFromString(verdict_str) && |
| 436 verdict->IsInitialized()) { | 563 verdict->IsInitialized()) { |
| 437 // We do the malware IP matching and request sending if the feature | |
| 438 // is enabled. | |
| 439 if (malware_report_enabled_ && !MalwareKillSwitchIsOn()) { | |
| 440 scoped_ptr<ClientMalwareRequest> malware_verdict( | |
| 441 new ClientMalwareRequest); | |
| 442 // Start browser-side malware feature extraction. Once we're done it will | |
| 443 // send the malware client verdict request. | |
| 444 malware_verdict->set_url(verdict->url()); | |
| 445 const GURL& referrer = browse_info_->referrer; | |
| 446 if (referrer.SchemeIs("http")) { // Only send http urls. | |
| 447 malware_verdict->set_referrer_url(referrer.spec()); | |
| 448 } | |
| 449 // This function doesn't expect browse_info_ to stay around after this | |
| 450 // function returns. | |
| 451 feature_extractor_->ExtractMalwareFeatures( | |
| 452 browse_info_.get(), | |
| 453 malware_verdict.release(), | |
| 454 base::Bind(&ClientSideDetectionHost::MalwareFeatureExtractionDone, | |
| 455 weak_factory_.GetWeakPtr())); | |
| 456 } | |
| 457 | |
| 458 // We only send phishing verdict to the server if the verdict is phishing or | 564 // We only send phishing verdict to the server if the verdict is phishing or |
| 459 // if a SafeBrowsing interstitial was already shown for this site. E.g., a | 565 // if a SafeBrowsing interstitial was already shown for this site. E.g., a |
| 460 // malware or phishing interstitial was shown but the user clicked | 566 // malware or phishing interstitial was shown but the user clicked |
| 461 // through. | 567 // through. |
| 462 if (verdict->is_phishing() || DidShowSBInterstitial()) { | 568 if (verdict->is_phishing() || DidShowSBInterstitial()) { |
| 463 if (DidShowSBInterstitial()) { | 569 if (DidShowSBInterstitial()) { |
| 464 browse_info_->unsafe_resource.reset(unsafe_resource_.release()); | 570 browse_info_->unsafe_resource.reset(unsafe_resource_.release()); |
| 465 } | 571 } |
| 466 // Start browser-side feature extraction. Once we're done it will send | 572 // Start browser-side feature extraction. Once we're done it will send |
| 467 // the client verdict request. | 573 // the client verdict request. |
| 468 feature_extractor_->ExtractFeatures( | 574 feature_extractor_->ExtractFeatures( |
| 469 browse_info_.get(), | 575 browse_info_.get(), |
| 470 verdict.release(), | 576 verdict.release(), |
| 471 base::Bind(&ClientSideDetectionHost::FeatureExtractionDone, | 577 base::Bind(&ClientSideDetectionHost::FeatureExtractionDone, |
| 472 weak_factory_.GetWeakPtr())); | 578 weak_factory_.GetWeakPtr())); |
| 473 } | 579 } |
| 474 } | 580 } |
| 475 browse_info_.reset(); | |
| 476 } | 581 } |
| 477 | 582 |
| 478 void ClientSideDetectionHost::MaybeShowPhishingWarning(GURL phishing_url, | 583 void ClientSideDetectionHost::MaybeShowPhishingWarning(GURL phishing_url, |
| 479 bool is_phishing) { | 584 bool is_phishing) { |
| 480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 585 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 481 VLOG(2) << "Received server phishing verdict for URL:" << phishing_url | 586 DVLOG(2) << "Received server phishing verdict for URL:" << phishing_url |
| 482 << " is_phishing:" << is_phishing; | 587 << " is_phishing:" << is_phishing; |
| 483 if (is_phishing) { | 588 if (is_phishing) { |
| 484 DCHECK(web_contents()); | 589 DCHECK(web_contents()); |
| 485 if (ui_manager_.get()) { | 590 if (ui_manager_.get()) { |
| 486 SafeBrowsingUIManager::UnsafeResource resource; | 591 SafeBrowsingUIManager::UnsafeResource resource; |
| 487 resource.url = phishing_url; | 592 resource.url = phishing_url; |
| 488 resource.original_url = phishing_url; | 593 resource.original_url = phishing_url; |
| 489 resource.is_subresource = false; | 594 resource.is_subresource = false; |
| 490 resource.threat_type = SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL; | 595 resource.threat_type = SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL; |
| 491 resource.render_process_host_id = | 596 resource.render_process_host_id = |
| 492 web_contents()->GetRenderProcessHost()->GetID(); | 597 web_contents()->GetRenderProcessHost()->GetID(); |
| 493 resource.render_view_id = | 598 resource.render_view_id = |
| 494 web_contents()->GetRenderViewHost()->GetRoutingID(); | 599 web_contents()->GetRenderViewHost()->GetRoutingID(); |
| 495 if (!ui_manager_->IsWhitelisted(resource)) { | 600 if (!ui_manager_->IsWhitelisted(resource)) { |
| 496 // We need to stop any pending navigations, otherwise the interstital | 601 // We need to stop any pending navigations, otherwise the interstital |
| 497 // might not get created properly. | 602 // might not get created properly. |
| 498 web_contents()->GetController().DiscardNonCommittedEntries(); | 603 web_contents()->GetController().DiscardNonCommittedEntries(); |
| 499 } | 604 } |
| 500 ui_manager_->DisplayBlockingPage(resource); | 605 ui_manager_->DisplayBlockingPage(resource); |
| 501 } | 606 } |
| 502 // If there is true phishing verdict, invalidate weakptr so that no longer | 607 // If there is true phishing verdict, invalidate weakptr so that no longer |
| 503 // consider the malware vedict. | 608 // consider the malware vedict. |
| 504 weak_factory_.InvalidateWeakPtrs(); | 609 weak_factory_.InvalidateWeakPtrs(); |
| 505 } | 610 } |
| 506 } | 611 } |
| 507 | 612 |
| 508 void ClientSideDetectionHost::MaybeShowMalwareWarning(GURL original_url, | 613 void ClientSideDetectionHost::MaybeShowMalwareWarning(GURL original_url, |
| 509 GURL malware_url, | 614 GURL malware_url, |
| 510 bool is_malware) { | 615 bool is_malware) { |
| 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 512 VLOG(2) << "Received server malawre IP verdict for URL:" << malware_url | 617 DVLOG(2) << "Received server malawre IP verdict for URL:" << malware_url |
| 513 << " is_malware:" << is_malware; | 618 << " is_malware:" << is_malware; |
| 514 if (is_malware && malware_url.is_valid() && original_url.is_valid()) { | 619 if (is_malware && malware_url.is_valid() && original_url.is_valid()) { |
| 515 DCHECK(web_contents()); | 620 DCHECK(web_contents()); |
| 516 if (ui_manager_.get()) { | 621 if (ui_manager_.get()) { |
| 517 SafeBrowsingUIManager::UnsafeResource resource; | 622 SafeBrowsingUIManager::UnsafeResource resource; |
| 518 resource.url = malware_url; | 623 resource.url = malware_url; |
| 519 resource.original_url = original_url; | 624 resource.original_url = original_url; |
| 520 resource.is_subresource = (malware_url.host() != original_url.host()); | 625 resource.is_subresource = (malware_url.host() != original_url.host()); |
| 521 resource.threat_type = SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL; | 626 resource.threat_type = SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL; |
| 522 resource.render_process_host_id = | 627 resource.render_process_host_id = |
| 523 web_contents()->GetRenderProcessHost()->GetID(); | 628 web_contents()->GetRenderProcessHost()->GetID(); |
| 524 resource.render_view_id = | 629 resource.render_view_id = |
| 525 web_contents()->GetRenderViewHost()->GetRoutingID(); | 630 web_contents()->GetRenderViewHost()->GetRoutingID(); |
| 526 if (!ui_manager_->IsWhitelisted(resource)) { | 631 if (!ui_manager_->IsWhitelisted(resource)) { |
| 527 // We need to stop any pending navigations, otherwise the interstital | 632 // We need to stop any pending navigations, otherwise the interstital |
| 528 // might not get created properly. | 633 // might not get created properly. |
| 529 web_contents()->GetController().DiscardNonCommittedEntries(); | 634 web_contents()->GetController().DiscardNonCommittedEntries(); |
| 530 } | 635 } |
| 531 ui_manager_->DisplayBlockingPage(resource); | 636 ui_manager_->DisplayBlockingPage(resource); |
| 532 } | 637 } |
| 533 // If there is true malware verdict, invalidate weakptr so that no longer | 638 // If there is true malware verdict, invalidate weakptr so that no longer |
| 534 // consider the phishing vedict. | 639 // consider the phishing vedict. |
| 535 weak_factory_.InvalidateWeakPtrs(); | 640 weak_factory_.InvalidateWeakPtrs(); |
| 536 } | 641 } |
| 537 } | 642 } |
| 538 | 643 |
| 539 void ClientSideDetectionHost::FeatureExtractionDone( | 644 void ClientSideDetectionHost::FeatureExtractionDone( |
| 540 bool success, | 645 bool success, |
| 541 ClientPhishingRequest* request) { | 646 ClientPhishingRequest* request) { |
| 542 DCHECK(request); | 647 DCHECK(request); |
| 543 VLOG(2) << "Feature extraction done (success:" << success << ") for URL: " | 648 DVLOG(2) << "Feature extraction done (success:" << success << ") for URL: " |
| 544 << request->url() << ". Start sending client phishing request."; | 649 << request->url() << ". Start sending client phishing request."; |
| 545 ClientSideDetectionService::ClientReportPhishingRequestCallback callback; | 650 ClientSideDetectionService::ClientReportPhishingRequestCallback callback; |
| 546 // If the client-side verdict isn't phishing we don't care about the server | 651 // If the client-side verdict isn't phishing we don't care about the server |
| 547 // response because we aren't going to display a warning. | 652 // response because we aren't going to display a warning. |
| 548 if (request->is_phishing()) { | 653 if (request->is_phishing()) { |
| 549 callback = base::Bind(&ClientSideDetectionHost::MaybeShowPhishingWarning, | 654 callback = base::Bind(&ClientSideDetectionHost::MaybeShowPhishingWarning, |
| 550 weak_factory_.GetWeakPtr()); | 655 weak_factory_.GetWeakPtr()); |
| 551 } | 656 } |
| 552 // Send ping even if the browser feature extraction failed. | 657 // Send ping even if the browser feature extraction failed. |
| 553 csd_service_->SendClientReportPhishingRequest( | 658 csd_service_->SendClientReportPhishingRequest( |
| 554 request, // The service takes ownership of the request object. | 659 request, // The service takes ownership of the request object. |
| 555 callback); | 660 callback); |
| 556 } | 661 } |
| 557 | 662 |
| 558 void ClientSideDetectionHost::MalwareFeatureExtractionDone( | 663 void ClientSideDetectionHost::MalwareFeatureExtractionDone( |
| 559 bool feature_extraction_success, | 664 bool feature_extraction_success, |
| 560 scoped_ptr<ClientMalwareRequest> request) { | 665 scoped_ptr<ClientMalwareRequest> request) { |
| 561 DCHECK(request.get()); | 666 DCHECK(request.get()); |
| 562 VLOG(2) << "Malware Feature extraction done for URL: " << request->url() | 667 DVLOG(2) << "Malware Feature extraction done for URL: " << request->url() |
| 563 << ", with badip url count:" << request->bad_ip_url_info_size(); | 668 << ", with badip url count:" << request->bad_ip_url_info_size(); |
| 564 | 669 |
| 565 // Send ping if there is matching features. | 670 // Send ping if there is matching features. |
| 566 if (feature_extraction_success && request->bad_ip_url_info_size() > 0) { | 671 if (feature_extraction_success && request->bad_ip_url_info_size() > 0) { |
| 567 VLOG(1) << "Start sending client malware request."; | 672 VLOG(1) << "Start sending client malware request."; |
| 568 ClientSideDetectionService::ClientReportMalwareRequestCallback callback; | 673 ClientSideDetectionService::ClientReportMalwareRequestCallback callback; |
| 569 callback = base::Bind(&ClientSideDetectionHost::MaybeShowMalwareWarning, | 674 callback = base::Bind(&ClientSideDetectionHost::MaybeShowMalwareWarning, |
| 570 weak_factory_.GetWeakPtr()); | 675 weak_factory_.GetWeakPtr()); |
| 571 csd_service_->SendClientReportMalwareRequest(request.release(), callback); | 676 csd_service_->SendClientReportMalwareRequest(request.release(), callback); |
| 572 } | 677 } |
| 573 } | 678 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 594 } | 699 } |
| 595 | 700 |
| 596 void ClientSideDetectionHost::Observe( | 701 void ClientSideDetectionHost::Observe( |
| 597 int type, | 702 int type, |
| 598 const content::NotificationSource& source, | 703 const content::NotificationSource& source, |
| 599 const content::NotificationDetails& details) { | 704 const content::NotificationDetails& details) { |
| 600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 601 DCHECK_EQ(type, content::NOTIFICATION_RESOURCE_RESPONSE_STARTED); | 706 DCHECK_EQ(type, content::NOTIFICATION_RESOURCE_RESPONSE_STARTED); |
| 602 const ResourceRequestDetails* req = content::Details<ResourceRequestDetails>( | 707 const ResourceRequestDetails* req = content::Details<ResourceRequestDetails>( |
| 603 details).ptr(); | 708 details).ptr(); |
| 604 if (req && browse_info_.get() && malware_report_enabled_ && | 709 if (req && browse_info_.get() && |
| 605 !MalwareKillSwitchIsOn()) { | 710 should_extract_malware_features_ && req->url.is_valid()) { |
| 606 if (req->url.is_valid()) { | 711 UpdateIPUrlMap(req->socket_address.host() /* ip */, |
| 607 UpdateIPUrlMap(req->socket_address.host() /* ip */, | 712 req->url.spec() /* url */, |
| 608 req->url.spec() /* url */, | 713 req->method, |
| 609 req->method, | 714 req->referrer, |
| 610 req->referrer, | 715 req->resource_type); |
| 611 req->resource_type); | |
| 612 } | |
| 613 } | 716 } |
| 614 } | 717 } |
| 615 | 718 |
| 616 bool ClientSideDetectionHost::DidShowSBInterstitial() const { | 719 bool ClientSideDetectionHost::DidShowSBInterstitial() const { |
| 617 if (unsafe_unique_page_id_ <= 0 || !web_contents()) { | 720 if (unsafe_unique_page_id_ <= 0 || !web_contents()) { |
| 618 return false; | 721 return false; |
| 619 } | 722 } |
| 620 const NavigationEntry* nav_entry = | 723 const NavigationEntry* nav_entry = |
| 621 web_contents()->GetController().GetActiveEntry(); | 724 web_contents()->GetController().GetActiveEntry(); |
| 622 return (nav_entry && nav_entry->GetUniqueID() == unsafe_unique_page_id_); | 725 return (nav_entry && nav_entry->GetUniqueID() == unsafe_unique_page_id_); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 633 if (ui_manager_.get()) | 736 if (ui_manager_.get()) |
| 634 ui_manager_->RemoveObserver(this); | 737 ui_manager_->RemoveObserver(this); |
| 635 | 738 |
| 636 ui_manager_ = ui_manager; | 739 ui_manager_ = ui_manager; |
| 637 if (ui_manager) | 740 if (ui_manager) |
| 638 ui_manager_->AddObserver(this); | 741 ui_manager_->AddObserver(this); |
| 639 | 742 |
| 640 database_manager_ = database_manager; | 743 database_manager_ = database_manager; |
| 641 } | 744 } |
| 642 | 745 |
| 643 bool ClientSideDetectionHost::MalwareKillSwitchIsOn() { | |
| 644 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 645 return malware_killswitch_on_; | |
| 646 } | |
| 647 | |
| 648 void ClientSideDetectionHost::SetMalwareKillSwitch(bool killswitch_on) { | |
| 649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 650 malware_killswitch_on_ = killswitch_on; | |
| 651 } | |
| 652 | |
| 653 } // namespace safe_browsing | 746 } // namespace safe_browsing |
| OLD | NEW |