OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #ifndef CHROME_BROWSER_SAFE_BROWSING_THREAT_DETAILS_H_ | |
6 #define CHROME_BROWSER_SAFE_BROWSING_THREAT_DETAILS_H_ | |
7 | |
8 // A class that encapsulates the detailed threat reports sent when | |
9 // users opt-in to do so from the safe browsing warning page. | |
10 | |
11 // An instance of this class is generated when a safe browsing warning page | |
12 // is shown (SafeBrowsingBlockingPage). | |
13 | |
14 #include <memory> | |
15 #include <string> | |
16 #include <unordered_set> | |
17 #include <vector> | |
18 | |
19 #include "base/containers/hash_tables.h" | |
20 #include "base/gtest_prod_util.h" | |
21 #include "base/macros.h" | |
22 #include "base/memory/ref_counted.h" | |
23 #include "components/safe_browsing/common/safebrowsing_types.h" | |
24 #include "components/safe_browsing/csd.pb.h" | |
25 #include "components/security_interstitials/content/unsafe_resource.h" | |
26 #include "content/public/browser/browser_thread.h" | |
27 #include "content/public/browser/web_contents_observer.h" | |
28 #include "net/base/completion_callback.h" | |
29 | |
30 namespace history { | |
31 class HistoryService; | |
32 } // namespace history | |
33 | |
34 namespace net { | |
35 class URLRequestContextGetter; | |
36 } // namespace net | |
37 | |
38 struct SafeBrowsingHostMsg_ThreatDOMDetails_Node; | |
39 | |
40 namespace safe_browsing { | |
41 | |
42 class BaseUIManager; | |
43 | |
44 // Maps a URL to its Resource. | |
45 class ThreatDetailsCacheCollector; | |
46 class ThreatDetailsRedirectsCollector; | |
47 class ThreatDetailsFactory; | |
48 | |
49 using ResourceMap = | |
50 base::hash_map<std::string, | |
51 std::unique_ptr<ClientSafeBrowsingReportRequest::Resource>>; | |
52 | |
53 // Maps a key of an HTML element to its corresponding HTMLElement proto message. | |
54 // HTML Element keys have the form "<frame_id>-<node_id>", where |frame_id| is | |
55 // the FrameTree NodeID of the render frame containing the element, and | |
56 // |node_id| is a seqeuntial ID for the element generated by the renderer. | |
57 using ElementMap = base::hash_map<std::string, std::unique_ptr<HTMLElement>>; | |
58 | |
59 // Maps a URL to some HTML Elements. Used to maintain parent/child relationship | |
60 // for HTML Elements across IFrame boundaries. | |
61 // The key is the string URL set as the src attribute of an iframe. The value is | |
62 // the HTMLElement proto that represents the iframe element with that URL. | |
63 // The HTMLElement protos are not owned by this map. | |
64 using UrlToDomElementMap = base::hash_map<std::string, HTMLElement*>; | |
65 | |
66 // Maps a URL to some Element IDs. Used to maintain parent/child relationship | |
67 // for HTML Elements across IFrame boundaries. | |
68 // The key is the string URL of a render frame. The value is the set of Element | |
69 // IDs that are at the top-level of this render frame. | |
70 using UrlToChildIdsMap = base::hash_map<std::string, std::unordered_set<int>>; | |
71 | |
72 class ThreatDetails : public base::RefCountedThreadSafe< | |
73 ThreatDetails, | |
74 content::BrowserThread::DeleteOnUIThread>, | |
75 public content::WebContentsObserver { | |
76 public: | |
77 typedef security_interstitials::UnsafeResource UnsafeResource; | |
78 | |
79 // Constructs a new ThreatDetails instance, using the factory. | |
80 static ThreatDetails* NewThreatDetails( | |
81 BaseUIManager* ui_manager, | |
82 content::WebContents* web_contents, | |
83 const UnsafeResource& resource, | |
84 net::URLRequestContextGetter* request_context_getter, | |
85 history::HistoryService* history_service); | |
86 | |
87 // Makes the passed |factory| the factory used to instantiate | |
88 // SafeBrowsingBlockingPage objects. Useful for tests. | |
89 static void RegisterFactory(ThreatDetailsFactory* factory) { | |
90 factory_ = factory; | |
91 } | |
92 | |
93 // The SafeBrowsingBlockingPage calls this from the IO thread when | |
94 // the user is leaving the blocking page and has opted-in to sending | |
95 // the report. We start the redirection urls collection from history service | |
96 // in UI thread; then do cache collection back in IO thread. We also record | |
97 // if the user did proceed with the warning page, and how many times user | |
98 // visited this page before. When we are done, we send the report. | |
99 void FinishCollection(bool did_proceed, int num_visits); | |
100 | |
101 void OnCacheCollectionReady(); | |
102 | |
103 void OnRedirectionCollectionReady(); | |
104 | |
105 // content::WebContentsObserver implementation. | |
106 bool OnMessageReceived(const IPC::Message& message, | |
107 content::RenderFrameHost* render_frame_host) override; | |
108 | |
109 protected: | |
110 friend class ThreatDetailsFactoryImpl; | |
111 friend class TestThreatDetailsFactory; | |
112 | |
113 ThreatDetails(BaseUIManager* ui_manager, | |
114 content::WebContents* web_contents, | |
115 const UnsafeResource& resource, | |
116 net::URLRequestContextGetter* request_context_getter, | |
117 history::HistoryService* history_service); | |
118 | |
119 ~ThreatDetails() override; | |
120 | |
121 // Called on the IO thread with the DOM details. | |
122 virtual void AddDOMDetails( | |
123 const int frame_tree_node_id, | |
124 const GURL& frame_last_committed_url, | |
125 const std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>& params); | |
126 | |
127 // The report protocol buffer. | |
128 std::unique_ptr<ClientSafeBrowsingReportRequest> report_; | |
129 | |
130 // Used to get a pointer to the HTTP cache. | |
131 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | |
132 | |
133 private: | |
134 friend class base::RefCountedThreadSafe<ThreatDetails>; | |
135 friend struct content::BrowserThread::DeleteOnThread< | |
136 content::BrowserThread::UI>; | |
137 friend class base::DeleteHelper<ThreatDetails>; | |
138 | |
139 // Starts the collection of the report. | |
140 void StartCollection(); | |
141 | |
142 // Whether the url is "public" so we can add it to the report. | |
143 bool IsReportableUrl(const GURL& url) const; | |
144 | |
145 // Finds an existing Resource for the given url, or creates a new one if not | |
146 // found, and adds it to |resources_|. Returns the found/created resource. | |
147 ClientSafeBrowsingReportRequest::Resource* FindOrCreateResource( | |
148 const GURL& url); | |
149 | |
150 // Finds an existing HTMLElement for a given key, or creates a new one if not | |
151 // found and adds it to |elements_|. Returns the found/created element. | |
152 HTMLElement* FindOrCreateElement(const std::string& element_key); | |
153 | |
154 // Adds a Resource to resources_ with the given parent-child | |
155 // relationship. |parent| and |tagname| can be empty, |children| can be NULL. | |
156 // Returns the Resource that was affected, or null if no work was done. | |
157 ClientSafeBrowsingReportRequest::Resource* AddUrl( | |
158 const GURL& url, | |
159 const GURL& parent, | |
160 const std::string& tagname, | |
161 const std::vector<GURL>* children); | |
162 | |
163 // Message handler. | |
164 void OnReceivedThreatDOMDetails( | |
165 content::RenderFrameHost* sender, | |
166 const std::vector<SafeBrowsingHostMsg_ThreatDOMDetails_Node>& params); | |
167 | |
168 void AddRedirectUrlList(const std::vector<GURL>& urls); | |
169 | |
170 // Adds an HTML Element to the DOM structure. | |
171 // |frame_tree_node_id| is the unique ID of the render frame the element came | |
172 // from. |frame_url| is the URL that the render frame was handling. | |
173 // |element_node_id| is a unique ID of the element within the render frame. | |
174 // |tag_name| is the tag of the element. |parent_element_node_id| is the | |
175 // unique ID of the parent element with the render frame. |attributes| | |
176 // containes the names and values of the element's attributes.|resource| is | |
177 // set if this element is a resource. | |
178 void AddDomElement(const int frame_tree_node_id, | |
179 const std::string& frame_url, | |
180 const int element_node_id, | |
181 const std::string& tag_name, | |
182 const int parent_element_node_id, | |
183 const std::vector<AttributeNameValue>& attributes, | |
184 const ClientSafeBrowsingReportRequest::Resource* resource); | |
185 | |
186 scoped_refptr<BaseUIManager> ui_manager_; | |
187 | |
188 const UnsafeResource resource_; | |
189 | |
190 // For every Url we collect we create a Resource message. We keep | |
191 // them in a map so we can avoid duplicates. | |
192 ResourceMap resources_; | |
193 | |
194 // Store all HTML elements collected, keep them in a map for easy lookup. | |
195 ElementMap elements_; | |
196 | |
197 // For each iframe element encountered we map the src of the iframe to the | |
198 // iframe element. This is used when we receive elements from a different | |
199 // frame whose document URL matches the src of an iframe in this map. We can | |
200 // then add all elements from the subframe as children of the iframe element | |
201 // stored here. | |
202 UrlToDomElementMap iframe_src_to_element_map_; | |
203 | |
204 // When getting a set of elements from a render frame, we store the frame's | |
205 // URL and a collection of all the top-level elements in that frame. When we | |
206 // later encounter the parent iframe with the same src URL, we can add all of | |
207 // these elements as children of that iframe. | |
208 UrlToChildIdsMap document_url_to_children_map_; | |
209 | |
210 // Result from the cache extractor. | |
211 bool cache_result_; | |
212 | |
213 // Whether user did proceed with the safe browsing blocking page or | |
214 // not. | |
215 bool did_proceed_; | |
216 | |
217 // How many times this user has visited this page before. | |
218 int num_visits_; | |
219 | |
220 // Keeps track of whether we have an ambiguous DOM in this report. This can | |
221 // happen when the HTML Elements returned by a render frame can't be | |
222 // associated with a parent Element in the parent frame. | |
223 bool ambiguous_dom_; | |
224 | |
225 // The factory used to instanciate SafeBrowsingBlockingPage objects. | |
226 // Usefull for tests, so they can provide their own implementation of | |
227 // SafeBrowsingBlockingPage. | |
228 static ThreatDetailsFactory* factory_; | |
229 | |
230 // Used to collect details from the HTTP Cache. | |
231 scoped_refptr<ThreatDetailsCacheCollector> cache_collector_; | |
232 | |
233 // Used to collect redirect urls from the history service | |
234 scoped_refptr<ThreatDetailsRedirectsCollector> redirects_collector_; | |
235 | |
236 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HistoryServiceUrls); | |
237 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HttpsResourceSanitization); | |
238 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HTTPCacheNoEntries); | |
239 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HTTPCache); | |
240 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM); | |
241 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames); | |
242 FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails); | |
243 | |
244 DISALLOW_COPY_AND_ASSIGN(ThreatDetails); | |
245 }; | |
246 | |
247 // Factory for creating ThreatDetails. Useful for tests. | |
248 class ThreatDetailsFactory { | |
249 public: | |
250 virtual ~ThreatDetailsFactory() {} | |
251 | |
252 virtual ThreatDetails* CreateThreatDetails( | |
253 BaseUIManager* ui_manager, | |
254 content::WebContents* web_contents, | |
255 const security_interstitials::UnsafeResource& unsafe_resource, | |
256 net::URLRequestContextGetter* request_context_getter, | |
257 history::HistoryService* history_service) = 0; | |
258 }; | |
259 | |
260 } // namespace safe_browsing | |
261 | |
262 #endif // CHROME_BROWSER_SAFE_BROWSING_THREAT_DETAILS_H_ | |
OLD | NEW |