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 bildirime dayalı yapılandırmadır. Bu, kuralların ürün mantığından ayrı olarak tanımlandığı anlamına gelir. Bu durumun çeşitli avantajları vardır: Müşteriler güvenliği zorunlu kılmaktan sorumlu değildir, hatalı uygulamalar verilerinizi tehlikeye atmaz ve belki de en önemlisi, verileri dünyadan korumak için sunucu gibi bir ara hakeme gerek yoktur.

Bu konuda, eksiksiz kural kümeleri oluşturmak için kullanılan Realtime Database Güvenlik Kuralları'nın 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şimin izin verildiği veya reddedildiği koşulları tanımlar. Aşağıdaki örneklerde koşullarımız basit true ve false ifadeleri olacaktır. Ancak bir sonraki konuda koşulları ifade etmenin daha dinamik yollarını ele alacağız.

Örneğin, parent_node altında bir child_node güvenliğini 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 ileti 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 anlamlı olabilecek salt okunur güvenlik kurallarını aşağıda bulabilirsiniz. Bu örnekte, kuralların uygulandığı veritabanı düğümlerinin ve bu düğümlerdeki kuralların değerlendirilme koşullarının nasıl belirtildiği 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şlemin türüne göre güvenliği zorunlu kılmak için üç tür kural vardır: .write, .read ve .validate. Bu kaynakların amaçlarının kısa bir özetini aşağıda bulabilirsiniz:

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

Joker Karakterle Yakalama Değişkenleri

Tüm kural ifadeleri düğümleri gösterir. Bir ifade, belirli bir düğümü işaret edebilir veya hiyerarşi 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 Rules koşullar yazmanıza olanak tanır. Bu konuyu bir sonraki bölümde 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, $other değişkenini kullanarak .validate ve color dışında alt öğesi olmayan widget öğesini sağlayan bir .validate kuralı tanımlıyoruz.title 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 }
    }
  }
}

Read and Write Rules Cascade

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

{
  "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ı, /bar/ öğesinin, /foo/ öğesi true değerine sahip bir baz alt öğesi içerdiğinde okunmasına olanak tanır. Erişim bir alt yol tarafından iptal edilemediğinden /foo/bar/ altındaki ".read": false kuralı burada geçerli değildir.

Bu özellik ilk bakışta sezgisel görünmese de kurallar 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 durum, kılavuzun ilerleyen bölümlerinde kullanıcı tabanlı güvenlik konusunu ele aldığımızda açıklanacaktır.

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

Kurallar Filtre Değildir

Kurallar atomik olarak uygulanır. Bu, söz konusu konumda veya erişim izni veren bir üst konumda kural yoksa okuma veya yazma işleminin hemen başarısız olacağı anlamına gelir. Etkilenen tüm alt yollar erişilebilir 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/ yolunun getirilmesinin 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ü, App Clip 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ü, App Clip 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 işlemine, /records/ yoluna erişime izin veren bir okuma kuralı olmadığı için izin verilmediğini görebiliriz. Ancak rec1 için kuralın, istediğimiz yolda olmadığı için hiçbir zaman değerlendirilmediğini unutmayın. rec1 öğesini getirmek için 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ü, App Clip hedefinde kullanılamaz.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
Not: Bu Firebase ürünü, App Clip 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 ifadeler

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 da ikinci kural her zaman false olduğundan message1 düğümüne yapılan okuma işlemleri reddedilir.

Sonraki adımlar

Firebase Realtime Database güvenlik kuralları hakkındaki bilginizi derinleştirebilirsiniz:

  • Rules dilinin bir sonraki önemli kavramı olan dinamik koşullar hakkında bilgi edinin. Bu koşullar, Rules dilinin 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ına olanak tanır.

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