remote_database_manager.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Copyright 2015 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 "components/safe_browsing/android/remote_database_manager.h"
  5. #include <memory>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/bind.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_split.h"
  13. #include "base/timer/elapsed_timer.h"
  14. #include "components/safe_browsing/android/safe_browsing_api_handler_bridge.h"
  15. #include "components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h"
  16. #include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
  17. #include "components/variations/variations_associated_data.h"
  18. #include "content/public/browser/browser_task_traits.h"
  19. #include "content/public/browser/browser_thread.h"
  20. #include "services/network/public/cpp/shared_url_loader_factory.h"
  21. using content::BrowserThread;
  22. namespace safe_browsing {
  23. namespace {
  24. // Android field trial for controlling types_to_check.
  25. const char kAndroidFieldExperiment[] = "SafeBrowsingAndroid";
  26. const char kAndroidTypesToCheckParam[] = "types_to_check";
  27. } // namespace
  28. //
  29. // RemoteSafeBrowsingDatabaseManager::ClientRequest methods
  30. //
  31. class RemoteSafeBrowsingDatabaseManager::ClientRequest {
  32. public:
  33. ClientRequest(Client* client,
  34. RemoteSafeBrowsingDatabaseManager* db_manager,
  35. const GURL& url);
  36. static void OnRequestDoneWeak(const base::WeakPtr<ClientRequest>& req,
  37. SBThreatType matched_threat_type,
  38. const ThreatMetadata& metadata);
  39. void OnRequestDone(SBThreatType matched_threat_type,
  40. const ThreatMetadata& metadata);
  41. // Accessors
  42. Client* client() const { return client_; }
  43. const GURL& url() const { return url_; }
  44. base::WeakPtr<ClientRequest> GetWeakPtr() {
  45. return weak_factory_.GetWeakPtr();
  46. }
  47. private:
  48. raw_ptr<Client> client_;
  49. raw_ptr<RemoteSafeBrowsingDatabaseManager> db_manager_;
  50. GURL url_;
  51. base::ElapsedTimer timer_;
  52. base::WeakPtrFactory<ClientRequest> weak_factory_{this};
  53. };
  54. RemoteSafeBrowsingDatabaseManager::ClientRequest::ClientRequest(
  55. Client* client,
  56. RemoteSafeBrowsingDatabaseManager* db_manager,
  57. const GURL& url)
  58. : client_(client), db_manager_(db_manager), url_(url) {}
  59. // Static
  60. void RemoteSafeBrowsingDatabaseManager::ClientRequest::OnRequestDoneWeak(
  61. const base::WeakPtr<ClientRequest>& req,
  62. SBThreatType matched_threat_type,
  63. const ThreatMetadata& metadata) {
  64. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  65. if (!req)
  66. return; // Previously canceled
  67. req->OnRequestDone(matched_threat_type, metadata);
  68. }
  69. void RemoteSafeBrowsingDatabaseManager::ClientRequest::OnRequestDone(
  70. SBThreatType matched_threat_type,
  71. const ThreatMetadata& metadata) {
  72. DVLOG(1) << "OnRequestDone took " << timer_.Elapsed().InMilliseconds()
  73. << " ms for client " << client_ << " and URL " << url_;
  74. client_->OnCheckBrowseUrlResult(url_, matched_threat_type, metadata);
  75. UMA_HISTOGRAM_TIMES("SB2.RemoteCall.Elapsed", timer_.Elapsed());
  76. // CancelCheck() will delete *this.
  77. db_manager_->CancelCheck(client_);
  78. }
  79. //
  80. // RemoteSafeBrowsingDatabaseManager methods
  81. //
  82. // TODO(nparker): Add more tests for this class
  83. RemoteSafeBrowsingDatabaseManager::RemoteSafeBrowsingDatabaseManager()
  84. : SafeBrowsingDatabaseManager(content::GetUIThreadTaskRunner({}),
  85. content::GetIOThreadTaskRunner({})) {
  86. // Avoid memory allocations growing the underlying vector. Although this
  87. // usually wastes a bit of memory, it will still be less than the default
  88. // vector allocation strategy.
  89. request_destinations_to_check_.reserve(
  90. static_cast<int>(network::mojom::RequestDestination::kMaxValue) + 1);
  91. // Decide which request destinations to check. These three are the minimum.
  92. request_destinations_to_check_.insert(
  93. network::mojom::RequestDestination::kDocument);
  94. request_destinations_to_check_.insert(
  95. network::mojom::RequestDestination::kIframe);
  96. request_destinations_to_check_.insert(
  97. network::mojom::RequestDestination::kFrame);
  98. request_destinations_to_check_.insert(
  99. network::mojom::RequestDestination::kFencedframe);
  100. // The param is expected to be a comma-separated list of ints
  101. // corresponding to the enum types. We're keeping this finch
  102. // control around so we can add back types if they later become dangerous.
  103. const std::string ints_str = variations::GetVariationParamValue(
  104. kAndroidFieldExperiment, kAndroidTypesToCheckParam);
  105. if (ints_str.empty()) {
  106. // By default, we check all types except a few.
  107. static_assert(
  108. network::mojom::RequestDestination::kMaxValue ==
  109. network::mojom::RequestDestination::kFencedframe,
  110. "Decide if new request destination should be skipped on mobile.");
  111. for (int t_int = 0;
  112. t_int <=
  113. static_cast<int>(network::mojom::RequestDestination::kMaxValue);
  114. t_int++) {
  115. network::mojom::RequestDestination t =
  116. static_cast<network::mojom::RequestDestination>(t_int);
  117. switch (t) {
  118. case network::mojom::RequestDestination::kStyle:
  119. case network::mojom::RequestDestination::kImage:
  120. case network::mojom::RequestDestination::kFont:
  121. break;
  122. default:
  123. request_destinations_to_check_.insert(t);
  124. }
  125. }
  126. } else {
  127. // Use the finch param.
  128. for (const std::string& val_str : base::SplitString(
  129. ints_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
  130. int i;
  131. if (base::StringToInt(val_str, &i) && i >= 0 &&
  132. i <=
  133. static_cast<int>(network::mojom::RequestDestination::kMaxValue)) {
  134. request_destinations_to_check_.insert(
  135. static_cast<network::mojom::RequestDestination>(i));
  136. }
  137. }
  138. }
  139. }
  140. RemoteSafeBrowsingDatabaseManager::~RemoteSafeBrowsingDatabaseManager() {
  141. DCHECK(!enabled_);
  142. }
  143. void RemoteSafeBrowsingDatabaseManager::CancelCheck(Client* client) {
  144. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  145. DCHECK(enabled_);
  146. for (auto itr = current_requests_.begin(); itr != current_requests_.end();
  147. ++itr) {
  148. if ((*itr)->client() == client) {
  149. DVLOG(2) << "Canceling check for URL " << (*itr)->url();
  150. delete *itr;
  151. current_requests_.erase(itr);
  152. return;
  153. }
  154. }
  155. }
  156. bool RemoteSafeBrowsingDatabaseManager::CanCheckRequestDestination(
  157. network::mojom::RequestDestination request_destination) const {
  158. return request_destinations_to_check_.count(request_destination) > 0;
  159. }
  160. bool RemoteSafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
  161. return url.SchemeIsHTTPOrHTTPS() || url.SchemeIs(url::kFtpScheme) ||
  162. url.SchemeIsWSOrWSS();
  163. }
  164. bool RemoteSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
  165. return true;
  166. }
  167. bool RemoteSafeBrowsingDatabaseManager::CheckBrowseUrl(
  168. const GURL& url,
  169. const SBThreatTypeSet& threat_types,
  170. Client* client) {
  171. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  172. DCHECK(!threat_types.empty());
  173. DCHECK(SBThreatTypeSetIsValidForCheckBrowseUrl(threat_types));
  174. if (!enabled_)
  175. return true;
  176. bool can_check_url = CanCheckUrl(url);
  177. UMA_HISTOGRAM_BOOLEAN("SB2.RemoteCall.CanCheckUrl", can_check_url);
  178. if (!can_check_url)
  179. return true; // Safe, continue right away.
  180. std::unique_ptr<ClientRequest> req(new ClientRequest(client, this, url));
  181. DVLOG(1) << "Checking for client " << client << " and URL " << url;
  182. auto callback =
  183. std::make_unique<SafeBrowsingApiHandlerBridge::ResponseCallback>(
  184. base::BindOnce(&ClientRequest::OnRequestDoneWeak, req->GetWeakPtr()));
  185. SafeBrowsingApiHandlerBridge::GetInstance().StartURLCheck(std::move(callback),
  186. url, threat_types);
  187. current_requests_.push_back(req.release());
  188. // Defer the resource load.
  189. return false;
  190. }
  191. bool RemoteSafeBrowsingDatabaseManager::CheckDownloadUrl(
  192. const std::vector<GURL>& url_chain,
  193. Client* client) {
  194. NOTREACHED();
  195. return true;
  196. }
  197. bool RemoteSafeBrowsingDatabaseManager::CheckExtensionIDs(
  198. const std::set<std::string>& extension_ids,
  199. Client* client) {
  200. NOTREACHED();
  201. return true;
  202. }
  203. bool RemoteSafeBrowsingDatabaseManager::CheckResourceUrl(const GURL& url,
  204. Client* client) {
  205. NOTREACHED();
  206. return true;
  207. }
  208. AsyncMatch
  209. RemoteSafeBrowsingDatabaseManager::CheckUrlForHighConfidenceAllowlist(
  210. const GURL& url,
  211. Client* client) {
  212. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  213. if (!enabled_ || !CanCheckUrl(url))
  214. return AsyncMatch::NO_MATCH;
  215. // TODO(crbug.com/1014202): Make this call async.
  216. bool is_match = SafeBrowsingApiHandlerBridge::GetInstance()
  217. .StartHighConfidenceAllowlistCheck(url);
  218. return is_match ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH;
  219. }
  220. bool RemoteSafeBrowsingDatabaseManager::CheckUrlForAccuracyTips(
  221. const GURL& url,
  222. Client* client) {
  223. NOTREACHED();
  224. return true;
  225. }
  226. bool RemoteSafeBrowsingDatabaseManager::CheckUrlForSubresourceFilter(
  227. const GURL& url,
  228. Client* client) {
  229. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  230. if (!enabled_ || !CanCheckUrl(url))
  231. return true;
  232. std::unique_ptr<ClientRequest> req(new ClientRequest(client, this, url));
  233. DVLOG(1) << "Checking for client " << client << " and URL " << url;
  234. auto callback =
  235. std::make_unique<SafeBrowsingApiHandlerBridge::ResponseCallback>(
  236. base::BindOnce(&ClientRequest::OnRequestDoneWeak, req->GetWeakPtr()));
  237. SafeBrowsingApiHandlerBridge::GetInstance().StartURLCheck(
  238. std::move(callback), url,
  239. CreateSBThreatTypeSet(
  240. {SB_THREAT_TYPE_SUBRESOURCE_FILTER, SB_THREAT_TYPE_URL_PHISHING}));
  241. current_requests_.push_back(req.release());
  242. // Defer the resource load.
  243. return false;
  244. }
  245. AsyncMatch RemoteSafeBrowsingDatabaseManager::CheckCsdAllowlistUrl(
  246. const GURL& url,
  247. Client* client) {
  248. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  249. // If this URL's scheme isn't supported, call is safe.
  250. if (!CanCheckUrl(url)) {
  251. return AsyncMatch::MATCH;
  252. }
  253. // TODO(crbug.com/995926): Make this call async.
  254. bool is_match =
  255. SafeBrowsingApiHandlerBridge::GetInstance().StartCSDAllowlistCheck(url);
  256. return is_match ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH;
  257. }
  258. bool RemoteSafeBrowsingDatabaseManager::MatchDownloadAllowlistUrl(
  259. const GURL& url) {
  260. NOTREACHED();
  261. return true;
  262. }
  263. bool RemoteSafeBrowsingDatabaseManager::MatchMalwareIP(
  264. const std::string& ip_address) {
  265. NOTREACHED();
  266. return false;
  267. }
  268. safe_browsing::ThreatSource RemoteSafeBrowsingDatabaseManager::GetThreatSource()
  269. const {
  270. return safe_browsing::ThreatSource::REMOTE;
  271. }
  272. bool RemoteSafeBrowsingDatabaseManager::IsDownloadProtectionEnabled() const {
  273. return false;
  274. }
  275. void RemoteSafeBrowsingDatabaseManager::StartOnIOThread(
  276. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  277. const V4ProtocolConfig& config) {
  278. VLOG(1) << "RemoteSafeBrowsingDatabaseManager starting";
  279. SafeBrowsingDatabaseManager::StartOnIOThread(url_loader_factory, config);
  280. enabled_ = true;
  281. }
  282. void RemoteSafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
  283. // |shutdown| is not used.
  284. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  285. DVLOG(1) << "RemoteSafeBrowsingDatabaseManager stopping";
  286. // Call back and delete any remaining clients. OnRequestDone() modifies
  287. // |current_requests_|, so we make a copy first.
  288. std::vector<ClientRequest*> to_callback(current_requests_);
  289. for (auto* req : to_callback) {
  290. DVLOG(1) << "Stopping: Invoking unfinished req for URL " << req->url();
  291. req->OnRequestDone(SB_THREAT_TYPE_SAFE, ThreatMetadata());
  292. }
  293. enabled_ = false;
  294. SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
  295. }
  296. } // namespace safe_browsing