Realtime Database Güvenlik Kuralları dilinin temel söz dizimini öğrenin

Firebase Realtime Database güvenlik kuralları, veritabanınızda depolanan verilere erişimi kontrol etmenize olanak tanır. Esnek kural söz dizimi, veritabanınıza yapılan tüm yazma işlemlerinden tek tek düğümlerdeki işlemlere kadar her şeyle eşleşen kurallar oluşturmanıza olanak tanır.

Realtime Database Güvenlik Kuralları, veritabanınız için bildirim temelli yapılandırmadır. Yani kurallar, ürün mantığından ayrı olarak tanımlanır. Bu yaklaşımın çeşitli avantajları vardır: İstemciler güvenliği uygulamaktan sorumlu değildir, hatalı uygulamalar verilerinizin güvenliğini tehlikeye atmaz ve belki de en önemlisi, verileri dünyadan korumak için sunucu gibi bir aracıya gerek yoktur.

Bu konuda, eksiksiz kural kümeleri oluşturmak için kullanılan Realtime Database Security Rules'un temel söz dizimi ve yapısı açıklanmaktadır.

Güvenlik Kurallarınızı Yapılandırma

Realtime Database Güvenlik Kuralları, bir JSON belgesinde bulunan JavaScript benzeri ifadelerden oluşur. Kurallarınızın yapısı, veritabanınızda depoladığınız verilerin yapısına uygun olmalıdır.

Temel kurallar, güvenli hale getirilecek bir dizi düğümü, ilgili erişim yöntemlerini (ör. okuma, yazma) ve erişime izin verilen veya erişimin reddedildiği koşulları tanımlar. Aşağıdaki örneklerde koşullarımız basit true ve false ifadeleri olacak ancak bir sonraki konuda koşulları ifade etmenin daha dinamik yollarını ele alacağız.

Örneğin, bir parent_node altındaki child_node için güvenlik sağlamaya çalışıyorsak izlenecek genel söz dizimi şöyledir:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

Bu deseni uygulayalım. Örneğin, bir mesaj listesini takip ettiğinizi ve aşağıdaki gibi verilere sahip olduğunuzu varsayalım:

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

Kurallarınız benzer şekilde yapılandırılmalıdır. Bu veri yapısı için mantıklı olabilecek salt okunur güvenlik kuralları şunlardır: Bu örnekte, kuralların geçerli olduğu veritabanı düğümlerini ve bu düğümlerdeki kuralları değerlendirme koşullarını nasıl belirlediğimiz gösterilmektedir.

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

Temel Kural İşlemleri

Veriler üzerinde gerçekleştirilen işlem türüne göre güvenliği zorunlu kılan üç tür kural vardır: .write, .read ve .validate. Bu araçların amaçlarını kısaca özetleyelim:

Kural Türleri
.read Verilerin kullanıcılar tarafından okunmasına izin verilip verilmediğini ve ne zaman izin verildiğini açıklar.
.write Verilerin yazılmasına izin verilip verilmediğini ve ne zaman izin verildiğini açıklar.
.validate Doğru biçimlendirilmiş bir değerin nasıl görüneceğini, alt özellikleri olup olmadığını ve veri türünü tanımlar.

Joker Karakter Yakalama Değişkenleri

Tüm kural ifadeleri düğümlere işaret eder. Bir ifade, belirli bir düğümü işaret edebilir veya hiyerarşinin bir düzeyindeki düğüm kümelerini işaret etmek için $ joker karakter yakalama değişkenlerini kullanabilir. Düğüm anahtarlarının değerini sonraki kural ifadelerinde kullanmak üzere depolamak için bu yakalama değişkenlerini kullanın. Bu teknik, daha karmaşık Security Rules koşullar yazmanıza olanak tanır. Bu konuyu bir sonraki başlıkta daha ayrıntılı olarak ele alacağız.

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

Dinamik $ değişkenleri, sabit yol adlarıyla paralel olarak da kullanılabilir. Bu örnekte, widget öğesinin title ve color dışında alt öğesi olmamasını sağlayan bir .validate kuralı bildirmek için $other değişkenini kullanıyoruz. Ek alt öğelerin oluşturulmasına neden olacak tüm yazma işlemleri başarısız olur.

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

Okuma ve Yazma Kuralları Basamaklı Yapısı

.read ve .write kuralları yukarıdan aşağıya doğru çalışır. Daha yüzeysel kurallar, daha derin kuralları geçersiz kılar. Bir kural belirli bir yolda okuma veya yazma izinleri veriyorsa altındaki tüm alt düğümlere de erişim izni verir. Aşağıdaki yapıyı inceleyin:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

Bu güvenlik yapısı, /foo/ değeri true olan bir alt baz içerdiğinde /bar/ öğesinin okunmasına olanak tanır. Erişim bir alt yol tarafından iptal edilemediğinden /foo/bar/ altındaki ".read": false kuralının burada bir etkisi yoktur.

İlk bakışta sezgisel görünmese de bu, kural dilinin güçlü bir parçasıdır ve çok karmaşık erişim ayrıcalıklarının minimum çabayla uygulanmasına olanak tanır. Bu konuyu, kılavuzun ilerleyen bölümlerinde kullanıcı tabanlı güvenlikten bahsederken açıklayacağız.

.validate kurallarının basamaklı olmadığını unutmayın. Bir yazma işlemine izin verilmesi için hiyerarşinin tüm düzeylerinde tüm doğrulama kurallarının karşılanması gerekir.

Kurallar Filtre Değildir

Kurallar atomik bir şekilde uygulanır. Bu, ilgili konumda veya erişim izni veren bir üst konumda kural yoksa okuma ya da yazma işleminin hemen başarısız olacağı anlamına gelir. Etkilenen her alt yola erişilebiliyor olsa bile üst konumda okuma işlemi tamamen başarısız olur. Şu yapıyı göz önünde bulundurun:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Kuralların atomik olarak değerlendirildiğini anlamadan, /records/ yolunu getirmenin rec1 döndüreceği ancak rec2 döndürmeyeceği düşünülebilir. Ancak gerçek sonuç bir hatadır:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
Not: Bu Firebase ürünü, Uygulama Klibi hedefinde kullanılamaz.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
Not: Bu Firebase ürünü, Uygulama Klibi hedefinde kullanılamaz.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

/records/ konumundaki okuma işlemi atomik olduğundan ve /records/ altındaki tüm verilere erişim izni veren bir okuma kuralı olmadığından bu işlem PERMISSION_DENIED hatası verir. Bu kuralı Firebase konsolumuzdaki güvenlik simülatöründe değerlendirirsek okuma kuralı /records/ yoluna erişime izin vermediği için okuma işleminin reddedildiğini görebiliriz. Ancak rec1 kuralı, istediğimiz yolda olmadığı için hiçbir zaman değerlendirilmedi. rec1 sayfasını getirmek için sayfaya doğrudan erişmemiz gerekir:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
Not: Bu Firebase ürünü, Uygulama Klibi hedefinde kullanılamaz.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
Not: Bu Firebase ürünü, Uygulama Klibi hedefinde kullanılamaz.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Çakışan İfadeler

Bir düğüme birden fazla kural uygulanabilir. Birden fazla kural ifadesinin bir düğümü tanımladığı durumlarda, koşullardan herhangi biri false ise erişim yöntemi reddedilir:

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

Yukarıdaki örnekte, ilk kural her zaman true olsa bile ikinci kural her zaman false olduğundan message1 düğümüne okuma işlemleri reddedilir.

Sonraki adımlar

Firebase Realtime Database Güvenlik Kuralları hakkında daha fazla bilgi edinebilirsiniz:

  • Security Rules dilinin bir sonraki önemli kavramı olan dinamik koşulları öğrenin. Bu koşullar, Security Rules uygulamanızın kullanıcı yetkilendirmesini kontrol etmesine, mevcut ve gelen verileri karşılaştırmasına, gelen verileri doğrulamasına, istemciden gelen sorguların yapısını kontrol etmesine ve daha fazlasını yapmasına olanak tanır.

  • Tipik güvenlik kullanım alanlarını ve bunları ele alan Firebase Güvenlik Kuralları tanımlarını inceleyin.