【转】Google Chrome如何保存密码口令

每个已发布的浏览器都有一些保存密码口令的管理系统,对于Google的。我筛选了Chrome的源代码,了解了Chrome是如。如果增加一个新的密码口令或更新修改已存在的密码,DCHECK_EQ和。当然,密码是不会储存在纯文本中,

每个已发布的浏览器都有一些保存密码口令的管理系统,对于Google的Chrome浏览器来说也不例外。我筛选了Chrome的源代码,了解了Chrome是如何保存口令的。这里,我将讲解下Google的Chrome浏览器是如何快速安全保存你的密码的。

在点击密码保存时,首先会出现下面的对话框


在Chrome里,上面的对话框称为密码管理器。当你点击Savepassword时会出现什么情形呢?


当点击保存按钮时,调用如下函数。
void PasswordManager::SavePasswordBar::OKButtonPressed() {
  form_manager_->Save();
  BeginClose();
}

form_manager是另外一个对象,下面代码才真正实现了保存功能。
void PasswordFormManager::Save() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(!profile_->IsOffTheRecord());

  if (IsNewLogin())
    SaveAsNewLogin();
  else
    UpdateLogin();
}


如果增加一个新的密码口令或更新修改已存在的密码,DCHECK_EQ和DCHECK两个对象会对此进行检查。让我们来看一下增加新密码的代码。

void PasswordFormManager::SaveAsNewLogin() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(IsNewLogin());
  // The new_form is being used to sign in, so it is preferred.
  DCHECK(pending_credentials_.preferred);
  // new_form contains the same basic data as observed_form_ 

(because its the
  // same form), but with the newly added credentials.

  DCHECK(!profile_->IsOffTheRecord());

  WebDataService* web_data_service =
      profile_->GetWebDataService(Profile::IMPLICIT_ACCESS);
  if (!web_data_service) {
    NOTREACHED();
    return;
  }
  pending_credentials_.date_created = Time::Now();
  web_data_service->AddLogin(pending_credentials_);
}

大部分的函数是可调试代码。我们关心的是调用的AddLogin函数。WebDataService对象负责将meta数据和web网页进行关联。

void WebDataService::AddLogin(const PasswordForm& form) {
  GenericRequest<PasswordForm>* request =
      new GenericRequest<PasswordForm>
        (this, GetNextRequestHandle(), NULL, form);
  RegisterRequest(request);
  ScheduleTask(NewRunnableMethod
    (this, &WebDataService::AddLoginImpl, request));
}


到这里有一点点复杂了。新增一个密码,是通过异步和处理调度函数实现。它似乎是非常重要的,没有干扰Chrome的用户界面--仍然保持着快速反应。当执行代码时,让我们考虑一下会发生什么事。

void WebDataService::AddLoginImpl(
  GenericRequest<PasswordForm>* request) {
  if (db_ && !request->IsCancelled()) {
    if (db_->AddLogin(request->GetArgument()))
      ScheduleCommit();
  }
  request->RequestComplete();
}


AddLogin在这里是很重要的,所以让我们继续研究它。
bool WebDatabase::AddLogin(const PasswordForm& form) {
  SQLStatement s;
  std::string encrypted_password;
  if (s.prepare(db_,
    "INSERT OR REPLACE INTO logins "
    "(origin_url, action_url, username_element, username_value, "
    " password_element, password_value, submit_element, "
    " signon_realm, ssl_valid, preferred, date_created, "
    " blacklisted_by_user, scheme) "
    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") != 

SQLITE_OK) {
    NOTREACHED() <<"Statement prepare failed";
    return false;
  }

  s.bind_string(0, form.origin.spec());
  s.bind_string(1, form.action.spec());
  s.bind_wstring(2, form.username_element);
  s.bind_wstring(3, form.username_value);
  s.bind_wstring(4, form.password_element);
  Encryptor::EncryptWideString(form.password_value, 

&encrypted_password);
  s.bind_blob(5, encrypted_password.data(),  static_cast<int>(encrypted_password.length()));
  s.bind_wstring(6, form.submit_element);
  s.bind_string(7, form.signon_realm);
  s.bind_int(8, form.ssl_valid);
  s.bind_int(9, form.preferred);
  s.bind_int64(10, form.date_created.ToTimeT());
  s.bind_int(11, form.blacklisted_by_user);
  s.bind_int(12, form.scheme);
  if (s.step() != SQLITE_DONE) {
    NOTREACHED();
    return false;
  }
  return true;
}
    

终于完成了。这个功能其实是在Chrome的SQLite数据库中,通过建立SQL语句来添加一个新的密码。当然,密码是不会储存在纯文本中,因为Chrome有一个encryptor对象,负责加密密码口令。让我们来看一下。

bool Encryptor::EncryptString(const std::string& plaintext,  std::string* ciphertext)
 {
  DATA_BLOB input;
  input.pbData = const_cast<BYTE*>(   reinterpret_cast<const BYTE*>(plaintext.data()));
  input.cbData = static_cast<DWORD>(plaintext.length());

  DATA_BLOB output;
  BOOL result = CryptProtectData(&input, L"", NULL, NULL, NULL,  0, &output);
  if (!result)
    return false;

  // this does a copy
  ciphertext->assign(reinterpret_cast<std::string::value_type*>
    (output.pbData), output.cbData);

  LocalFree(output.pbData);
  return true;
}


重要的一块是CryptProtectData,它是一个Windows API加密函数。使用它加密后数据是相当坚固的。

通过了解,我们学习了Chrome的密码口令管理系统。Google使用SQLite作为密码和其他网页相关数据的存储机制。唯一的Windows特定代码来实现加密的功能,它可以很容易被移植,为每个操作系统创造不同的encryptor对象。

 
原文地址:https://www.cnblogs.com/rainduck/p/2281050.html