jloosli / node-firestore-import-export

Firestore data import and export
https://www.npmjs.com/package/node-firestore-import-export
MIT License
392 stars 79 forks source link

Special FieldValues not properly checked - major security risk #673

Open Joebayld opened 3 years ago

Joebayld commented 3 years ago

I'm trying to run an export but the timestamp special datatype doesn't seem to be working.. I'm testing in the Emulator and Production. When performing the export, the data looks like the following:

{
  "5Ie1pOL8": {
    "updated_at": {
      "_seconds": 1613879304,
      "_nanoseconds": 172000000
    },
    "__collections__": {}
  }
}

It's just exporting the raw Firebase timestamp and not the formatted special type.

Any ideas?

Joebayld commented 3 years ago

Just an update -

Did some digging and it found the issue resides in the serializeSpecialTypes function. Seems like when checking if the data is an instanceOf a FieldValue, all those checks fail as the instanceOf fail. Why? I think because it's checking it's own instance of firebase-admin and not the library in your project. It shouldn't even install firebase-admin as a dependency if the project is also using it..

This can end up EXTREMELY DANGEROUS. I did some digging and when you are exporting a FieldValue of type DocumentReference it exports the entire firebase ref as JSON. Included in that firebase ref is the service account private keys!

This is extremely dangerous - there must be some checks to make sure this can't happen. Here's a screenshot of the JSON I got back.

Screen Shot 2021-02-21 at 4 26 16 AM

Possible Fix

Something I did and seemed to fix it is instead of these calls:

if (rawValue instanceof admin.firestore.Timestamp)
if (rawValue instanceof admin.firestore.GeoPoint)
if (rawValue instanceof admin.firestore.DocumentReference)

We could check the constructor - which wouldn't rely on using the exact same library, but rather any admin library as long as the types are the same name.

if (rawValue.constructor.name === 'Timestamp')
if (rawValue.constructor.name === 'GeoPoint')
if (rawValue.constructor.name === 'DocumentReference')