Php ve React.js ile api güvenliği nasıl sağlanır?
Merhaba arkadaşlar. Ben web sitemin front-end kısmını Reacjt.js ile back-end kısımını ise php ile yapıyorum. Php'de verileri veritabanından çekip json'a çeviriyorum ve sonra bu verileri React.js'de fetch ile alıyorum. Benim takıldığım nokta bu api adresine örneğin siteismi.com/uyecek.php sayfasına başka uygulamalardanda sorgu yapılabilir. Bunu nasıl engelleyebilirim? Bu api'ı sadece ben kullanmak istiyorum. Dışarıdan izinsiz kimse erişemesin istiyorum.
Soru hatalı mı? 👎
Eğer sorunun kurallara aykırı olduğunu düşünüyorsanız lütfen bize bildirin!
Cevaplar (3)
Frontend (React.js) Kodu
import React, { useState } from 'react';
function UrunEkle() {
const [urunAdi, setUrunAdi] = useState('');
const [urunFiyati, setUrunFiyati] = useState('');
const [csrfToken, setCsrfToken] = useState('');
// CSRF token'ı backend'den almak için bir fonksiyon yazın
function getCsrfToken() {
fetch('http://siteismi.com/csrf_token.php', {
credentials: 'include'
})
.then(response => response.json())
.then(data => setCsrfToken(data.csrfToken));
}
// Sayfa yüklendiğinde CSRF token'ını alın
useEffect(() => {
getCsrfToken();
}, []);
// Ürün bilgilerini backend'e gönderen bir fonksiyon yazın
function handleSubmit(event) {
event.preventDefault();
const data = {
urunAdi: urunAdi,
urunFiyati: urunFiyati,
csrfToken: csrfToken // CSRF token gönderilir
};
fetch('http://siteismi.com/urun_ekle.php', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Error:', error);
});
}
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="urun-adi">Ürün Adı:</label>
<input type="text" id="urun-adi" value={urunAdi} onChange={e => setUrunAdi(e.target.value)} />
</div>
<div>
<label htmlFor="urun-fiyati">Ürün Fiyatı:</label>
<input type="number" id="urun-fiyati" value={urunFiyati} onChange={e => setUrunFiyati(e.target.value)} />
</div>
<input type="hidden" name="csrf_token" value={csrfToken} /> {/* CSRF token hidden input alanı olarak eklenir */}
<button type="submit">Ürün Ekle</button>
</form>
);
}
Backend (PHP) Kodu
<?php
session_start();
// Veritabanı bağlantısı yapılır
$servername = "localhost";
$username = "kullanici_adi";
$password = "sifre";
$dbname = "veritabani_adi";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Veritabanı bağlantısı başarısız: " . $conn->connect_error);
}
// CSRF token'ı oluşturan ve kontrol eden fonksiyonları içeren bir sınıf yazın
class Csrf {
public static function generateToken() {
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token; // CSRF token session'da saklanır
return $token;
}
public static function validateToken($csrf_token) {
if (isset($_SESSION['csrf_token']) && $csrf_token === $_SESSION['csrf_token']) {
return true;
} else {
return false;
}
}
}
// Ürün ekleme işlemini gerçekleştiren bir fonksiyon yazın
function urunEkle($data) {
// CSRF token doğrulaması yapılır
if (!isset($data['csrf_token']) || !Csrf::validateToken($data['csrf_token'])) {
header('HTTP/1.1 401 Unauthorized');
echo json_encode(['message' => 'CSRF token doğrulaması başarısız.']);
exit();
}
// POST verileri alınır
$urunAdi = isset($data['urunAdi']) ? htmlspecialchars($data['urunAdi']) : null;
$urunFiyati = isset($data['urunFiyati']) ? (float) $data['urunFiyati'] : null;
// Verilerin doğruluğu kontrol edilir
if (!$urunAdi || !$urunFiyati) {
header('HTTP/1.1 400 Bad Request');
echo json_encode(['message' => 'Ürün adı ve fiyatı belirtilmelidir.']);
exit();
}
// Veritabanına ürün eklenir
$sql = "INSERT INTO urunler (urun_adi, urun_fiyati) VALUES ('$urunAdi', $urunFiyati)";
if ($conn->query($sql) === true) {
echo json_encode(['message' => 'Ürün başarıyla eklendi.']);
} else {
header('HTTP/1.1 500 Internal Server Error');
echo json_encode(['message' => 'Ürün eklenirken bir hata oluştu: ' . $conn->error]);
}
}
// GET isteği alındığında CSRF token oluşturup döndüren bir API endpoint'i yazın
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['csrf_token'])) {
$csrfToken = Csrf::generateToken();
echo json_encode(['csrfToken' => $csrfToken]);
}
// POST isteği alındığında ürün ekleme fonksiyonunu çağıran bir API endpoint'i yazın
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['urunAdi']) && isset($_POST['urunFiyati'])) {
urunEkle($_POST);
} else {
header('HTTP/1.1 400 Bad Request');
echo json_encode(['message' => 'Geçersiz istek.']);
}
$conn->close();
?>
1. IP Kontrolü: PHP'de sadece web sitenin IP adresinden gelen isteklere yanıt verilmesini sağla.
$_SERVER['REMOTE_ADDR']
sana isteğin geldiği IP adresini verir. Bir if kontrolüyle, bu IP'den gelmeyen isteklere hata dönebilirsin.
Kullanıcı, header'dan giden IP bilgisini değiştirebilir ve isteği sitenden yapılmış gibi gösterebilir. Bu yüzden sadece bu koruma yeterli değil.
2. Token Kontrolü: CSRF açıklarından korunmak için iyidir. Front end önce PHP'ye istek atıp token alır ve bundan sonra yapacağı tüm isteklerde header üzerinden bu token'ı iletir. PHP, gelen isteğin header'ında bu token'ı kontrol eder.
Burada bahsettiğim token, PHP tarafında sadece senin bildiğin bir anahtar ile şifrelenmiş bir string ifade. Sana bu token ile bir istek yapıldığında elindeki anahtarla token'ı açtığında, senin token'ın içine koyduğun verilere ulaşamıyorsan servisine hata döndürebilirsin.
Kullanıcı anahtar olmadan bu token'ı kendisi üretemeyeceği için bir güvenlik sağlar. Ama kullanıcı siteye bir kez giriş yaptığında bir token elde edebileceğine göre bu token ile sunucuya yine isteklerde bulunabilir. Bu yüzden token'ların içine bir son kullanım tarihi de eklemek iyi olur. Ama bu token'ın kullanım süresi boyunca kullanıcı bu token ile sunucuya istekler atabilir. Ayrıca token süresi dolsa bile yine siteye girip yeni token bir alabilir. Yani bu koruma da tam olarak yeterli değil.
3. HTTPS: HTTPS protokolü, iletişimi şifreleyerek istekleri güvenli hale getirir. Bu nedenle, sadece HTTPS kullanımına izin vermek de ek bir güvenlik sağlar.
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') { // HTTPS ile istek yapılmamış...
şeklinde bir kontrol eklenebilir.
Kullanıcı https üzerinden de istek atabilir. Bu da yeterli değil.
4. CAPTCHA: Botların otomatik isteklerini engellemek için kullanılan bir güvenlik önlemi olsun diye kullanılabilir. Bu sitede olduğu gibi...
Kullanıcı sitene girmeden de servisinin endpoint'lerine istek atabilir. Bu elbette senin soruna binaen yeterli bir önlem değil.
5. DDoS: Sunucu tarafında bu saldırıları önmelek için güvenlik duvarı kullanmak, tüm kaynakları kendi sitende barındırmak yerine cdn kullanmak iyi olabilir.
Bunun da doğrudan soruyla ilgisi yok ama yapmak iyi olur. Paylaşımlı sunucularda genelde bu hazırda vardır. Sunucu seninse bu kontrolleri de senin yapman gerekebilir.
Böyle şeyler... Bunlar geldi aklıma. Bunlar içinde özellikle token kullanmak, istenmeyen istekleri reddetmek için kullanılabilir. Çoğu sistem bu şekilde çalışıyor.