1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This test creates a fake safebrowsing service, where we can inject
6 // malware and phishing urls. It then uses a real browser to go to
7 // these urls, and sends "goback" or "proceed" commands and verifies
10 #include "base/bind.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/safe_browsing/malware_details.h"
15 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
16 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/browser/browser_thread.h"
24 #include "content/browser/renderer_host/render_process_host.h"
25 #include "content/browser/renderer_host/resource_dispatcher_host.h"
26 #include "content/browser/tab_contents/tab_contents.h"
27 #include "content/browser/tab_contents/tab_contents_view.h"
29 // A SafeBrowingService class that allows us to inject the malicious URLs.
30 class FakeSafeBrowsingService
: public SafeBrowsingService
{
32 FakeSafeBrowsingService() {}
34 virtual ~FakeSafeBrowsingService() {}
36 // Called on the IO thread to check if the given url is safe or not. If we
37 // can synchronously determine that the url is safe, CheckUrl returns true.
38 // Otherwise it returns false, and "client" is called asynchronously with the
39 // result when it is ready.
40 // Overrides SafeBrowsingService::CheckBrowseUrl.
41 virtual bool CheckBrowseUrl(const GURL
& gurl
, Client
* client
) {
42 if (badurls
[gurl
.spec()] == SAFE
)
45 BrowserThread::PostTask(
46 BrowserThread::IO
, FROM_HERE
,
47 base::Bind(&FakeSafeBrowsingService::OnCheckBrowseURLDone
,
52 void OnCheckBrowseURLDone(const GURL
& gurl
, Client
* client
) {
53 SafeBrowsingService::SafeBrowsingCheck check
;
54 check
.urls
.push_back(gurl
);
55 check
.client
= client
;
56 check
.result
= badurls
[gurl
.spec()];
57 client
->OnSafeBrowsingResult(check
);
60 void AddURLResult(const GURL
& url
, UrlCheckResult checkresult
) {
61 badurls
[url
.spec()] = checkresult
;
64 // Overrides SafeBrowsingService.
65 virtual void SendSerializedMalwareDetails(const std::string
& serialized
) {
66 reports_
.push_back(serialized
);
67 // Notify the UI thread that we got a report.
68 BrowserThread::PostTask(
69 BrowserThread::UI
, FROM_HERE
,
70 base::Bind(&FakeSafeBrowsingService::OnMalwareDetailsDone
, this));
73 void OnMalwareDetailsDone() {
74 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
75 MessageLoopForUI::current()->Quit();
78 std::string
GetReport() {
79 EXPECT_TRUE(reports_
.size() == 1);
83 std::vector
<std::string
> reports_
;
86 base::hash_map
<std::string
, UrlCheckResult
> badurls
;
89 // Factory that creates FakeSafeBrowsingService instances.
90 class TestSafeBrowsingServiceFactory
: public SafeBrowsingServiceFactory
{
92 TestSafeBrowsingServiceFactory() { }
93 virtual ~TestSafeBrowsingServiceFactory() { }
95 virtual SafeBrowsingService
* CreateSafeBrowsingService() {
96 return new FakeSafeBrowsingService();
100 // A MalwareDetails class lets us intercept calls from the renderer.
101 class FakeMalwareDetails
: public MalwareDetails
{
103 FakeMalwareDetails(SafeBrowsingService
* sb_service
,
104 TabContents
* tab_contents
,
105 const SafeBrowsingService::UnsafeResource
& unsafe_resource
)
106 : MalwareDetails(sb_service
, tab_contents
, unsafe_resource
) { }
108 virtual ~FakeMalwareDetails() {}
110 virtual void AddDOMDetails(
111 const std::vector
<SafeBrowsingHostMsg_MalwareDOMDetails_Node
>& params
) {
112 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
113 MalwareDetails::AddDOMDetails(params
);
115 // Notify the UI thread that we got the dom details.
116 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
117 base::Bind(&FakeMalwareDetails::OnDOMDetailsDone
,
121 void OnDOMDetailsDone() {
124 MessageLoopForUI::current()->Quit();
128 bool got_dom() const {
132 bool waiting() const {
136 void set_got_dom(bool got_dom
) {
140 void set_waiting(bool waiting
) {
144 safe_browsing::ClientMalwareReportRequest
* get_report() {
145 return report_
.get();
149 // Some logic to figure out if we should wait for the dom details or not.
150 // These variables should only be accessed in the UI thread.
156 class TestMalwareDetailsFactory
: public MalwareDetailsFactory
{
158 TestMalwareDetailsFactory() { }
159 virtual ~TestMalwareDetailsFactory() { }
161 virtual MalwareDetails
* CreateMalwareDetails(
162 SafeBrowsingService
* sb_service
,
163 TabContents
* tab_contents
,
164 const SafeBrowsingService::UnsafeResource
& unsafe_resource
) {
165 details_
= new FakeMalwareDetails(sb_service
, tab_contents
,
170 FakeMalwareDetails
* get_details() {
175 FakeMalwareDetails
* details_
;
178 // A SafeBrowingBlockingPage class that lets us wait until it's hidden.
179 class TestSafeBrowsingBlockingPage
: public SafeBrowsingBlockingPage
{
181 TestSafeBrowsingBlockingPage(SafeBrowsingService
* service
,
182 TabContents
* tab_contents
,
183 const UnsafeResourceList
& unsafe_resources
)
184 : SafeBrowsingBlockingPage(service
, tab_contents
, unsafe_resources
) {
185 // Don't wait the whole 3 seconds for the browser test.
186 malware_details_proceed_delay_ms_
= 100;
187 wait_for_delete_
= false;
190 ~TestSafeBrowsingBlockingPage() {
191 if (wait_for_delete_
) {
192 // Notify that we are gone
193 MessageLoopForUI::current()->Quit();
197 void set_wait_for_delete() {
198 wait_for_delete_
= true;
202 bool wait_for_delete_
;
205 class TestSafeBrowsingBlockingPageFactory
206 : public SafeBrowsingBlockingPageFactory
{
208 TestSafeBrowsingBlockingPageFactory() { }
209 ~TestSafeBrowsingBlockingPageFactory() { }
211 virtual SafeBrowsingBlockingPage
* CreateSafeBrowsingPage(
212 SafeBrowsingService
* service
,
213 TabContents
* tab_contents
,
214 const SafeBrowsingBlockingPage::UnsafeResourceList
& unsafe_resources
) {
215 return new TestSafeBrowsingBlockingPage(service
, tab_contents
,
220 // Tests the safe browsing blocking page in a browser.
221 class SafeBrowsingBlockingPageTest
: public InProcessBrowserTest
,
222 public SafeBrowsingService::Client
{
224 SafeBrowsingBlockingPageTest() {
227 virtual void SetUp() {
228 SafeBrowsingService::RegisterFactory(&factory_
);
229 SafeBrowsingBlockingPage::RegisterFactory(&blocking_page_factory_
);
230 MalwareDetails::RegisterFactory(&details_factory_
);
231 InProcessBrowserTest::SetUp();
234 virtual void TearDown() {
235 InProcessBrowserTest::TearDown();
236 SafeBrowsingBlockingPage::RegisterFactory(NULL
);
237 SafeBrowsingService::RegisterFactory(NULL
);
238 MalwareDetails::RegisterFactory(NULL
);
241 virtual void SetUpInProcessBrowserTestFixture() {
242 ASSERT_TRUE(test_server()->Start());
245 // SafeBrowsingService::Client implementation.
246 virtual void OnSafeBrowsingResult(
247 const SafeBrowsingService::SafeBrowsingCheck
& check
) {
250 virtual void OnBlockingPageComplete(bool proceed
) {
253 void AddURLResult(const GURL
& url
,
254 SafeBrowsingService::UrlCheckResult checkresult
) {
255 FakeSafeBrowsingService
* service
=
256 static_cast<FakeSafeBrowsingService
*>(
257 g_browser_process
->safe_browsing_service());
259 ASSERT_TRUE(service
);
260 service
->AddURLResult(url
, checkresult
);
263 void SendCommand(const std::string
& command
) {
264 TabContents
* contents
= browser()->GetSelectedTabContents();
265 // We use InterstitialPage::GetInterstitialPage(tab) instead of
266 // tab->interstitial_page() because the tab doesn't have a pointer
267 // to its interstital page until it gets a command from the renderer
268 // that it has indeed displayed it -- and this sometimes happens after
269 // NavigateToURL returns.
270 SafeBrowsingBlockingPage
* interstitial_page
=
271 static_cast<SafeBrowsingBlockingPage
*>(
272 InterstitialPage::GetInterstitialPage(contents
));
273 ASSERT_TRUE(interstitial_page
);
274 interstitial_page
->CommandReceived(command
);
277 void DontProceedThroughInterstitial() {
278 TabContents
* contents
= browser()->GetSelectedTabContents();
279 InterstitialPage
* interstitial_page
= InterstitialPage::GetInterstitialPage(
281 ASSERT_TRUE(interstitial_page
);
282 interstitial_page
->DontProceed();
285 void ProceedThroughInterstitial() {
286 TabContents
* contents
= browser()->GetSelectedTabContents();
287 InterstitialPage
* interstitial_page
= InterstitialPage::GetInterstitialPage(
289 ASSERT_TRUE(interstitial_page
);
290 interstitial_page
->Proceed();
293 void AssertNoInterstitial(bool wait_for_delete
) {
294 TabContents
* contents
= browser()->GetSelectedTabContents();
296 if (contents
->showing_interstitial_page() && wait_for_delete
) {
297 // We'll get notified when the interstitial is deleted.
298 static_cast<TestSafeBrowsingBlockingPage
*>(
299 contents
->interstitial_page())->set_wait_for_delete();
300 ui_test_utils::RunMessageLoop();
303 // Can't use InterstitialPage::GetInterstitialPage() because that
304 // gets updated after the TestSafeBrowsingBlockingPage destructor
305 ASSERT_FALSE(contents
->showing_interstitial_page());
308 bool YesInterstitial() {
309 TabContents
* contents
= browser()->GetSelectedTabContents();
310 InterstitialPage
* interstitial_page
= InterstitialPage::GetInterstitialPage(
312 return interstitial_page
!= NULL
;
315 void WaitForInterstitial() {
316 TabContents
* contents
= browser()->GetSelectedTabContents();
317 ui_test_utils::WindowedNotificationObserver
interstitial_observer(
318 content::NOTIFICATION_INTERSTITIAL_ATTACHED
,
319 Source
<TabContents
>(contents
));
320 if (!InterstitialPage::GetInterstitialPage(contents
))
321 interstitial_observer
.Wait();
324 void AssertReportSent() {
325 // When a report is scheduled in the IO thread we should get notified.
326 ui_test_utils::RunMessageLoop();
328 FakeSafeBrowsingService
* service
=
329 static_cast<FakeSafeBrowsingService
*>(
330 g_browser_process
->safe_browsing_service());
332 std::string serialized
= service
->GetReport();
334 safe_browsing::ClientMalwareReportRequest report
;
335 ASSERT_TRUE(report
.ParseFromString(serialized
));
337 // Verify the report is complete.
338 EXPECT_TRUE(report
.complete());
341 void MalwareRedirectCancelAndProceed(const std::string open_function
);
344 TestMalwareDetailsFactory details_factory_
;
347 TestSafeBrowsingServiceFactory factory_
;
348 TestSafeBrowsingBlockingPageFactory blocking_page_factory_
;
350 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageTest
);
353 void SafeBrowsingBlockingPageTest::MalwareRedirectCancelAndProceed(
354 const std::string open_function
) {
355 GURL load_url
= test_server()->GetURL(
356 "files/safe_browsing/interstitial_cancel.html");
357 GURL
malware_url("http://localhost/files/safe_browsing/malware.html");
358 AddURLResult(malware_url
, SafeBrowsingService::URL_MALWARE
);
360 // Load the test page.
361 ui_test_utils::NavigateToURL(browser(), load_url
);
362 // Trigger the safe browsing interstitial page via a redirect in "openWin()".
363 ui_test_utils::NavigateToURLWithDisposition(
365 GURL("javascript:" + open_function
+ "()"),
367 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
368 WaitForInterstitial();
369 // Cancel the redirect request while interstitial page is open.
370 browser()->ActivateTabAt(0, true);
371 ui_test_utils::NavigateToURLWithDisposition(
373 GURL("javascript:stopWin()"),
375 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
376 browser()->ActivateTabAt(1, true);
377 // Simulate the user clicking "proceed", there should be no crash.
378 SendCommand("\"proceed\"");
383 const char kEmptyPage
[] = "files/empty.html";
384 const char kMalwarePage
[] = "files/safe_browsing/malware.html";
385 const char kMalwareIframe
[] = "files/safe_browsing/malware_iframe.html";
387 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
,
388 MalwareRedirectInIFrameCanceled
) {
389 // 1. Test the case that redirect is a subresource.
390 MalwareRedirectCancelAndProceed("openWinIFrame");
391 // If the redirect was from subresource but canceled, "proceed" will continue
392 // with the rest of resources.
393 AssertNoInterstitial(true);
396 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, MalwareRedirectCanceled
) {
397 // 2. Test the case that redirect is the only resource.
398 MalwareRedirectCancelAndProceed("openWin");
399 // Clicking proceed won't do anything if the main request is cancelled
400 // already. See crbug.com/76460.
401 EXPECT_TRUE(YesInterstitial());
404 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, MalwareDontProceed
) {
405 GURL url
= test_server()->GetURL(kEmptyPage
);
406 AddURLResult(url
, SafeBrowsingService::URL_MALWARE
);
408 ui_test_utils::NavigateToURL(browser(), url
);
410 SendCommand("\"takeMeBack\""); // Simulate the user clicking "back"
411 AssertNoInterstitial(false); // Assert the interstitial is gone
412 EXPECT_EQ(GURL(chrome::kAboutBlankURL
), // Back to "about:blank"
413 browser()->GetSelectedTabContents()->GetURL());
416 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, MalwareProceed
) {
417 GURL url
= test_server()->GetURL(kEmptyPage
);
418 AddURLResult(url
, SafeBrowsingService::URL_MALWARE
);
420 ui_test_utils::NavigateToURL(browser(), url
);
421 ui_test_utils::WindowedNotificationObserver
observer(
422 content::NOTIFICATION_LOAD_STOP
,
423 Source
<NavigationController
>(
424 &browser()->GetSelectedTabContentsWrapper()->controller()));
425 SendCommand("\"proceed\""); // Simulate the user clicking "proceed"
427 AssertNoInterstitial(true); // Assert the interstitial is gone.
428 EXPECT_EQ(url
, browser()->GetSelectedTabContents()->GetURL());
431 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, PhishingDontProceed
) {
432 GURL url
= test_server()->GetURL(kEmptyPage
);
433 AddURLResult(url
, SafeBrowsingService::URL_PHISHING
);
435 ui_test_utils::NavigateToURL(browser(), url
);
437 SendCommand("\"takeMeBack\""); // Simulate the user clicking "proceed"
438 AssertNoInterstitial(false); // Assert the interstitial is gone
439 EXPECT_EQ(GURL(chrome::kAboutBlankURL
), // We are back to "about:blank".
440 browser()->GetSelectedTabContents()->GetURL());
443 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, PhishingProceed
) {
444 GURL url
= test_server()->GetURL(kEmptyPage
);
445 AddURLResult(url
, SafeBrowsingService::URL_PHISHING
);
447 ui_test_utils::NavigateToURL(browser(), url
);
449 ui_test_utils::WindowedNotificationObserver
observer(
450 content::NOTIFICATION_LOAD_STOP
,
451 Source
<NavigationController
>(
452 &browser()->GetSelectedTabContentsWrapper()->controller()));
453 SendCommand("\"proceed\""); // Simulate the user clicking "proceed".
455 AssertNoInterstitial(true); // Assert the interstitial is gone
456 EXPECT_EQ(url
, browser()->GetSelectedTabContents()->GetURL());
459 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, PhishingReportError
) {
460 GURL url
= test_server()->GetURL(kEmptyPage
);
461 AddURLResult(url
, SafeBrowsingService::URL_PHISHING
);
463 ui_test_utils::NavigateToURL(browser(), url
);
465 ui_test_utils::WindowedNotificationObserver
observer(
466 content::NOTIFICATION_LOAD_STOP
,
467 Source
<NavigationController
>(
468 &browser()->GetSelectedTabContentsWrapper()->controller()));
469 SendCommand("\"reportError\""); // Simulate the user clicking "report error"
471 AssertNoInterstitial(false); // Assert the interstitial is gone
473 // We are in the error reporting page.
474 EXPECT_EQ("/safebrowsing/report_error/",
475 browser()->GetSelectedTabContents()->GetURL().path());
478 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
,
480 GURL url
= test_server()->GetURL(kEmptyPage
);
481 AddURLResult(url
, SafeBrowsingService::URL_PHISHING
);
483 ui_test_utils::NavigateToURL(browser(), url
);
485 ui_test_utils::WindowedNotificationObserver
observer(
486 content::NOTIFICATION_LOAD_STOP
,
487 Source
<NavigationController
>(
488 &browser()->GetSelectedTabContentsWrapper()->controller()));
489 SendCommand("\"learnMore\""); // Simulate the user clicking "learn more"
491 AssertNoInterstitial(false); // Assert the interstitial is gone
493 // We are in the help page.
494 EXPECT_EQ("/support/bin/answer.py",
495 browser()->GetSelectedTabContents()->GetURL().path());
498 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
, MalwareIframeDontProceed
) {
499 GURL url
= test_server()->GetURL(kMalwarePage
);
500 GURL iframe_url
= test_server()->GetURL(kMalwareIframe
);
501 AddURLResult(iframe_url
, SafeBrowsingService::URL_MALWARE
);
503 ui_test_utils::NavigateToURL(browser(), url
);
505 SendCommand("\"takeMeBack\""); // Simulate the user clicking "back"
506 AssertNoInterstitial(false); // Assert the interstitial is gone
508 EXPECT_EQ(GURL(chrome::kAboutBlankURL
), // Back to "about:blank"
509 browser()->GetSelectedTabContents()->GetURL());
512 // Crashy, http://crbug.com/68834.
513 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
,
514 DISABLED_MalwareIframeProceed
) {
515 GURL url
= test_server()->GetURL(kMalwarePage
);
516 GURL iframe_url
= test_server()->GetURL(kMalwareIframe
);
517 AddURLResult(iframe_url
, SafeBrowsingService::URL_MALWARE
);
519 ui_test_utils::NavigateToURL(browser(), url
);
521 SendCommand("\"proceed\""); // Simulate the user clicking "proceed"
522 AssertNoInterstitial(true); // Assert the interstitial is gone
524 EXPECT_EQ(url
, browser()->GetSelectedTabContents()->GetURL());
527 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest
,
528 MalwareIframeReportDetails
) {
529 GURL url
= test_server()->GetURL(kMalwarePage
);
530 GURL iframe_url
= test_server()->GetURL(kMalwareIframe
);
531 AddURLResult(iframe_url
, SafeBrowsingService::URL_MALWARE
);
533 ui_test_utils::NavigateToURL(browser(), url
);
535 // If the DOM details from renderer did not already return, wait for them.
536 if (!details_factory_
.get_details()->got_dom()) {
537 // This condition might not trigger normally, but if you add a
538 // sleep(1) in malware_dom_details it triggers :).
539 details_factory_
.get_details()->set_waiting(true);
540 LOG(INFO
) << "Waiting for dom details.";
541 ui_test_utils::RunMessageLoop();
543 LOG(INFO
) << "Already got the dom details.";
546 SendCommand("\"doReport\""); // Simulate the user checking the checkbox.
547 EXPECT_TRUE(browser()->GetProfile()->GetPrefs()->GetBoolean(
548 prefs::kSafeBrowsingReportingEnabled
));
550 SendCommand("\"proceed\""); // Simulate the user clicking "back"
551 AssertNoInterstitial(true); // Assert the interstitial is gone
553 EXPECT_EQ(url
, browser()->GetSelectedTabContents()->GetURL());