Tencent / MMKV

An efficient, small mobile key-value storage framework developed by WeChat. Works on Android, iOS, macOS, Windows, and POSIX.
Other
17.1k stars 1.88k forks source link

Is there any option to disable data history, or manual clear history operation? #1335

Closed richardo2016x closed 2 weeks ago

richardo2016x commented 2 weeks ago

We're using MMKV's react-native bindings, in some cases, we put some password-encrypted data into MMKV.

The data could be RE-encrypted (e.g. user change the password of application) and put into MMKV, it's OK for usage. But for security, the history data still was left on the mmkv.default file, we think its potential vulnerability for our application.

So it there any option to disable the data history for specific/all mmkv data? Or any API to make sure some data history clear before we set it.

If not, do you think we can fork MMKV and do some simple modification to disable the data history feature?

Looking forward for your reply.

richardo2016x commented 2 weeks ago

I tested call mmkv.clearAll before every time mmkv.set, it seems worked.

I guess, This call clean up the history data?

    if (!keepSpace) {
        m_file->truncate(m_expectedCapacity);
    }

If it is, maybe call mmkv.trim also worked?

lingol commented 2 weeks ago

Whenever a user does a rekey() (RE-encrypted, or changes the encryption key), MMKV does a full write back which erases all history data in that file. https://github.com/Tencent/MMKV/blob/master/Core/MMKV_IO.cpp#L1339 Is there any misunderstanding?

richardo2016x commented 2 weeks ago

Whenever a user does a rekey() (RE-encrypted, or changes the encryption key), MMKV does a full write back which erases all history data in that file. https://github.com/Tencent/MMKV/blob/master/Core/MMKV_IO.cpp#L1339 Is there any misunderstanding?

Thx for your reply, the password-encrypted data in my previous comment is not encrypted by MMKV itself, but by application. We store data as plain format, that is, we initialize mmkv like this:

new MMKV() // no configuration provided

acccording to your reply, if fullWriteback() was executed(such as in ::trim()), all history data will be erased?

If so, I'll try to call ::trim() from react-native-mmkv which not expose the method (I can patch it by myself)

richardo2016x commented 2 weeks ago

I found in ::trim(), fullWriteback() is ONLY called on fileSize greater than m_expectedCapacity, here

My app is Android/iOS, we ignore iOS here because its data couldn't be access by others. For Android, the m_expectedCapacity was initialized here

#ifndef MMKV_ANDROID
MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity)
    : m_mmapID(mmapID)
    , m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
    , m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
    , m_dic(nullptr)
    , m_dicCrypt(nullptr)
    , m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
    , m_file(new MemoryFile(m_path, m_expectedCapacity))

That means, though I called ::trim(), the fullWriteback() is not always called. Maybe I need fork MMKV version which react-native-mmkv using, and add one method to make fullWriteback() called explicitly.

richardo2016x commented 2 weeks ago

After some trial and test, I think I just need to call those two methods in order:

  1. ::clearMemoryCache()
  2. ::trim()

Then all history data would be erased.

lingol commented 2 weeks ago

Though it might work, for now, there's no guarantee that the combination will also work in the future. I suggest using MMKV's encryption. It's cleaner.