zoukankan      html  css  js  c++  java
  • 【转】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对象。

     
  • 相关阅读:
    设计模式
    常用数据结构及复杂度 array、LinkedList、List、Stack、Queue、Dictionary、SortedDictionary、HashSet、SortedSet
    在 ASP.NET MVC 项目中使用 WebForm、 HTML
    二分法 数据必须是排序好的
    location.href IE6 下不起作用的罪魁祸首
    leetcode 372. Super Pow
    turple list dict 互相转换
    Pandas之Dropna滤除缺失数据
    模型选择---KFold,StratifiedKFold k折交叉切分
    xgb, lgb, Keras, LR(二分类、多分类代码)
  • 原文地址:https://www.cnblogs.com/rainduck/p/2281050.html
Copyright © 2011-2022 走看看