API Güvenliği: RESTful API'leri Koruma Rehberi
Modern web uygulamalarında API güvenliğini sağlamak için kapsamlı rehber ve en iyi pratikler.

API Güvenliği: RESTful API'leri Koruma Rehberi
API'ler modern uygulamaların omurgasıdır. Ancak, güvenli olmayan API'ler ciddi güvenlik açıklarına yol açabilir. Bu rehberde, RESTful API güvenliğinin tüm yönlerini inceleyeceğiz.
API Güvenliği Neden Kritik?
2024 istatistiklerine göre:
- Veri ihlallerinin %80'i API güvenlik açıklarından kaynaklanıyor
- Ortalama veri ihlali maliyeti $4.35 milyon
- API saldırıları her yıl %200 artıyor
Yaygın API Güvenlik Tehditleri
- Broken Authentication: Kimlik doğrulama zafiyetleri
- Excessive Data Exposure: Gereksiz veri paylaşımı
- Injection Attacks: SQL, NoSQL, Command injection
- Rate Limiting: DoS saldırılarına karşı koruma eksikliği
- IDOR: Güvensiz nesne referansları
Authentication (Kimlik Doğrulama)
1. JWT (JSON Web Tokens)
const jwt = require('jsonwebtoken');
// Token oluşturma
function generateToken(user) {
const payload = {
id: user.id,
email: user.email,
role: user.role
};
return jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: '24h',
issuer: 'codebros-api',
audience: 'codebros-app'
});
}
// Token doğrulama middleware
function authMiddleware(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({
error: 'Authentication required'
});
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({
error: 'Invalid token'
});
}
}
2. Refresh Token Stratejisi
// Token yenileme endpoint'i
app.post('/api/auth/refresh', async (req, res) => {
const { refreshToken } = req.body;
try {
// Refresh token'ı doğrula
const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
// Veritabanında kontrol et
const tokenRecord = await RefreshToken.findOne({
token: refreshToken,
userId: decoded.id,
expiresAt: { $gt: new Date() }
});
if (!tokenRecord) {
return res.status(401).json({ error: 'Invalid refresh token' });
}
// Yeni access token oluştur
const user = await User.findById(decoded.id);
const newAccessToken = generateToken(user);
res.json({ accessToken: newAccessToken });
} catch (error) {
res.status(401).json({ error: 'Refresh token expired' });
}
});
3. OAuth 2.0 Implementation
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/api/auth/google/callback"
},
async (accessToken, refreshToken, profile, done) => {
try {
let user = await User.findOne({ googleId: profile.id });
if (!user) {
user = await User.create({
googleId: profile.id,
email: profile.emails[0].value,
name: profile.displayName
});
}
return done(null, user);
} catch (error) {
return done(error, null);
}
}
));
Authorization (Yetkilendirme)
Role-Based Access Control (RBAC)
// Rol tabanlı middleware
function authorize(...roles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({
error: 'Insufficient permissions'
});
}
next();
};
}
// Kullanım
app.get('/api/admin/users',
authMiddleware,
authorize('admin', 'superadmin'),
async (req, res) => {
// Sadece admin ve superadmin erişebilir
const users = await User.find();
res.json(users);
}
);
Resource-Based Authorization
// Kaynak sahipliği kontrolü
async function checkOwnership(req, res, next) {
const postId = req.params.id;
const userId = req.user.id;
try {
const post = await Post.findById(postId);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
if (post.authorId.toString() !== userId && req.user.role !== 'admin') {
return res.status(403).json({
error: 'You can only modify your own posts'
});
}
req.post = post;
next();
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
}
// Kullanım
app.delete('/api/posts/:id',
authMiddleware,
checkOwnership,
async (req, res) => {
await req.post.delete();
res.json({ message: 'Post deleted' });
}
);
Input Validation
Request Validation with Joi
const Joi = require('joi');
// Validation şemaları
const schemas = {
createUser: Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/).required(),
name: Joi.string().min(2).max(50).required(),
age: Joi.number().integer().min(18).max(120)
}),
updateProfile: Joi.object({
name: Joi.string().min(2).max(50),
bio: Joi.string().max(500),
website: Joi.string().uri()
})
};
// Validation middleware
function validate(schema) {
return (req, res, next) => {
const { error, value } = schema.validate(req.body, {
abortEarly: false,
stripUnknown: true
});
if (error) {
const errors = error.details.map(detail => ({
field: detail.path[0],
message: detail.message
}));
return res.status(400).json({ errors });
}
req.body = value;
next();
};
}
// Kullanım
app.post('/api/users',
validate(schemas.createUser),
async (req, res) => {
// req.body artık valide edilmiş ve temizlenmiş
const user = await User.create(req.body);
res.status(201).json(user);
}
);
SQL Injection Prevention
// ❌ YANLIŞ: SQL Injection'a açık
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const query = `SELECT * FROM users WHERE name LIKE '%${search}%'`;
const results = await db.query(query); // TEHLİKELİ!
});
// ✅ DOĞRU: Parameterized queries
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const query = 'SELECT * FROM users WHERE name LIKE $1';
const results = await db.query(query, [`%${search}%`]);
res.json(results);
});
// ✅ DOĞRU: ORM kullanımı
app.get('/api/users', async (req, res) => {
const { search } = req.query;
const users = await User.findAll({
where: {
name: { [Op.like]: `%${search}%` }
}
});
res.json(users);
});
Rate Limiting
Express Rate Limit
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
// Genel rate limiting
const limiter = rateLimit({
store: new RedisStore({
client: redisClient
}),
windowMs: 15 * 60 * 1000, // 15 dakika
max: 100, // IP başına maksimum 100 istek
message: 'Too many requests, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
// Login endpoint için özel rate limiting
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 15 dakikada maksimum 5 deneme
skipSuccessfulRequests: true,
message: 'Too many login attempts, please try again later.'
});
app.post('/api/auth/login', loginLimiter, async (req, res) => {
// Login logic
});
Custom Rate Limiting with Redis
async function advancedRateLimit(req, res, next) {
const userId = req.user?.id || req.ip;
const key = `rate_limit:${userId}`;
try {
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, 60); // 60 saniye TTL
}
if (current > 10) {
return res.status(429).json({
error: 'Rate limit exceeded',
retryAfter: await redis.ttl(key)
});
}
res.setHeader('X-RateLimit-Limit', 10);
res.setHeader('X-RateLimit-Remaining', Math.max(0, 10 - current));
next();
} catch (error) {
next(error);
}
}
CORS Configuration
const cors = require('cors');
// Geliştirme ortamı
const corsOptions = {
origin: function (origin, callback) {
const whitelist = [
'http://localhost:3000',
'https://codebros.com',
'https://www.codebros.com'
];
if (!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));
Secure Headers
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
noSniff: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' }
}));
// Custom headers
app.use((req, res, next) => {
res.setHeader('X-API-Version', '1.0.0');
res.setHeader('X-Response-Time', Date.now() - req.startTime);
next();
});
API Versioning
// URL versioning
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
// Header versioning
app.use((req, res, next) => {
const version = req.headers['api-version'] || '1.0';
if (version === '1.0') {
req.apiVersion = 'v1';
} else if (version === '2.0') {
req.apiVersion = 'v2';
} else {
return res.status(400).json({
error: 'Unsupported API version'
});
}
next();
});
Error Handling
// Merkezi hata yönetimi
class APIError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
}
}
// Error middleware
app.use((err, req, res, next) => {
// Log hatayı
logger.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method,
ip: req.ip,
user: req.user?.id
});
// Üretim ortamında detay verme
if (process.env.NODE_ENV === 'production' && !err.isOperational) {
return res.status(500).json({
error: 'Internal server error',
requestId: req.id
});
}
res.status(err.statusCode || 500).json({
error: err.message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});
Logging ve Monitoring
const winston = require('winston');
const morgan = require('morgan');
// Winston logger
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Morgan HTTP logger
app.use(morgan('combined', {
stream: {
write: (message) => logger.info(message.trim())
}
}));
// Request tracking
app.use((req, res, next) => {
req.id = crypto.randomUUID();
req.startTime = Date.now();
res.on('finish', () => {
logger.info({
requestId: req.id,
method: req.method,
url: req.url,
statusCode: res.statusCode,
duration: Date.now() - req.startTime,
userAgent: req.headers['user-agent'],
ip: req.ip
});
});
next();
});
Sensitive Data Protection
// Password hashing
const bcrypt = require('bcrypt');
async function hashPassword(password) {
const saltRounds = 12;
return await bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// Data encryption
const crypto = require('crypto');
function encrypt(text) {
const algorithm = 'aes-256-gcm';
const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex')
};
}
// Response filtering
function sanitizeUser(user) {
const { password, resetToken, ...sanitized } = user.toObject();
return sanitized;
}
app.get('/api/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(sanitizeUser(user)); // Password ve sensitive data gizli
});
API Documentation
/**
* @swagger
* /api/users:
* post:
* summary: Yeni kullanıcı oluştur
* tags: [Users]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - email
* - password
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* minLength: 8
* responses:
* 201:
* description: Kullanıcı başarıyla oluşturuldu
* 400:
* description: Geçersiz giriş
* 401:
* description: Yetkisiz erişim
*/
Security Checklist
✅ HTTPS kullanımı (TLS 1.3)
✅ JWT ile authentication
✅ Refresh token stratejisi
✅ Role-based authorization
✅ Input validation (Joi, Yup)
✅ SQL injection koruması
✅ XSS koruması
✅ CSRF token'ları
✅ Rate limiting
✅ CORS yapılandırması
✅ Secure headers (Helmet.js)
✅ Password hashing (bcrypt)
✅ Sensitive data encryption
✅ Error handling
✅ Logging ve monitoring
✅ API versioning
✅ Regular security audits
CodeBros API Güvenlik Hizmetleri
CodeBros olarak API güvenliği konusunda:
✅ Security Audit: Mevcut API'lerinizin güvenlik taraması ✅ Secure Design: Güvenlik odaklı API mimarisi ✅ Best Practices: Industry standartlarına uygun geliştirme ✅ Penetration Testing: Güvenlik zafiyet testleri ✅ Monitoring Setup: 24/7 güvenlik izleme sistemleri
Sonuç
API güvenliği, modern uygulama geliştirmede öncelikli olmalıdır. Bu rehberde ele aldığımız tüm pratikleri uygulayarak, güvenli ve dayanıklı API'ler geliştirebilirsiniz.
API güvenliği ve geliştirme hizmetlerimiz için iletişime geçin!
Etiketler: #APISecurity #Backend #WebSecurity #Authentication #RESTful #NodeJS #CodeBros



