Günümüz web uygulamalarında güvenlik, her zamankinden daha önemli bir unsur haline geldi. Kullanıcıların yetkilendirilmesi ve kimlik doğrulama işlemleri, bir web uygulamasının temel taşlarından biridir. Node.js gibi popüler bir platformda, bu ihtiyaçları karşılamak için middleware’ları kullanmak oldukça etkili ve verimli bir yol sağlar. Bu makalede, Node.js ile middleware’ları kullanarak authorization yönetimini ele alacağız.
Authorization Nedir ve Neden Önemlidir?
Authorization, yetkilendirme anlamına gelmektedir. Uygulamaya giriş yapan kullanıcının hangi haklara sahip olduğu, hangi sayfalara erişebileceği ve hangi işlemleri kullanabileceğini belirler. Her uygulama kendine has özellikler bulundurmaktadır. Bunların belirli kısmına yalnızca admin kullanıcısı erişim sağlayabilirken bazılarına moderatörler erişim sağlacak olabilir. Ayrıca normal üyeler ve premium üyelerin bulunduğu bir sistem yapınız olabilir. Bu yapıda doğal olarak normal üyelerin belirli kısıtlamaları olmalı, premium üyelerin kullanmış oldukları belirli yapılara/fonksiyonlara erişim yetkileri olmaması gereklidir.
Authorization ile Authentication Arasındaki Farklar
Authentication, kimlik doğrulama anlamına gelmektedir. Kullanıcının bilgilerinin sahte olup olmadığıyla ilgilenir. Giriş ekranlarında kullanılan email-şifre / k.adı-şifre/ telefon numarası doğrulama gibi durumlar kimlik doğrulaması uygun örneklerdir. Kredi kartı ödemelerinde kullanılan kart bilgilerinin girilmesi bir doğrulama işlemidir, daha sonrasında kullanılan telefon ile sms onayı da yine bir doğrulama işlemidir. Authorization yani ‘yetkilendirme’ ise daha çok yapılan işlemin o kullanıcının yapıp yapamacağıyla alakalıdır. Örneğin e-ticaret sitelerinde kullanıcının indirimli satın alım yapıp yapamayacağı, farklı üyelerin bilgilerini düzenleyip düzenleyemeyeceği, hangi süreçlere erişip erişemeyeceği yetkilendirmeyle alakalıdır.
Middleware Nedir?
Middleware, yazılım uygulamalarında belirli bir işlevi yerine getiren ara katman yazılımlardır. Node.js’de middleware, bir istek ve yanıt döngüsünde belirli bir noktada çalıştırılan ve bu isteklerin işlenmesi sürecinde kullanılabilen işlevlerdir. Middleware’lar, genellikle birden çok işlevi zincir halinde kullanarak modüler ve yönetilebilir bir uygulama yapısı oluşturmak için kullanılır.
Node.js’de Middleware Kullanımı
Express.js, Node.js uygulamalarında sıkça kullanılan minimal ve esnek bir web uygulama çatısıdır. Express.js ile middleware’ları kolayca kullanabilir ve uygulamanızda modüler bir yapı oluşturabilirsiniz.
const express = require('express');
const app = express();
const myMiddleware = (req, res, next) => {
console.log('Middleware çalıştı!');
next();
};
app.use(myMiddleware);
app.get('/', (req, res) => {
res.send('Merhaba Dünya!');
});
app.listen(3000, () => {
console.log('Sunucu çalışıyor!');
});
Yukarıdaki örnekte, myMiddleware adlı bir middleware tanımlanmış ve bu middleware tüm isteklere uygulanmıştır. next() işlevi, middleware’ın işini tamamladıktan sonra bir sonraki middleware’a geçiş yapmasını sağlar.
JWT ile Token Tabanlı Yetkilendirme
JWT (JSON Web Token), web uygulamalarında kimlik doğrulama ve yetkilendirme için yaygın olarak kullanılan bir tekniktir. JWT, istemci ve sunucu arasında güvenli bir şekilde veri alışverişi yapmak için kullanılır.
Roller ve Mesajlar
// Define error messages as constants
const ERROR_MESSAGES = {
NO_INPUT_TOKEN: "Unauthorized, there is no input token!",
UNMATCHED_TOKEN: "Unauthorized, not matched token!",
UNAUTHORIZED_LOGGED: "Unauthorized, you are not logged user.",
UNAUTHORIZED_USER: "Unauthorized, you are not authorized.",
USER_ID_NOT_FOUND: "User id not found in token.",
// Add more error messages as needed
};
// Export the error messages
module.exports = ERROR_MESSAGES;
const roles = {
CONTRIBUTOR: "contributor",
ADMINISTRATOR: "administrator",
SUBSCRIBER: "subscriber",
};
module.exports = roles;
Yetkilendirme Middleware’ları
Bu bölümde, genel kullanıcı yetkilendirme için bir middleware örneği inceleyeceğiz.
const jwt = require("jsonwebtoken");
const ERROR_MESSAGES = require("../constants/messages");
const authMiddleware = (req, res, next) => {
const authorizationHeader = req.header("Authorization");
const userId = req.header("userId");
if (!authorizationHeader || !userId) {
return res.status(401).json({ msg: ERROR_MESSAGES.NO_INPUT_TOKEN });
}
const token = authorizationHeader.replace("Bearer ", "");
jwt.verify(token, process.env.JWT_AUTH_SECRET_KEY, (err, decoded) => {
if (err) {
return res.status(401).json({ msg: ERROR_MESSAGES.UNMATCHED_TOKEN });
}
if (decoded.data.user.id === userId) {
req.token = token;
next();
} else {
return res.status(401).json({ msg: ERROR_MESSAGES.UNAUTHORIZED_LOGGED });
}
});
};
module.exports = authMiddleware;
Bu middleware, kullanıcının kimliğini doğrulamak ve isteklerin yetkilendirilmesini sağlamak için JWT kullanır. Kullanıcının userId’si ve Bearer Token’ı alınır. Bu token environment dosyamızda tuttuğumuz secret keyimiz ile karşılaştırılarak doğrulanır. Eğer doğrulama başarılıysa decode edilmiş veri üzerinde tuttuğumuz id ile kullanıcının ilk başta header’da vermiş olduğu userId ile karşılaştırılır. Böylece kullanıcının kimliği doğrulanmış olur.
Admin Yetkilendirme Middleware’ı
Bu bölümde, admin yetkilendirme için bir middleware örneği inceleyeceğiz.
const jwt = require("jsonwebtoken");
const ERROR_MESSAGES = require("../constants/messages");
const ROLES = require("../constants/roles");
const adminAuth = (req, res, next) => {
const authorizationHeader = req.header("Authorization");
if (!authorizationHeader) {
return res.status(401).json({ msg: ERROR_MESSAGES.NO_INPUT_TOKEN });
}
const token = authorizationHeader.replace("Bearer ", "");
if (token) {
jwt.verify(token, process.env.JWT_AUTH_SECRET_KEY, (err, decoded) => {
if (err) {
res.status(401).json({ msg: ERROR_MESSAGES.UNMATCHED_TOKEN });
} else {
const roles = JSON.parse(decoded.data.user.roles);
if (roles.includes(ROLES.ADMINISTRATOR)) {
next();
} else {
res.status(401).json({ msg: ERROR_MESSAGES.UNAUTHORIZED_USER });
}
}
});
} else {
res.status(401).json({ msg: ERROR_MESSAGES.NO_INPUT_TOKEN });
}
};
module.exports = adminAuth;
Buradaki kodda ise kullanıcının admin rolüne sahip olup olmadığını kontrol ediyoruz. Bunun amacı yazdığımız API endpoint’ine sadece admin kullanıcılarının erişmesini sağlamaktır. Bu fonksiyon genişletilerek dinamik bir biçime getirilebilir örneğin parametre olarak rol alan bir fonksiyona çevirebiliriz. Böylece gelen parametredeki rolün varlığını kontrol edebiliriz. Bu yazıda daha basit anlamda yetkilendirme kontrolü yaptığımızdan ötürü amacın anlaşılmasına yönelik bir fonksiyon tercih edilmiştir.
API Endpoint’i Üzerinde Middleware Kullanma Senaryosu
const userEtkinlikTableName = "UserEvent";
// @desc Tum kullanıcı etkinliklerini getir
// @route /api/v1/user-event
// @access PUBLIC
router.get("/user-event", adminAuth, async (req, res) => {
try {
var sqlQuery = `SELECT UserId,EventId,EventName FROM ${userEventsTableName}`;
db.query(sqlQuery, (err, data) => {
if (err) throw err;
res.status(200).json(data);
});
} catch (error) {
res.status(500).json(error);
}
});
Yukarıdaki get isteği tabloya kayıtlı bütün kullanıcı etkinliklerini getirmeye sağlayan bir endpoint. Bu endpointe sadece admin kullanıcılarının erişmesini istediğimiz için kullandığımız router.get() methoduna 2. parametre olarak adminAuth middleware’ını geçtik. Böylece bu endpointe erişmeden önce gelen isteğin admin kullanıcısından olup olmadığını teyit ediyoruz. Bunu yaparken yukarıdaki middleware’de olduğu gibi jwt token doğrulaması kullanıyoruz.
Gerçek Dünya Uygulamaları ve En İyi Pratikler
Bankacılık Sistemleri: Bankacılık sistemlerinde para aktarımı kritik öneme sahiptir. Kullanıcıların hangi yetkilere sahip olduğu ve hangi işlemleri gerçekleştirebileceğinin belirlenmesi ve sistemin buna göre kurgulanmış olması gerekmektedir. Örneğin giriş yapmış bir kullanıcı yalnızca kendi hesaplarının bakiyelerini görebilmesi gerekmektedir. Kendi üyelik tipinin sahip olduğu erişim haklarına sahip olmalıdır.
Sosyal Medya Platformları: Sosyal medya uygulamalarında kullanıcı yalnızca sahip olduğu gönderileri düzenleyebilme yetkisine sahip olmalı, başka bir hesabı düzenlemek için erişim yetkisine sahip olmamalıdır. Sadece kendi hesabıyla gönderilere yorum yapabilmeli, başkası adına yorum gönderme yetkisine sahip olmamalıdır.
Sağlık Sistemleri: Sağlık sisteminde, hastaların kayıtlarına yalnızca doktorlar ve yetkili kişiler erişim sağlayabilmelidir. Standart bir kullanıcının bu dosyalara erişim yetkisi olmamalıdır.
Güvenlik Açıkları ve Bunları Önleme Yöntemleri
Aşırı Yetkilendirme (Over-authorization): Kullanıcıya aşırı yetki vererek normalde erişim sağlayamayacağı yerlere erişim yetkisi vermek demektir. Önlemek için erişime açık olan API’lerin hangi role sahip kullanıcıların kullanabileceği listeleme yöntemiyle çıkartılabilir. Buna uygun olarak dökümantasyon çıkartılarak uygun yönetim sağlanabilir.
Zayıf Oturum Yönetimi: Oturum yönetimi işlemlerinin yetersiz olması, yetkilendirme güvenliğini tehlikeye atabilir. Örneğin, oturumların süresiz açık kalması veya oturumun doğru şekilde sonlandırılmaması gibi durumlar güvenlik açıklarına yol açabilir. Bu durumun önüne geçebilmek için sistem analiz edilerek oturumların ne kadar süre açık kalacağı belirlenmelidir. Bu belirleme uygulamada yapılan transactional işlemlerin sıklığına, kullanıcı verilerinin ne kadar önemli olduğuna göre değişebilmektedir. Bu analiz sonucunda uygun bir değer seçilerek oturum yönetimi sağlanabilir.
Kimlik Doğrulama Zafiyetleri: Zayıf kimlik doğrulama mekanizmaları, saldırganların sisteme izinsiz erişimini kolaylaştırabilir. Bu durumun önüne geçmek için güçlü şifre politikaları, çok faktörlü kimlik doğrulama (MFA) ve güvenli parola saklama teknikleri uygulanmalıdır.
Özet
Node.js ile middleware kullanarak yetkilendirme yönetimi, güvenli ve etkili web uygulamaları geliştirmek için kritik bir unsurdur. Bu makalede, yetkilendirme ve kimlik doğrulama arasındaki farkları, middleware kullanımını ve JWT ile token tabanlı yetkilendirme yöntemlerini inceledik. Ayrıca, farklı sektörlerde yetkilendirme ihtiyaçlarını ve güvenlik açıklarını nasıl önleyebileceğimizi tartıştık. Bu bilgiler, Node.js ile güvenli ve yönetilebilir web uygulamaları geliştirme sürecinde yol gösterici olacaktır. Okuduğunuz için teşekkürler esenlikler dilerim.