Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: chrome/browser/safe_browsing/safe_browsing_impl.cc

Issue 2900563002: Network service: Safe browsing check for sub-resources from renderer. (Closed)
Patch Set: . Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
5 #include "chrome/browser/safe_browsing/safe_browsing_impl.h"
6
7 #include <vector>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/timer/timer.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/prerender/prerender_contents.h"
14 #include "chrome/browser/safe_browsing/ui_manager.h"
15 #include "components/safe_browsing_db/database_manager.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/resource_type.h"
20 #include "mojo/public/cpp/bindings/strong_binding.h"
21 #include "net/base/load_flags.h"
22
23 namespace safe_browsing {
24 namespace {
25
26 // TODO(yzshen): Share such value with safe_browsing::BaseResourceThrottle.
27 // Maximum time in milliseconds to wait for the safe browsing service to
28 // verify a URL. After this amount of time the outstanding check will be
29 // aborted, and the URL will be treated as if it were safe.
30 const int kCheckUrlTimeoutMs = 5000;
31
32 content::WebContents* GetWebContentsFromID(int render_process_id,
33 int render_frame_id) {
34 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
35 content::RenderFrameHost* render_frame_host =
36 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
37 if (!render_frame_host)
38 return nullptr;
39
40 return content::WebContents::FromRenderFrameHost(render_frame_host);
41 }
42
43 // TODO(yzshen): Handle the case where safe browsing is not enabled, or
44 // !database_manager()->IsSupported().
45 // TODO(yzshen): Make sure it also works on Andorid.
46 // TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
47 class SafeBrowsingUrlCheckerImpl : public chrome::mojom::SafeBrowsingUrlChecker,
48 public SafeBrowsingDatabaseManager::Client {
49 public:
50 SafeBrowsingUrlCheckerImpl(
51 int load_flags,
52 content::ResourceType resource_type,
53
kinuko 2017/05/25 11:30:57 nit: extra empty line
yzshen1 2017/05/26 20:43:51 Done.
54 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
55 scoped_refptr<SafeBrowsingUIManager> ui_manager,
56 int render_process_id,
57 int render_frame_id)
58 : load_flags_(load_flags),
59 resource_type_(resource_type),
60 render_process_id_(render_process_id),
61 render_frame_id_(render_frame_id),
62 database_manager_(std::move(database_manager)),
63 ui_manager_(std::move(ui_manager)),
64 weak_factory_(this) {
65 DCHECK_NE(resource_type, content::RESOURCE_TYPE_MAIN_FRAME);
66 DCHECK_NE(resource_type, content::RESOURCE_TYPE_SUB_FRAME);
67 }
68
69 ~SafeBrowsingUrlCheckerImpl() override {
70 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
71
72 if (state_ == STATE_CHECKING_URL)
73 database_manager_->CancelCheck(this);
74
75 for (size_t i = next_index_; i < callbacks_.size(); ++i)
76 callbacks_[i].Run(false);
77 }
78
79 // chrome::mojom::SafeBrowsingUrlChecker implementation.
80 void CheckUrl(const GURL& url, const CheckUrlCallback& callback) override {
81 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
82
83 DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
84 urls_.push_back(url);
85 callbacks_.push_back(callback);
86
87 ProcessUrls();
88 }
89
90 private:
91 // SafeBrowsingDatabaseManager::Client implementation:
92 void OnCheckBrowseUrlResult(const GURL& url,
93 SBThreatType threat_type,
94 const ThreatMetadata& metadata) override {
95 DCHECK_EQ(STATE_CHECKING_URL, state_);
96 DCHECK_LT(next_index_, urls_.size());
97 DCHECK_EQ(urls_[next_index_], url);
98
99 timer_.Stop();
100 if (threat_type == SB_THREAT_TYPE_SAFE) {
101 state_ = STATE_NONE;
102 callbacks_[next_index_].Run(true);
103 callbacks_[next_index_].Reset();
104 next_index_++;
105 ProcessUrls();
106 return;
107 }
108
109 if (load_flags_ & net::LOAD_PREFETCH) {
110 BlockAndProcessUrls();
111 return;
112 }
113
114 security_interstitials::UnsafeResource resource;
115 resource.url = url;
116 resource.original_url = urls_[0];
117 if (urls_.size() > 1)
118 resource.redirect_urls =
119 std::vector<GURL>(urls_.begin() + 1, urls_.end());
120 resource.is_subresource = true;
121 resource.is_subframe = false;
122 resource.threat_type = threat_type;
123 resource.threat_metadata = metadata;
124 resource.callback =
125 base::Bind(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
126 weak_factory_.GetWeakPtr());
127 resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
128 content::BrowserThread::IO);
129 resource.web_contents_getter =
130 base::Bind(&GetWebContentsFromID, render_process_id_, render_frame_id_);
131 resource.threat_source = database_manager_->GetThreatSource();
132
133 state_ = STATE_DISPLAYING_BLOCKING_PAGE;
134
135 content::BrowserThread::PostTask(
136 content::BrowserThread::UI, FROM_HERE,
137 base::Bind(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
138 weak_factory_.GetWeakPtr(), ui_manager_, resource));
139 }
140
141 static void StartDisplayingBlockingPage(
142 const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
143 scoped_refptr<BaseUIManager> ui_manager,
144 const security_interstitials::UnsafeResource& resource) {
145 content::WebContents* web_contents = resource.web_contents_getter.Run();
146 if (web_contents) {
147 prerender::PrerenderContents* prerender_contents =
148 prerender::PrerenderContents::FromWebContents(web_contents);
149 if (prerender_contents) {
150 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
151 } else {
152 ui_manager->DisplayBlockingPage(resource);
153 return;
154 }
155 }
156
157 // Tab is gone or it's being prerendered.
158 content::BrowserThread::PostTask(
159 content::BrowserThread::IO, FROM_HERE,
160 base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
161 checker));
162 }
163
164 void OnCheckUrlTimeout() {
165 database_manager_->CancelCheck(this);
166
167 OnCheckBrowseUrlResult(urls_[next_index_],
168 safe_browsing::SB_THREAT_TYPE_SAFE,
169 ThreatMetadata());
170 }
171
172 void ProcessUrls() {
173 if (state_ == STATE_CHECKING_URL ||
174 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
175 return;
176 }
177
178 while (next_index_ < urls_.size()) {
179 if (state_ == STATE_BLOCKED) {
180 callbacks_[next_index_].Run(false);
181 callbacks_[next_index_].Reset();
182 next_index_++;
183 continue;
184 }
185
186 DCHECK_EQ(STATE_NONE, state_);
187 // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
188 // side. That would save some IPCs.
189 if (!database_manager_->CanCheckResourceType(resource_type_) ||
190 database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
191 callbacks_[next_index_].Run(true);
192 callbacks_[next_index_].Reset();
193 next_index_++;
194 continue;
195 }
196
197 state_ = STATE_CHECKING_URL;
198 // Start a timer to abort the check if it takes too long.
199 timer_.Start(FROM_HERE,
200 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
201 &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
202
203 break;
204 };
205 }
206
207 void BlockAndProcessUrls() {
208 DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
209 state_ = STATE_BLOCKED;
210 ProcessUrls();
211 }
212
213 void OnBlockingPageComplete(bool proceed) {
214 DCHECK_EQ(STATE_DISPLAYING_BLOCKING_PAGE, state_);
215
216 if (proceed) {
217 state_ = STATE_NONE;
218 callbacks_[next_index_].Run(true);
219 callbacks_[next_index_].Reset();
220 next_index_++;
221 ProcessUrls();
222 } else {
223 BlockAndProcessUrls();
224 }
225 }
226
227 enum State {
228 // Haven't started checking or checking is complete.
229 STATE_NONE,
230 // We have one outstanding URL-check.
231 STATE_CHECKING_URL,
232 // We're displaying a blocking page.
233 STATE_DISPLAYING_BLOCKING_PAGE,
234 // The blocking page has returned *not* to proceed.
235 STATE_BLOCKED
236 };
237
238 const int load_flags_;
239 const content::ResourceType resource_type_;
240 const int render_process_id_;
241 const int render_frame_id_;
242 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
243 scoped_refptr<BaseUIManager> ui_manager_;
244
245 // The redirect chain for this resource, including the original URL and
246 // subsequent redirect URLs.
247 std::vector<GURL> urls_;
248 std::vector<CheckUrlCallback> callbacks_;
249 size_t next_index_ = 0;
250
251 State state_ = STATE_NONE;
252
253 // Timer to abort the safe browsing check if it takes too long.
254 base::OneShotTimer timer_;
255
256 base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
257
258 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
259 };
260
261 } // namespace
262
263 SafeBrowsingImpl::SafeBrowsingImpl(
264 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
265 scoped_refptr<SafeBrowsingUIManager> ui_manager,
266 int render_process_id,
267 int render_frame_id)
268 : database_manager_(std::move(database_manager)),
269 ui_manager_(std::move(ui_manager)),
270 render_process_id_(render_process_id),
271 render_frame_id_(render_frame_id) {}
272
273 SafeBrowsingImpl::~SafeBrowsingImpl() {
274 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
275 }
276
277 // static
278 void SafeBrowsingImpl::Create(
279 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
280 scoped_refptr<SafeBrowsingUIManager> ui_manager,
281 int render_process_id,
282 int render_frame_id,
283 const service_manager::BindSourceInfo& source_info,
284 chrome::mojom::SafeBrowsingRequest request) {
285 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
286 mojo::MakeStrongBinding(
287 base::MakeUnique<SafeBrowsingImpl>(std::move(database_manager),
288 std::move(ui_manager),
289 render_process_id, render_frame_id),
290 std::move(request));
291 }
292
293 void SafeBrowsingImpl::CreateCheckerAndCheck(
294 chrome::mojom::SafeBrowsingUrlCheckerRequest request,
295 const GURL& url,
296 int32_t load_flags,
297 content::ResourceType resource_type,
298 const CreateCheckerAndCheckCallback& callback) {
299 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
300 auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
301 load_flags, resource_type, database_manager_, ui_manager_,
302 render_process_id_, render_frame_id_);
303 checker_impl->CheckUrl(url, callback);
304 mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
305 }
306
307 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698