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

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: Compile errors fixed 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/memory/scoped_ptr.h"
9 #include "base/numerics/safe_conversions.h" 12 #include "base/numerics/safe_conversions.h"
13 #include "base/strings/string16.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 // Note 1: Caching the ID->string map in an array would be probably faster, but
30 // the switch statement is (a) robust against re-ordering, and (b) checks in
31 // compile-time, that all IDs get a string assigned. The expected frequency of
32 // calls is low enough (in particular, zero if password manager internals page
33 // is not open), that optimizing for code robustness is preferred against speed.
34 // Note 2: The messages can be used as dictionary keys. Do not use '.' in them.
35 std::string GetStringFromID(SavePasswordProgressLogger::StringID id) {
36 switch (id) {
37 case SavePasswordProgressLogger::STRING_DECISION_ASK:
38 return "Decision: ASK the user";
39 case SavePasswordProgressLogger::STRING_DECISION_DROP:
40 return "Decision: DROP the password";
41 case SavePasswordProgressLogger::STRING_DECISION_SAVE:
42 return "Decision: SAVE the password";
43 case SavePasswordProgressLogger::STRING_METHOD:
44 return "Form method";
45 case SavePasswordProgressLogger::STRING_METHOD_GET:
46 return "GET";
47 case SavePasswordProgressLogger::STRING_METHOD_POST:
48 return "POST";
49 case SavePasswordProgressLogger::STRING_METHOD_EMPTY:
50 return "(empty)";
51 case SavePasswordProgressLogger::STRING_OTHER:
52 return "(other)";
53 case SavePasswordProgressLogger::STRING_SCHEME_HTML:
54 return "HTML";
55 case SavePasswordProgressLogger::STRING_SCHEME_BASIC:
56 return "Basic";
57 case SavePasswordProgressLogger::STRING_SCHEME_DIGEST:
58 return "Digest";
59 case SavePasswordProgressLogger::STRING_SCHEME_MESSAGE:
60 return "Scheme";
61 case SavePasswordProgressLogger::STRING_SIGNON_REALM:
62 return "Signon realm";
63 case SavePasswordProgressLogger::STRING_ORIGINAL_SIGNON_REALM:
64 return "Original signon realm";
65 case SavePasswordProgressLogger::STRING_ORIGIN:
66 return "Origin";
67 case SavePasswordProgressLogger::STRING_ACTION:
68 return "Action";
69 case SavePasswordProgressLogger::STRING_USERNAME_ELEMENT:
70 return "Username element";
71 case SavePasswordProgressLogger::STRING_PASSWORD_ELEMENT:
72 return "Password element";
73 case SavePasswordProgressLogger::STRING_PASSWORD_AUTOCOMPLETE_SET:
74 return "Password autocomplete set";
75 case SavePasswordProgressLogger::STRING_OLD_PASSWORD_ELEMENT:
76 return "Old password element";
77 case SavePasswordProgressLogger::STRING_SSL_VALID:
78 return "SSL valid";
79 case SavePasswordProgressLogger::STRING_PASSWORD_GENERATED:
80 return "Password generated";
81 case SavePasswordProgressLogger::STRING_TIMES_USED:
82 return "Times used";
83 case SavePasswordProgressLogger::STRING_USE_ADDITIONAL_AUTHENTICATION:
84 return "Use additional authentication";
85 case SavePasswordProgressLogger::STRING_PSL_MATCH:
86 return "PSL match";
87 case SavePasswordProgressLogger::STRING_NAME_OR_ID:
88 return "Form name or ID";
89 case SavePasswordProgressLogger::STRING_MESSAGE:
90 return "Message";
91 case SavePasswordProgressLogger::STRING_INVALID:
92 return "INVALID";
93 // Intentionally no default: clause here -- all IDs need to get covered.
94 }
95 NOTREACHED(); // Win compilers don't believe this is unreachable.
96 return std::string();
97 };
98
23 // Removes privacy sensitive parts of |url| (currently all but host and scheme). 99 // Removes privacy sensitive parts of |url| (currently all but host and scheme).
24 std::string ScrubURL(const GURL& url) { 100 std::string ScrubURL(const GURL& url) {
25 if (url.is_valid()) 101 if (url.is_valid())
26 return url.GetWithEmptyPath().spec(); 102 return url.GetWithEmptyPath().spec();
27 return std::string(); 103 return std::string();
28 } 104 }
29 105
30 std::string FormSchemeToString(PasswordForm::Scheme scheme) { 106 // Returns true for all characters which we don't want to see in the logged IDs
107 // or names of HTML elements.
108 bool IsUnwantedInElementID(char c) {
109 return !(c == '_' || c == '-' || IsAsciiAlpha(c) || IsAsciiDigit(c));
110 }
111
112 // Replaces all characters satisfying IsUnwantedInElementID by a ' ', and turns
113 // all characters to lowercase. This damages some valid HTML element IDs or
114 // names, but it is likely that it will be still possible to match the scrubbed
115 // string to the original ID or name in the HTML doc. That's good enough for the
116 // logging purposes, and provides some security benefits.
117 std::string ScrubElementID(std::string element_id) {
118 std::replace_if(
119 element_id.begin(), element_id.end(), IsUnwantedInElementID, ' ');
120 return StringToLowerASCII(element_id);
121 }
122
123 SavePasswordProgressLogger::StringID FormSchemeToStringID(
124 PasswordForm::Scheme scheme) {
31 switch (scheme) { 125 switch (scheme) {
32 case PasswordForm::SCHEME_HTML: 126 case PasswordForm::SCHEME_HTML:
33 return "HTML"; 127 return SavePasswordProgressLogger::STRING_SCHEME_HTML;
34 case PasswordForm::SCHEME_BASIC: 128 case PasswordForm::SCHEME_BASIC:
35 return "BASIC"; 129 return SavePasswordProgressLogger::STRING_SCHEME_BASIC;
36 case PasswordForm::SCHEME_DIGEST: 130 case PasswordForm::SCHEME_DIGEST:
37 return "DIGEST"; 131 return SavePasswordProgressLogger::STRING_SCHEME_DIGEST;
38 case PasswordForm::SCHEME_OTHER: 132 case PasswordForm::SCHEME_OTHER:
39 return "OTHER"; 133 return SavePasswordProgressLogger::STRING_OTHER;
40 } 134 }
41 NOTREACHED(); // Win compilers don't believe this is unreachable. 135 NOTREACHED(); // Win compilers don't believe this is unreachable.
42 return std::string(); 136 return SavePasswordProgressLogger::STRING_INVALID;
43 } 137 }
44 138
45 StringValue DecisionToStringValue( 139 SavePasswordProgressLogger::StringID FormMethodToStringID(
46 SavePasswordProgressLogger::Decision decision) { 140 const std::string& method) {
47 switch (decision) { 141 std::string method_processed;
48 case SavePasswordProgressLogger::DECISION_SAVE: 142 base::TrimWhitespaceASCII(
49 return StringValue("SAVE the password"); 143 StringToLowerASCII(method), base::TRIM_ALL, &method_processed);
50 case SavePasswordProgressLogger::DECISION_ASK: 144 if (method_processed.empty())
51 return StringValue("ASK the user whether to save the password"); 145 return SavePasswordProgressLogger::STRING_METHOD_EMPTY;
52 case SavePasswordProgressLogger::DECISION_DROP: 146 else if (method_processed == "get")
53 return StringValue("DROP the password"); 147 return SavePasswordProgressLogger::STRING_METHOD_GET;
54 } 148 else if (method_processed == "post")
55 NOTREACHED(); // Win compilers don't believe this is unreachable. 149 return SavePasswordProgressLogger::STRING_METHOD_POST;
56 return StringValue(std::string()); 150 else
151 return SavePasswordProgressLogger::STRING_OTHER;
152 }
153
154 // GetValueFrom*: Sanitize the arguments, and return them as base::Value.
155 scoped_ptr<Value> GetValueFromURL(const GURL& url) {
156 return scoped_ptr<Value>(Value::CreateStringValue(ScrubURL(url)));
157 }
158
159 scoped_ptr<Value> GetValueFromMessage(
160 SavePasswordProgressLogger::StringID message) {
161 return scoped_ptr<Value>(Value::CreateStringValue(GetStringFromID(message)));
162 }
163
164 scoped_ptr<Value> GetValueFromNumber(int number) {
165 return scoped_ptr<Value>(Value::CreateIntegerValue(number));
166 }
167
168 scoped_ptr<Value> GetValueFromBoolean(bool truth_value) {
169 return scoped_ptr<Value>(Value::CreateBooleanValue(truth_value));
170 }
171
172 scoped_ptr<Value> GetValueFromElementID(const std::string& element_id) {
173 return scoped_ptr<Value>(
174 Value::CreateStringValue(ScrubElementID(element_id)));
175 }
176
177 void AddURLToDict(DictionaryValue* dict,
178 SavePasswordProgressLogger::StringID label,
179 const GURL& url) {
180 dict->Set(GetStringFromID(label), GetValueFromURL(url).release());
181 }
182
183 void AddMessageToDict(DictionaryValue* dict,
184 SavePasswordProgressLogger::StringID label,
185 SavePasswordProgressLogger::StringID message) {
186 dict->Set(GetStringFromID(label), GetValueFromMessage(message).release());
187 }
188
189 void AddNumberToDict(DictionaryValue* dict,
190 SavePasswordProgressLogger::StringID label,
191 int number) {
192 dict->Set(GetStringFromID(label), GetValueFromNumber(number).release());
193 }
194
195 void AddBooleanToDict(DictionaryValue* dict,
196 SavePasswordProgressLogger::StringID label,
197 bool truth_value) {
198 dict->Set(GetStringFromID(label), GetValueFromBoolean(truth_value).release());
199 }
200
201 void AddElementIDToDict(DictionaryValue* dict,
202 SavePasswordProgressLogger::StringID label,
203 const std::string& element_id) {
204 dict->Set(GetStringFromID(label),
205 GetValueFromElementID(element_id).release());
206 }
207
208 void AddElementIDToDict(DictionaryValue* dict,
209 SavePasswordProgressLogger::StringID label,
210 const base::string16& element_id) {
211 dict->Set(GetStringFromID(label),
212 GetValueFromElementID(base::UTF16ToUTF8(element_id)).release());
57 } 213 }
58 214
59 } // namespace 215 } // namespace
60 216
61 SavePasswordProgressLogger::SavePasswordProgressLogger() {} 217 SavePasswordProgressLogger::SavePasswordProgressLogger() {
62 218 }
63 SavePasswordProgressLogger::~SavePasswordProgressLogger() {} 219
64 220 SavePasswordProgressLogger::~SavePasswordProgressLogger() {
65 void SavePasswordProgressLogger::LogPasswordForm(const std::string& message, 221 }
66 const PasswordForm& form) { 222
223 void SavePasswordProgressLogger::LogPasswordForm(
224 SavePasswordProgressLogger::StringID label,
225 const PasswordForm& form) {
67 DictionaryValue log; 226 DictionaryValue log;
68 // Do not use the "<<" operator for PasswordForms, because it also prints 227 AddMessageToDict(
69 // passwords. Also, that operator is only for testing. 228 &log, STRING_SCHEME_MESSAGE, FormSchemeToStringID(form.scheme));
Ilya Sherman 2014/04/17 21:12:05 Comparing AddMessageToDict( &log, STRING_SCHE
vabr (Chromium) 2014/04/19 07:39:53 It was, in fact, very convincing. Happy to remove
70 log.SetString("scheme", FormSchemeToString(form.scheme)); 229 AddMessageToDict(
71 log.SetString("signon realm", ScrubURL(GURL(form.signon_realm))); 230 &log, STRING_SCHEME_MESSAGE, FormSchemeToStringID(form.scheme));
72 log.SetString("original signon realm", 231 AddURLToDict(&log, STRING_SIGNON_REALM, GURL(form.signon_realm));
73 ScrubURL(GURL(form.original_signon_realm))); 232 AddURLToDict(
74 log.SetString("origin", ScrubURL(form.origin)); 233 &log, STRING_ORIGINAL_SIGNON_REALM, GURL(form.original_signon_realm));
75 log.SetString("action", ScrubURL(form.action)); 234 AddURLToDict(&log, STRING_ORIGIN, form.origin);
76 log.SetString("username element", form.username_element); 235 AddURLToDict(&log, STRING_ACTION, form.action);
77 log.SetString("password element", form.password_element); 236 AddElementIDToDict(&log, STRING_USERNAME_ELEMENT, form.username_element);
78 log.SetBoolean("password autocomplete set", form.password_autocomplete_set); 237 AddElementIDToDict(&log, STRING_PASSWORD_ELEMENT, form.password_element);
79 log.SetString("old password element", form.old_password_element); 238 AddBooleanToDict(
80 log.SetBoolean("ssl valid", form.ssl_valid); 239 &log, STRING_PASSWORD_AUTOCOMPLETE_SET, form.password_autocomplete_set);
81 log.SetBoolean("password generated", 240 AddElementIDToDict(
82 form.type == PasswordForm::TYPE_GENERATED); 241 &log, STRING_OLD_PASSWORD_ELEMENT, form.old_password_element);
83 log.SetInteger("times used", form.times_used); 242 AddBooleanToDict(&log, STRING_SSL_VALID, form.ssl_valid);
84 log.SetBoolean("use additional authentication", 243 AddBooleanToDict(&log,
85 form.use_additional_authentication); 244 STRING_PASSWORD_GENERATED,
86 log.SetBoolean("is PSL match", form.IsPublicSuffixMatch()); 245 form.type == PasswordForm::TYPE_GENERATED);
87 LogValue(message, log); 246 AddNumberToDict(&log, STRING_TIMES_USED, form.times_used);
88 } 247 AddBooleanToDict(&log,
89 248 STRING_USE_ADDITIONAL_AUTHENTICATION,
90 void SavePasswordProgressLogger::LogHTMLForm(const std::string& message, 249 form.use_additional_authentication);
91 const std::string& name_or_id, 250 AddBooleanToDict(&log, STRING_PSL_MATCH, form.IsPublicSuffixMatch());
92 const std::string& method, 251 LogValue(label, &log);
93 const GURL& action) { 252 }
253
254 void SavePasswordProgressLogger::LogHTMLForm(
255 SavePasswordProgressLogger::StringID label,
256 const std::string& name_or_id,
257 const std::string& method,
258 const GURL& action) {
94 DictionaryValue log; 259 DictionaryValue log;
95 log.SetString("name_or_id", name_or_id); 260 AddElementIDToDict(&log, STRING_NAME_OR_ID, name_or_id);
96 log.SetString("method", method); 261 AddMessageToDict(&log, STRING_METHOD, FormMethodToStringID(method));
97 log.SetString("action", ScrubURL(action)); 262 AddURLToDict(&log, STRING_ACTION, action);
98 LogValue(message, log); 263 LogValue(label, &log);
99 } 264 }
100 265
101 void SavePasswordProgressLogger::LogURL(const std::string& message, 266 void SavePasswordProgressLogger::LogURL(
102 const GURL& url) { 267 SavePasswordProgressLogger::StringID label,
103 LogValue(message, StringValue(ScrubURL(url))); 268 const GURL& url) {
104 } 269 LogValue(label, GetValueFromURL(url).get());
105 270 }
106 void SavePasswordProgressLogger::LogBoolean(const std::string& message, 271
107 bool value) { 272 void SavePasswordProgressLogger::LogBoolean(
108 LogValue(message, FundamentalValue(value)); 273 SavePasswordProgressLogger::StringID label,
109 } 274 bool truth_value) {
110 275 LogValue(label, GetValueFromBoolean(truth_value).get());
111 void SavePasswordProgressLogger::LogNumber(const std::string& message, 276 }
112 int value) { 277
113 LogValue(message, FundamentalValue(value)); 278 void SavePasswordProgressLogger::LogNumber(
114 } 279 SavePasswordProgressLogger::StringID label,
115 280 int signed_number) {
116 void SavePasswordProgressLogger::LogNumber(const std::string& message, 281 LogValue(label, GetValueFromNumber(signed_number).get());
117 size_t value) { 282 }
118 LogValue(message, FundamentalValue(checked_cast<int, size_t>(value))); 283
119 } 284 void SavePasswordProgressLogger::LogNumber(
120 285 SavePasswordProgressLogger::StringID label,
121 void SavePasswordProgressLogger::LogFinalDecision(Decision decision) { 286 size_t unsigned_number) {
122 LogValue("Final decision taken", DecisionToStringValue(decision)); 287 LogValue(
123 } 288 label,
124 289 GetValueFromNumber(checked_cast<int, size_t>(unsigned_number)).get());
125 void SavePasswordProgressLogger::LogMessage(const std::string& message) { 290 }
126 LogValue("Message", StringValue(message)); 291
127 } 292 void SavePasswordProgressLogger::LogMessage(
128 293 SavePasswordProgressLogger::StringID message) {
129 void SavePasswordProgressLogger::LogValue(const std::string& name, 294 LogValue(STRING_MESSAGE, GetValueFromMessage(message).get());
130 const Value& log) { 295 }
296
297 void SavePasswordProgressLogger::LogValue(StringID label, const Value* log) {
131 std::string log_string; 298 std::string log_string;
132 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions( 299 bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions(
133 &log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string); 300 log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string);
134 DCHECK(conversion_to_string_successful); 301 DCHECK(conversion_to_string_successful);
135 SendLog(name + ": " + log_string); 302 SendLog(GetStringFromID(label) + ": " + log_string);
136 } 303 }
137 304
138 } // namespace autofill 305 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698