0%

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.

📅
👤CodeBros
⏱️8 dakikada okunur
APISecurityBackendRESTAuthentication
API Güvenliği: RESTful API'leri Koruma Rehberi - Blog yazısı öne çıkan görseli

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

  1. Broken Authentication: Kimlik doğrulama zafiyetleri
  2. Excessive Data Exposure: Gereksiz veri paylaşımı
  3. Injection Attacks: SQL, NoSQL, Command injection
  4. Rate Limiting: DoS saldırılarına karşı koruma eksikliği
  5. 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

K
CodeBros
CodeBros - Profesyonel Yazılım Geliştirme Şirketi
Paylaş:
WhatsApp
WhatsApp