A B O U T M Y S E L F ࣗݾհ Tomokazu Kozuma @Tomokazu106 ౦ژۀେֶେֶӃଔۀޙɺαΠόʔΤʔδΣϯτͰεϚϗήʔϜͷαʔόɺΠϯ ϑϥશൠΛ୲ɻԾ௨՟ʹ͍ٕͭͯज़ϒϩάΛॻ͍ͯΔ͏ͪʹ಄͠ɺຊ৬ͱ ͯ͠ྗ͢ΔͨΊʹ(JODPʹೖࣾɻ(JODPͰϒϩοΫνΣʔϯͷϊʔυӡ༻ɺϋʔ υϑΥʔΫରԠɺόοΫΤϯυͳͲൣғΛ୲ɻ
S e c u r i t y P r o b l e m ԯ݅ͷػີใ͕ެ։͞Ε͍ͯΔ • 'JSFCBTF%BUBCBTFΛ͍ͬͯΔͷ͕࿙Ӯ • ݪҼSVMFTΛ͖ͪΜͱઃఆͰ͖͍ͯͳ͍ h t t p s : / / w w w . a p p t h o r i t y . c o m / c o m p a n y / p r e s s / p r e s s - r e l e a s e s / 6 2 - o f - e n t e r p r i s e s - e x p o s e d - t o - s e n s i t i v e - d a t a - l o s s - v i a - f i r e b a s e - v u l n e r a b i l i t y
• SFBE୯ҰEPDΛऔಘ͢ΔHFUͱෳऔಘ͢ΔMJTU • XSJUFDSFBUF
VQEBUF
EFMFUF SFBEXSJUFݖݶ R e a d R e s t r i c t i o n match /Users/{uid} { allow get: if someCondition(); allow create: if someCondition(); } function someCondition() { … }
• ϦΫΤετσʔλɿSFRVFTUSFTPVSDFEBUB • 'JSFTUPSFσʔλɿSFTPVSDFEBUB • ܕɿJOU
TUSJOH
CPPM
UJNFTUBNQͳͲ • LFZɿIBT"MM
IBT0OMZ
IBT"OZ σʔλͷόϦσʔγϣϯ D a t a V a l i d a t i o n match /Users/{uid} { allow update: if request.resource.data.keys().hasAll(["name", "age"]) && request.resource.data.name is string && request.resource.data.name != "" && request.resource.data.age == resource.data.age }
• ผ֊ʹͯ͠SVMFTઃఆΛݫ͘͢͠Δ ػີσʔλผ֊ D i v i d e S e c r e t D a t a match /Users/{uid} { // ೝূࡁϢʔβʹެ։ allow read: if isAuthUser(); // ࣗͷσʔλ͚ͩʹΞΫηεՄ match /Private/Info { allow read: if isMyData(uid); } } function isMyData(uid) { return request.auth.uid == uid; }
ϫΠϧυΧʔυͰͷSVMFTઃఆ • ϫΠϧυΧʔυͰෳSVMF͕ద༻͞ΕͯڐՄ͞ΕΔ U s i n g w i l d c a r d match /Users/{uid} { // ݅1 match /{allChildren=**} { allow read: if isAuthUser(); } // ݅2 match /Private/Info { allow read: if isMyData(uid); } } function isMyData(uid) { return request.auth.uid == uid; }
SVMFTͷςετํ๏ • 'JSFCBTF4%,ʹ$MJFOU4%,ͱ"ENJO4%,͕͋Δ • $MJFOU4%,͚ͩSVMFT͕ద༻͞ΕΔ • +BWB4DSJQU͚ͩͭͷ4%,͕͋Δ H o w t o t e s t Firestore Cloud $MJFOU4%, "ENJO4%, 3VMFT
• UFTUͷͨΊͷ'JSFCBTFϓϩδΣΫτΛ࡞ • 'JSFCBTF"VUIFOUJDBUJPOͰಗ໊ೝূΛ༗ޮԽ • ωοτϫʔΫӽ͠ͳͷͰ͕͔͔࣌ؒΔ • SVMFTͱςετσʔλͷڝ߹ ςετ1SPKFDUΛͬͨํ๏ T e s t u s i n g p r o j e c t Firestore Cloud
'JSFCBTF-PDBM&NVMBUPS • ςετʹ!pSFCBTFUFTUJOHϞδϡʔϧΛ༻ • ೝূະೝূΞΧϯτɺ"ENJOΞΧϯτΛ؆୯ʹར ༻Ͱ͖Δ • ςετσʔλͷڝ߹͠ͳ͍͠ɺUSVODBUF͠ͳ͍͍ͯ͘ • ςετ࣮ߦ͕࣌ؒʹݮ L o c a l E m u l a t o r
L o a d r u l e s SVMFTͷϩʔυ import * as firebase from ‘@firebase/testing’ // rulesͷϩʔυ firebase.loadFirestoreRules({ projectId: 'test-project-00', rules: fs.readFileSync("firestore.rules", "utf8") }) • SVMFTͷϩʔυҙͷQSPKFDU*EͰͰ͖Δ • QSPKFDU*EผʹݸผͷσʔλۭؒΛ࣋ͯΔ • ςετຖʹQSPKFDU*EΛมߋ͢Ε·ͬ͞Βͳঢ়ଶ
• ෳͷೝূΞΧϯτΛಉ࣌ʹѻ͑Δ L o a d r u l e s ΞΧϯτ࡞ // ೝূࡁΞΧϯτ const firestore = firebase .initializeTestApp({ projectId: ‘test-project-00', auth: {uid: ‘test-account’} }) .firestore(); // AdminΞΧϯτ const adminFirestore = firebase .initializeAdminApp({ projectId: 'test-project-00', auth: ‘admin-account’ }) .firestore();