14

似乎钥匙串文件(带有扩展名.keychain)通常会有一个与之关联的不可见文件,位于同一目录中。

此不可见文件始终具有以下属性:

  • 它是空的(零字节)。
  • 它的权限是0444(对所有用户只读)。
  • 它的名称由.fl后跟 8 个十六进制字符组成。例如:

    .fl043D1EDD
    .fl947E1BDB
    .fl9FAF0136
    .fl12663120
    .fl8E6EFC6C
    .flCF600F4B
    .fl1D8ECE61
    .fl0D1D1BA9
    .fl79E88CD1
    .fl62323D2F
    .fl75262C83
    .fl652F188E
    

不可见文件可以删除,但是下次修改钥匙串的内容时,将重新创建具有相同名称的不可见文件。

以下是使用钥匙串访问实用程序演示的一些步骤:

  1. 通过选择File > New Keychain并选择要在其中创建它的目录来创建一个新的钥匙串。将在与新钥匙串相同的目录中创建一个不可见文件。
  2. 删除不可见文件(使用 Finder 或终端)。
  3. 修改钥匙串的内容。例如,通过选择File > New Secure Note Item向钥匙串添加一个安全注释。将使用相同的名称重新创建不可见文件。
  4. 通过选择File > Delete Keychain > Delete References & Files 删除钥匙串。不可见的文件也将被删除。

我已经验证这发生在 OS X 10.810.9中。


更新

security在终端中使用 Apple 的工具操作钥匙串时会创建相同的不可见文件:

  1. 创建一个新的钥匙串。还会创建一个不可见的文件。

    $ cd ~/Desktop/
    $ ls -1a
    .
    ..
    $ /usr/bin/security create-keychain ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    .fl1BCE4B9A
    Test.keychain
    
  2. 删除不可见的文件。

    $ rm .fl1BCE4B9A
    $ ls -1a
    .
    ..
    Test.keychain
    
  3. 修改钥匙串的内容(例如:通过添加互联网密码)。以相同的名称重新创建不可见文件。

    $ /usr/bin/security add-internet-password -a account -s google.com -w password ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    .fl1BCE4B9A
    Test.keychain
    
  4. 删除钥匙串。不可见的文件也被删除。

    $ /usr/bin/security delete-keychain ~/Desktop/Test.keychain
    $ ls -1a
    .
    ..
    

问题

  1. 为什么会创建这些不可见的文件?他们的目的是什么?
  2. 文件名中的含义是什么fl
  3. 文件名中的 8 个十六进制字符是什么?某种标识钥匙串的唯一 ID 或哈希?
  4. 有没有办法防止在创建或修改钥匙串时创建这些文件?
4

1 回答 1

13

经过大量调查,我已经设法回答了我的大部分问题:

  1. 隐形文件为钥匙串的数据库实现了写锁
  2. .flAtomicFile是安全框架中的类创建的锁定文件的文件名前缀。
  3. 文件名中的 8 个十六进制字符是钥匙串文件名的 SHA-1 哈希的开头。例如,如果调用了钥匙串文件Test.keychain,则其文件名的 SHA-1 哈希以 开头,1BCE4B9A...因此将调用锁定文件.fl1BCE4B9A
  4. 我还没有找到一种方法来防止在创建或修改钥匙串时创建锁定文件。我认为这可能是不可能的,但如果有人能找到一种方法,我会非常感兴趣

以下是我的调查细节:

钥匙串的锁定/解锁状态

我注意到隐形文件不受钥匙串的锁定/解锁状态的影响。如果不可见文件已被删除,则锁定/解锁钥匙串不会重新创建不可见文件。

系统调用

我在 Apple 的Instruments工具中使用 File Activity 模板进行了一些调查。

这些系统调用负责操作不可见文件:

  • 创建新钥匙串时创建不可见文件:
    • Security::AtomicFile::create(unsigned short)
    • Security::RefPointer<Security::AtomicLockedFile>::release_internal()
    • 调用树的相关部分
  • 修改钥匙串的内容时重新创建不可见文件:
    • Security::AtomicFile::write()
    • Security::RefPointer<Security::AtomicLockedFile>::release_internal()
    • 调用树的相关部分
  • 删除钥匙串时删除不可见文件:

C++ 文件

这些是相关的文件和类(源代码可从Apple Open Source for OS X 10.9.2获得):

  • AtomicFile.cpp
    • Security::AtomicFile
    • Security::AtomicLockedFile
    • Security::AtomicTempFile
    • Security::LocalFileLocker
  • AppleDatabase.cpp
    • Security::AppleDatabase
    • Security::DbModifier

源代码中的注释

这些文件中的注释提供了一些线索:

  • AtomicFile::AtomicFile()
    • “计算此文件的锁定文件的名称”
  • AtomicFile::create()
    • “锁定文件以进行写入并返回新创建的 AtomicTempFile。”
    • “现在我们已经创建了锁,并且新的 db 文件创建了一个 tempfile 对象。”
  • LocalFileLocker::lock()
    • “如果锁定文件不存在,则创建它”
    • “尝试获得对文件的独占访问权”
    • “检查并查看我们有权访问的文件是否仍然存在。如果不存在,则另一个文件由于哈希冲突而共享了我们的文件锁并丢弃了我们的锁 - 或者用户自己炸毁了锁文件。”
  • DbModifier::modifyDatabase()
    • “现在我们持有写锁”
  • AtomicFile::write()
    • “锁定数据库文件以进行写入并返回一个新创建的 AtomicTempFile。”
  • AtomicFile::performDelete()
    • “获取写锁并删除文件。”
    • “取消链接我们的锁定文件”

生成锁定文件的名称

我在构造函数中找到了这段代码AtomicFile

char buffer[256];
sprintf(buffer, "%08X", hash);
mLockFilePath = mDir + ".fl" + buffer;

其中是钥匙串文件名的SHA-1哈希的hash前 4 个字节。

注意:仅使用 4 个字节(32 位)的散列,有合理的机会发生散列冲突,这在LocalFileLocker::lock().

锁的操作

系统flock()调用用于操作锁文件上的锁。

这是钥匙串的数据库被锁定以进行写入时的调用树:

DbModifier::createDatabase() or ::modifyDatabase() or ::deleteDatabase()
  AtomicFile::create() or ::write() or ::performDelete()
    AtomicLockedFile::lock()
      LocalFileLocker::lock()
        flock(mLockFile, LOCK_EX)  // exclusive lock

以及写入后解锁时:

DbModifier::commit()
  AtomicTempFile::commit()
    RefPointer<AtomicLockedFile>::setPointer(AtomicLockedFile*)
      RefPointer<AtomicLockedFile>::release_internal()
        AtomicLockedFile::~AtomicLockedFile()  // destructor
          AtomicLockedFile::unlock()
            LocalFileLocker::unlock()
              flock(mLockFile, LOCK_UN)  // unlock
于 2014-06-28T20:25:52.427 回答