aw_url_checker_delegate_impl.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Copyright 2017 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.
  4. #include "android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "android_webview/browser/aw_browser_context.h"
  10. #include "android_webview/browser/aw_contents.h"
  11. #include "android_webview/browser/aw_contents_client_bridge.h"
  12. #include "android_webview/browser/aw_contents_io_thread_client.h"
  13. #include "android_webview/browser/network_service/aw_web_resource_request.h"
  14. #include "android_webview/browser/safe_browsing/aw_safe_browsing_allowlist_manager.h"
  15. #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
  16. #include "android_webview/browser_jni_headers/AwSafeBrowsingConfigHelper_jni.h"
  17. #include "base/android/jni_android.h"
  18. #include "base/bind.h"
  19. #include "base/feature_list.h"
  20. #include "components/safe_browsing/core/browser/db/database_manager.h"
  21. #include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
  22. #include "components/safe_browsing/core/common/features.h"
  23. #include "components/safe_browsing/core/common/web_ui_constants.h"
  24. #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
  25. #include "components/security_interstitials/content/unsafe_resource_util.h"
  26. #include "components/security_interstitials/core/unsafe_resource.h"
  27. #include "components/security_interstitials/core/urls.h"
  28. #include "content/public/browser/browser_task_traits.h"
  29. #include "content/public/browser/browser_thread.h"
  30. #include "content/public/browser/global_routing_id.h"
  31. #include "content/public/browser/navigation_entry.h"
  32. #include "content/public/browser/web_contents.h"
  33. #include "content/public/common/url_constants.h"
  34. #include "ui/base/page_transition_types.h"
  35. namespace android_webview {
  36. namespace {
  37. void CallOnReceivedError(AwContentsClientBridge* client,
  38. AwWebResourceRequest request,
  39. content::NavigationEntry* entry) {
  40. if (!client)
  41. return;
  42. // We have no way of telling if a navigation was renderer initiated if entry
  43. // is null but OnReceivedError requires the value to be set, we default to
  44. // false for that case.
  45. request.is_renderer_initiated =
  46. entry ? ui::PageTransitionIsWebTriggerable(entry->GetTransitionType())
  47. : false;
  48. // We use ERR_ABORTED here since this is only used in cases where no
  49. // interstitial is shown.
  50. client->OnReceivedError(request, net::ERR_ABORTED, true, false);
  51. }
  52. } // namespace
  53. AwUrlCheckerDelegateImpl::AwUrlCheckerDelegateImpl(
  54. scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
  55. scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
  56. AwSafeBrowsingAllowlistManager* allowlist_manager)
  57. : database_manager_(std::move(database_manager)),
  58. ui_manager_(std::move(ui_manager)),
  59. threat_types_(safe_browsing::CreateSBThreatTypeSet(
  60. {safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
  61. safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
  62. safe_browsing::SB_THREAT_TYPE_URL_UNWANTED,
  63. safe_browsing::SB_THREAT_TYPE_BILLING})),
  64. allowlist_manager_(allowlist_manager) {}
  65. AwUrlCheckerDelegateImpl::~AwUrlCheckerDelegateImpl() = default;
  66. void AwUrlCheckerDelegateImpl::MaybeDestroyNoStatePrefetchContents(
  67. content::WebContents::OnceGetter web_contents_getter) {}
  68. void AwUrlCheckerDelegateImpl::StartDisplayingBlockingPageHelper(
  69. const security_interstitials::UnsafeResource& resource,
  70. const std::string& method,
  71. const net::HttpRequestHeaders& headers,
  72. bool is_outermost_main_frame,
  73. bool has_user_gesture) {
  74. AwWebResourceRequest request(resource.url.spec(), method,
  75. is_outermost_main_frame, has_user_gesture,
  76. headers);
  77. content::GetUIThreadTaskRunner({})->PostTask(
  78. FROM_HERE,
  79. base::BindOnce(&AwUrlCheckerDelegateImpl::StartApplicationResponse,
  80. ui_manager_, resource, std::move(request)));
  81. }
  82. void AwUrlCheckerDelegateImpl::
  83. StartObservingInteractionsForDelayedBlockingPageHelper(
  84. const security_interstitials::UnsafeResource& resource,
  85. bool is_main_frame) {
  86. NOTREACHED() << "Delayed warnings not implemented for WebView";
  87. }
  88. bool AwUrlCheckerDelegateImpl::IsUrlAllowlisted(const GURL& url) {
  89. return allowlist_manager_->IsUrlAllowed(url);
  90. }
  91. void AwUrlCheckerDelegateImpl::SetPolicyAllowlistDomains(
  92. const std::vector<std::string>& allowlist_domains) {
  93. // The SafeBrowsingAllowlistDomains policy is not supported on AW.
  94. return;
  95. }
  96. bool AwUrlCheckerDelegateImpl::ShouldSkipRequestCheck(
  97. const GURL& original_url,
  98. int frame_tree_node_id,
  99. int render_process_id,
  100. int render_frame_id,
  101. bool originated_from_service_worker) {
  102. const content::GlobalRenderFrameHostId rfh_id(render_process_id,
  103. render_frame_id);
  104. std::unique_ptr<AwContentsIoThreadClient> client;
  105. if (originated_from_service_worker) {
  106. client = AwContentsIoThreadClient::GetServiceWorkerIoThreadClient();
  107. } else if (!rfh_id) {
  108. client = AwContentsIoThreadClient::FromID(frame_tree_node_id);
  109. } else {
  110. client = AwContentsIoThreadClient::FromID(rfh_id);
  111. }
  112. // If Safe Browsing is disabled by the app, skip the check. Default to
  113. // performing the check if we can't find the |client|, since the |client| may
  114. // be null for some service worker requests (see https://crbug.com/979321).
  115. bool safe_browsing_enabled = client ? client->GetSafeBrowsingEnabled() : true;
  116. if (!safe_browsing_enabled)
  117. return true;
  118. // If this is a hardcoded WebUI URL we use for testing, do not skip the safe
  119. // browsing check. We do not check user consent here because we do not ever
  120. // send such URLs to GMS anyway. It's important to ignore user consent in this
  121. // case because the GMS APIs we rely on to check user consent often get
  122. // confused during CTS tests, reporting the user has not consented regardless
  123. // of the on-device setting. See https://crbug.com/938538.
  124. bool is_hardcoded_url =
  125. original_url.SchemeIs(content::kChromeUIScheme) &&
  126. original_url.host() == safe_browsing::kChromeUISafeBrowsingHost;
  127. if (is_hardcoded_url)
  128. return false;
  129. // For other requests, follow user consent.
  130. JNIEnv* env = base::android::AttachCurrentThread();
  131. bool safe_browsing_user_consent =
  132. Java_AwSafeBrowsingConfigHelper_getSafeBrowsingUserOptIn(env);
  133. return !safe_browsing_user_consent;
  134. }
  135. void AwUrlCheckerDelegateImpl::NotifySuspiciousSiteDetected(
  136. const base::RepeatingCallback<content::WebContents*()>&
  137. web_contents_getter) {}
  138. const safe_browsing::SBThreatTypeSet&
  139. AwUrlCheckerDelegateImpl::GetThreatTypes() {
  140. return threat_types_;
  141. }
  142. safe_browsing::SafeBrowsingDatabaseManager*
  143. AwUrlCheckerDelegateImpl::GetDatabaseManager() {
  144. return database_manager_.get();
  145. }
  146. safe_browsing::BaseUIManager* AwUrlCheckerDelegateImpl::GetUIManager() {
  147. return ui_manager_.get();
  148. }
  149. // static
  150. void AwUrlCheckerDelegateImpl::StartApplicationResponse(
  151. scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
  152. const security_interstitials::UnsafeResource& resource,
  153. const AwWebResourceRequest& request) {
  154. content::WebContents* web_contents =
  155. security_interstitials::GetWebContentsForResource(resource);
  156. security_interstitials::SecurityInterstitialTabHelper*
  157. security_interstitial_tab_helper = security_interstitials::
  158. SecurityInterstitialTabHelper::FromWebContents(web_contents);
  159. if (ui_manager->IsAllowlisted(resource) && security_interstitial_tab_helper &&
  160. security_interstitial_tab_helper->IsDisplayingInterstitial()) {
  161. // In this case we are about to leave an interstitial due to the user
  162. // clicking proceed on it, we shouldn't call OnSafeBrowsingHit again.
  163. resource.callback_sequence->PostTask(
  164. FROM_HERE, base::BindOnce(resource.callback, true /* proceed */,
  165. false /* showed_interstitial */));
  166. return;
  167. }
  168. AwContentsClientBridge* client =
  169. AwContentsClientBridge::FromWebContents(web_contents);
  170. if (client) {
  171. base::OnceCallback<void(SafeBrowsingAction, bool)> callback =
  172. base::BindOnce(&AwUrlCheckerDelegateImpl::DoApplicationResponse,
  173. ui_manager, resource, request);
  174. client->OnSafeBrowsingHit(request, resource.threat_type,
  175. std::move(callback));
  176. }
  177. }
  178. // static
  179. void AwUrlCheckerDelegateImpl::DoApplicationResponse(
  180. scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
  181. const security_interstitials::UnsafeResource& resource,
  182. const AwWebResourceRequest& request,
  183. SafeBrowsingAction action,
  184. bool reporting) {
  185. content::WebContents* web_contents =
  186. security_interstitials::GetWebContentsForResource(resource);
  187. // |web_contents| can be null after RenderFrameHost is destroyed.
  188. if (!web_contents)
  189. return;
  190. if (!reporting) {
  191. AwBrowserContext* browser_context =
  192. AwBrowserContext::FromWebContents(web_contents);
  193. browser_context->SetExtendedReportingAllowed(false);
  194. }
  195. content::NavigationEntry* entry = GetNavigationEntryForResource(resource);
  196. // TODO(ntfschr): fully handle reporting once we add support (crbug/688629)
  197. bool proceed;
  198. switch (action) {
  199. case SafeBrowsingAction::SHOW_INTERSTITIAL: {
  200. content::GetUIThreadTaskRunner({})->PostTask(
  201. FROM_HERE,
  202. base::BindOnce(
  203. &AwUrlCheckerDelegateImpl::StartDisplayingDefaultBlockingPage,
  204. ui_manager, resource));
  205. AwContents* contents = AwContents::FromWebContents(web_contents);
  206. if (!contents || !contents->CanShowInterstitial()) {
  207. // With committed interstitials OnReceivedError for safe browsing
  208. // blocked sites is generally called from the blocking page object.
  209. // When CanShowInterstitial is false, no blocking page is created from
  210. // StartDisplayingDefaultBlockingPage, so we handle the call here.
  211. CallOnReceivedError(
  212. AwContentsClientBridge::FromWebContents(web_contents), request,
  213. entry);
  214. }
  215. }
  216. return;
  217. case SafeBrowsingAction::PROCEED:
  218. proceed = true;
  219. break;
  220. case SafeBrowsingAction::BACK_TO_SAFETY:
  221. proceed = false;
  222. break;
  223. default:
  224. NOTREACHED();
  225. }
  226. if (!proceed) {
  227. // With committed interstitials OnReceivedError for safe browsing blocked
  228. // sites is generally called from the blocking page object. Since no
  229. // blocking page is created in this case, we manually call it here.
  230. CallOnReceivedError(AwContentsClientBridge::FromWebContents(web_contents),
  231. request, entry);
  232. }
  233. // Navigate back for back-to-safety on subresources
  234. if (!proceed && resource.is_subframe) {
  235. if (web_contents->GetController().CanGoBack()) {
  236. web_contents->GetController().GoBack();
  237. } else {
  238. web_contents->GetController().LoadURL(
  239. ui_manager->default_safe_page(), content::Referrer(),
  240. ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
  241. }
  242. }
  243. GURL main_frame_url = entry ? entry->GetURL() : GURL();
  244. ui_manager->OnBlockingPageDone(
  245. std::vector<security_interstitials::UnsafeResource>{resource}, proceed,
  246. web_contents, main_frame_url, false /* showed_interstitial */);
  247. }
  248. // static
  249. void AwUrlCheckerDelegateImpl::StartDisplayingDefaultBlockingPage(
  250. scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
  251. const security_interstitials::UnsafeResource& resource) {
  252. content::WebContents* web_contents =
  253. security_interstitials::GetWebContentsForResource(resource);
  254. if (web_contents) {
  255. ui_manager->DisplayBlockingPage(resource);
  256. return;
  257. }
  258. // Reporting back that it is not okay to proceed with loading the URL.
  259. content::GetIOThreadTaskRunner({})->PostTask(
  260. FROM_HERE, base::BindOnce(resource.callback, false /* proceed */,
  261. false /* showed_interstitial */));
  262. }
  263. } // namespace android_webview