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

Side by Side Diff: components/autofill/core/common/save_password_progress_logger.cc

Issue 235623002: Password manager internals page: Improve security (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: innerHTML -> innerText Created 6 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/common/save_password_progress_logger.h" 5 #include "components/autofill/core/common/save_password_progress_logger.h"
6 6
7 #include <algorithm>
8
7 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/scoped_ptr.h"
9 #include "base/numerics/safe_conversions.h" 13 #include "base/numerics/safe_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h" 16 #include "base/values.h"
11 #include "components/autofill/core/common/password_form.h" 17 #include "components/autofill/core/common/password_form.h"
12 18
13 using base::checked_cast; 19 using base::checked_cast;
14 using base::Value; 20 using base::Value;
15 using base::DictionaryValue; 21 using base::DictionaryValue;
16 using base::FundamentalValue; 22 using base::FundamentalValue;
17 using base::StringValue; 23 using base::StringValue;
18 24
19 namespace autofill { 25 namespace autofill {
20 26
21 namespace { 27 namespace {
22 28
29 // These messages can be used as dictionary keys. Do not use '.' in them.
30 const char* const kIDsToMessages[] = {
31 "Decision: ASK the user", // STRING_DECISION_ASK
32 "Decision: DROP the password", // STRING_DECISION_DROP,
33 "Decision: SAVE the password", // STRING_DECISION_SAVE,
34 "Form method", // STRING_METHOD,
35 "GET", // STRING_METHOD_GET,
36 "POST", // STRING_METHOD_POST,
37 "(empty)", // STRING_METHOD_EMPTY,
38 "(other)", // STRING_OTHER,
39 "HTML", // STRING_SCHEME_HTML,
40 "Basic", // STRING_SCHEME_BASIC,
41 "Digest", // STRING_SCHEME_DIGEST,
42 "Scheme", // STRING_SCHEME_MESSAGE,
43 "Signon realm", // STRING_SIGNON_REALM,
44 "Original signon realm", // STRING_ORIGINAL_SIGNON_REALM,
45 "Origin", // STRING_ORIGIN,
46 "Action", // STRING_ACTION,
47 "Username element", // STRING_USERNAME_ELEMENT,
48 "Password element", // STRING_PASSWORD_ELEMENT,
49 "Password autocomplete set", // STRING_PASSWORD_AUTOCOMPLETE_SET,
50 "Old password element", // STRING_OLD_PASSWORD_ELEMENT,
51 "SSL valid", // STRING_SSL_VALID,
52 "Password generated", // STRING_PASSWORD_GENERATED,
53 "Times used", // STRING_TIMES_USED,
54 "Use additional authentication", // STRING_USE_ADDITIONAL_AUTHENTICATION,
55 "PSL match", // STRING_PSL_MATCH,
56 "Form name or ID", // STRING_NAME_OR_ID,
57 "Message", // STRING_MESSAGE,
58 "INVALID", // STRING_INVALID,
59 };
60
61 COMPILE_ASSERT(SavePasswordProgressLogger::StringID::STRING_MAX + 1 ==
62 arraysize(kIDsToMessages),
63 IDsToMessagesMappingIsOutOfDate);
64
23 // Removes privacy sensitive parts of |url| (currently all but host and scheme). 65 // Removes privacy sensitive parts of |url| (currently all but host and scheme).
24 std::string ScrubURL(const GURL& url) { 66 std::string ScrubURL(const GURL& url) {
25 if (url.is_valid()) 67 if (url.is_valid())
26 return url.GetWithEmptyPath().spec(); 68 return url.GetWithEmptyPath().spec();
27 return std::string(); 69 return std::string();
28 } 70 }
29 71
30 std::string FormSchemeToString(PasswordForm::Scheme scheme) { 72 // Returns true for all characters which we don't want to see in the logged IDs
73 // or names of HTML elements.
74 bool IsUnwantedInElementID (char c) {
75 return !IsAsciiAlpha(c) && !IsAsciiDigit(c);
76 }
77
78 // Replaces all characters satisfying IsUnwantedInElementID by a ' ', and turns
79 // all characters to lowercase. This damages some valid HTML element IDs or
80 // names, but it is likely that it will be still possible to match the scrubbed
81 // string to the original ID or name in the HTML doc. That's good enough for the
82 // logging purposes, and provides some security benefits.
83 std::string ScrubElementID(std::string element_id) {
84 std::replace_if(
85 element_id.begin(), element_id.end(), IsUnwantedInElementID, ' ');
86 return StringToLowerASCII(element_id);
87 }
88
89 SavePasswordProgressLogger::StringID FormSchemeToStringID(
90 PasswordForm::Scheme scheme) {
31 switch (scheme) { 91 switch (scheme) {
32 case PasswordForm::SCHEME_HTML: 92 case PasswordForm::SCHEME_HTML:
33 return "HTML"; 93 return SavePasswordProgressLogger::STRING_SCHEME_HTML;
34 case PasswordForm::SCHEME_BASIC: 94 case PasswordForm::SCHEME_BASIC:
35 return "BASIC"; 95 return SavePasswordProgressLogger::STRING_SCHEME_BASIC;
36 case PasswordForm::SCHEME_DIGEST: 96 case PasswordForm::SCHEME_DIGEST:
37 return "DIGEST"; 97 return SavePasswordProgressLogger::STRING_SCHEME_DIGEST;
38 case PasswordForm::SCHEME_OTHER: 98 case PasswordForm::SCHEME_OTHER:
39 return "OTHER"; 99 return SavePasswordProgressLogger::STRING_OTHER;
40 } 100 }
41 NOTREACHED(); // Win compilers don't believe this is unreachable. 101 NOTREACHED(); // Win compilers don't believe this is unreachable.
42 return std::string(); 102 return SavePasswordProgressLogger::StringID::STRING_INVALID;
43 } 103 }
44 104
45 StringValue DecisionToStringValue( 105 SavePasswordProgressLogger::StringID FormMethodToStringID(
46 SavePasswordProgressLogger::Decision decision) { 106 const std::string& method) {
47 switch (decision) { 107 std::string method_processed;
48 case SavePasswordProgressLogger::DECISION_SAVE: 108 base::TrimWhitespaceASCII(
49 return StringValue("SAVE the password"); 109 StringToLowerASCII(method), base::TRIM_ALL, &method_processed);
50 case SavePasswordProgressLogger::DECISION_ASK: 110 if (method_processed.empty())
51 return StringValue("ASK the user whether to save the password"); 111 return SavePasswordProgressLogger::STRING_METHOD_EMPTY;
52 case SavePasswordProgressLogger::DECISION_DROP: 112 else if (method_processed == "get")
53 return StringValue("DROP the password"); 113 return SavePasswordProgressLogger::STRING_METHOD_GET;
114 else if (method_processed == "post")
115 return SavePasswordProgressLogger::STRING_METHOD_POST;
116 else
117 return SavePasswordProgressLogger::STRING_OTHER;
118 }
119
120 // Interprets |log|, sanitizes its value if needed, and returns it as
121 // base::Value. Does not work on LOG_TYPE_LABEL logs.
122 scoped_ptr<Value> GetValueFromStructuredLog(
123 const SavePasswordProgressLogger::StructuredLog& log) {
124 switch (log.log_type) {
125 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_LABEL:
126 NOTREACHED();
127 return scoped_ptr<Value>();
128 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_GURL:
129 return scoped_ptr<Value>(Value::CreateStringValue(ScrubURL(log.url)));
130 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_MESSAGE:
131 return scoped_ptr<Value>(
132 Value::CreateStringValue(kIDsToMessages[log.message]));
133 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_NUMBER:
134 return scoped_ptr<Value>(Value::CreateIntegerValue(log.number));
135 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_BOOL:
136 return scoped_ptr<Value>(Value::CreateBooleanValue(log.truth_value));
137 case SavePasswordProgressLogger::StructuredLog::LOG_TYPE_ELEMENT_ID:
138 return scoped_ptr<Value>(
139 Value::CreateStringValue(ScrubElementID(log.element_id)));
54 } 140 }
55 NOTREACHED(); // Win compilers don't believe this is unreachable. 141 NOTREACHED(); // Win compilers don't believe this is unreachable.
56 return StringValue(std::string()); 142 return scoped_ptr<Value>();
57 } 143 }
58 144
59 } // namespace 145 } // namespace
60 146
147 SavePasswordProgressLogger::StructuredLog::StructuredLog()
148 : log_type(LOG_TYPE_LABEL),
149 label(STRING_INVALID),
150 message(STRING_INVALID),
151 number(0),
152 truth_value(false) {
153 }
154
155 SavePasswordProgressLogger::StructuredLog::StructuredLog(
156 SavePasswordProgressLogger::StringID label)
157 : log_type(LOG_TYPE_LABEL),
158 label(label),
159 message(STRING_INVALID),
160 number(0),
161 truth_value(false) {
162 }
163
164 SavePasswordProgressLogger::StructuredLog::StructuredLog(StringID label,
165 GURL url)
166 : log_type(LOG_TYPE_GURL),
167 label(label),
168 url(url),
169 message(STRING_INVALID),
170 number(0),
171 truth_value(false) {
172 }
173
174 SavePasswordProgressLogger::StructuredLog::StructuredLog(StringID label,
175 StringID message)
176 : log_type(LOG_TYPE_MESSAGE),
177 label(label),
178 message(message),
179 number(0),
180 truth_value(false) {
181 }
182
183 SavePasswordProgressLogger::StructuredLog::StructuredLog(StringID label,
184 int number)
185 : log_type(LOG_TYPE_NUMBER),
186 label(label),
187 message(STRING_INVALID),
188 number(number),
189 truth_value(false) {
190 }
191
192 SavePasswordProgressLogger::StructuredLog::StructuredLog(StringID label,
193 bool truth_value)
194 : log_type(LOG_TYPE_BOOL),
195 label(label),
196 message(STRING_INVALID),
197 number(0),
198 truth_value(truth_value) {
199 }
200
201 SavePasswordProgressLogger::StructuredLog::StructuredLog(
202 StringID label,
203 const base::string16& element_id)
204 : log_type(LOG_TYPE_ELEMENT_ID),
205 label(label),
206 message(STRING_INVALID),
207 number(0),
208 truth_value(false),
209 element_id(UTF16ToUTF8(element_id)) {
210 }
211
212 SavePasswordProgressLogger::StructuredLog::StructuredLog(
213 StringID label,
214 const std::string& element_id)
215 : log_type(LOG_TYPE_ELEMENT_ID),
216 label(label),
217 message(STRING_INVALID),
218 number(0),
219 truth_value(false),
220 element_id(element_id) {
221 }
222
223 SavePasswordProgressLogger::StructuredLog::~StructuredLog() {
224 }
225
226 bool SavePasswordProgressLogger::StructuredLog::operator==(
227 const SavePasswordProgressLogger::StructuredLog& log) const {
228 if (log_type != log.log_type || label != log.label)
229 return false;
230 switch (log_type) {
231 case LOG_TYPE_LABEL:
232 return true;
233 case LOG_TYPE_GURL:
234 return url == log.url;
235 case LOG_TYPE_MESSAGE:
236 return message == log.message;
237 case LOG_TYPE_NUMBER:
238 return number == log.number;
239 case LOG_TYPE_BOOL:
240 return truth_value == log.truth_value;
241 case LOG_TYPE_ELEMENT_ID:
242 return element_id == log.element_id;
243 };
244 NOTREACHED(); // Win compilers don't believe this is unreachable.
245 return false;
246 }
247
248 bool SavePasswordProgressLogger::StructuredLog::operator!=(
249 const SavePasswordProgressLogger::StructuredLog& log) const {
250 return !operator==(log);
251 }
252
253
61 SavePasswordProgressLogger::SavePasswordProgressLogger() {} 254 SavePasswordProgressLogger::SavePasswordProgressLogger() {}
62 255
63 SavePasswordProgressLogger::~SavePasswordProgressLogger() {} 256 SavePasswordProgressLogger::~SavePasswordProgressLogger() {}
64 257
65 void SavePasswordProgressLogger::LogPasswordForm(const std::string& message, 258 // static
66 const PasswordForm& form) { 259 std::string SavePasswordProgressLogger::SanitizeStructuredLogs(
67 DictionaryValue log; 260 const std::vector<SavePasswordProgressLogger::StructuredLog>& logs) {
68 // Do not use the "<<" operator for PasswordForms, because it also prints 261 // First, we sanitize the logs and transform them into a base::Value.
69 // passwords. Also, that operator is only for testing. 262 DictionaryValue log_dict; // Always holds a single item: the log.
70 log.SetString("scheme", FormSchemeToString(form.scheme)); 263 if (logs.size() == 1) {
71 log.SetString("signon realm", ScrubURL(GURL(form.signon_realm))); 264 log_dict.Set(kIDsToMessages[logs[0].label],
72 log.SetString("original signon realm", 265 GetValueFromStructuredLog(logs[0]).release());
73 ScrubURL(GURL(form.original_signon_realm))); 266 } else {
74 log.SetString("origin", ScrubURL(form.origin)); 267 if (logs.empty() || logs[0].log_type != StructuredLog::LOG_TYPE_LABEL) {
75 log.SetString("action", ScrubURL(form.action)); 268 NOTREACHED(); // The logs vector looks damaged.
76 log.SetString("username element", form.username_element); 269 return std::string();
77 log.SetString("password element", form.password_element); 270 }
78 log.SetBoolean("password autocomplete set", form.password_autocomplete_set); 271 scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue);
79 log.SetString("old password element", form.old_password_element); 272 // Transform and add all but the first log into |inner_dict|.
80 log.SetBoolean("ssl valid", form.ssl_valid); 273 for (size_t i = 1; i < logs.size(); ++i) {
81 log.SetBoolean("password generated", 274 inner_dict->Set(kIDsToMessages[logs[i].label],
82 form.type == PasswordForm::TYPE_GENERATED); 275 GetValueFromStructuredLog(logs[i]).release());
83 log.SetInteger("times used", form.times_used); 276 }
84 log.SetBoolean("use additional authentication", 277 log_dict.Set(kIDsToMessages[logs[0].label], inner_dict.release());
85 form.use_additional_authentication); 278 }
86 log.SetBoolean("is PSL match", form.IsPublicSuffixMatch()); 279
87 LogValue(message, log); 280 // Now we convert the base::DictionaryValue to a string.
88 }
89
90 void SavePasswordProgressLogger::LogHTMLForm(const std::string& message,
91 const std::string& name_or_id,
92 const std::string& method,
93 const GURL& action) {
94 DictionaryValue log;
95 log.SetString("name_or_id", name_or_id);
96 log.SetString("method", method);
97 log.SetString("action", ScrubURL(action));
98 LogValue(message, log);
99 }
100
101 void SavePasswordProgressLogger::LogURL(const std::string& message,
102 const GURL& url) {
103 LogValue(message, StringValue(ScrubURL(url)));
104 }
105
106 void SavePasswordProgressLogger::LogBoolean(const std::string& message,
107 bool value) {
108 LogValue(message, FundamentalValue(value));
109 }
110
111 void SavePasswordProgressLogger::LogNumber(const std::string& message,
112 int value) {
113 LogValue(message, FundamentalValue(value));
114 }
115
116 void SavePasswordProgressLogger::LogNumber(const std::string& message,
117 size_t value) {
118 LogValue(message, FundamentalValue(checked_cast<int, size_t>(value)));
119 }
120
121 void SavePasswordProgressLogger::LogFinalDecision(Decision decision) {
122 LogValue("Final decision taken", DecisionToStringValue(decision));
123 }
124
125 void SavePasswordProgressLogger::LogMessage(const std::string& message) {
126 LogValue("Message", StringValue(message));
127 }
128
129 void SavePasswordProgressLogger::LogValue(const std::string& name,
130 const Value& log) {
131 std::string log_string; 281 std::string log_string;
132 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions( 282 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions(
133 &log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); 283 &log_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string);
134 DCHECK(conversion_to_string_successful); 284 DCHECK(conversion_to_string_successful);
135 SendLog(name + ": " + log_string); 285 return log_string;
286 }
287
288 void SavePasswordProgressLogger::LogPasswordForm(
289 SavePasswordProgressLogger::StringID label,
290 const PasswordForm& form) {
291 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
292 logs.reserve(15);
293 logs.push_back(StructuredLog(label));
294 logs.push_back(
295 StructuredLog(STRING_SCHEME_MESSAGE, FormSchemeToStringID(form.scheme)));
296 logs.push_back(StructuredLog(STRING_SIGNON_REALM, GURL(form.signon_realm)));
297 logs.push_back(StructuredLog(STRING_ORIGINAL_SIGNON_REALM,
298 GURL(form.original_signon_realm)));
299 logs.push_back(StructuredLog(STRING_ORIGIN, form.origin));
300 logs.push_back(StructuredLog(STRING_ACTION, form.action));
301 logs.push_back(StructuredLog(STRING_USERNAME_ELEMENT, form.username_element));
302 logs.push_back(StructuredLog(STRING_PASSWORD_ELEMENT, form.password_element));
303 logs.push_back(StructuredLog(STRING_PASSWORD_AUTOCOMPLETE_SET,
304 form.password_autocomplete_set));
305 logs.push_back(
306 StructuredLog(STRING_OLD_PASSWORD_ELEMENT, form.old_password_element));
307 logs.push_back(StructuredLog(STRING_SSL_VALID, form.ssl_valid));
308 logs.push_back(StructuredLog(STRING_PASSWORD_GENERATED,
309 form.type == PasswordForm::TYPE_GENERATED));
310 logs.push_back(StructuredLog(STRING_TIMES_USED, form.times_used));
311 logs.push_back(StructuredLog(STRING_USE_ADDITIONAL_AUTHENTICATION,
312 form.use_additional_authentication));
313 logs.push_back(StructuredLog(STRING_PSL_MATCH, form.IsPublicSuffixMatch()));
314 SendLog(logs);
315 }
316
317 void SavePasswordProgressLogger::LogHTMLForm(
318 SavePasswordProgressLogger::StringID label,
319 const std::string& name_or_id,
320 const std::string& method,
321 const GURL& action) {
322 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
323 logs.reserve(4);
324 logs.push_back(StructuredLog(label));
325 logs.push_back(StructuredLog(STRING_NAME_OR_ID, name_or_id));
326 logs.push_back(StructuredLog(STRING_METHOD, FormMethodToStringID(method)));
327 logs.push_back(StructuredLog(STRING_ACTION, action));
328 SendLog(logs);
329 }
330
331 void SavePasswordProgressLogger::LogURL(
332 SavePasswordProgressLogger::StringID label,
333 const GURL& url) {
334 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
335 logs.push_back(StructuredLog(label, url));
336 SendLog(logs);
337 }
338
339 void SavePasswordProgressLogger::LogBoolean(
340 SavePasswordProgressLogger::StringID label,
341 bool value) {
342 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
343 logs.push_back(StructuredLog(label, value));
344 SendLog(logs);
345 }
346
347 void SavePasswordProgressLogger::LogNumber(
348 SavePasswordProgressLogger::StringID label,
349 int value) {
350 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
351 logs.push_back(StructuredLog(label, value));
352 SendLog(logs);
353 }
354
355 void SavePasswordProgressLogger::LogNumber(
356 SavePasswordProgressLogger::StringID label,
357 size_t value) {
358 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
359 logs.push_back(StructuredLog(label, checked_cast<int, size_t>(value)));
360 SendLog(logs);
361 }
362
363 void SavePasswordProgressLogger::LogMessage(
364 SavePasswordProgressLogger::StringID message) {
365 std::vector<SavePasswordProgressLogger::StructuredLog> logs;
366 logs.push_back(StructuredLog(STRING_MESSAGE, message));
367 SendLog(logs);
136 } 368 }
137 369
138 } // namespace autofill 370 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698