· Nacho Coll · Guides · 10 dk okuma
IPFS Yükleme Tokenları: API Anahtarlarını Açığa Çıkarmadan Güvenli İstemci Tarafı Yüklemeler
İmzalı yükleme tokenlarının, API anahtarınızı açığa çıkarmadan tarayıcılardan ve mobil uygulamalardan IPFS'e güvenle yükleme yapmanızı nasıl sağladığını öğrenin.

Modern web uygulamaları geliştirmek genellikle dosyaların doğrudan kullanıcıların tarayıcılarından bulut depolamaya yüklenmesini gerektirir. Ancak IPFS yükleme güvenliği söz konusu olduğunda, geliştiriciler zorlu bir ikilemle karşı karşıya kalır: değerli API anahtarlarınızı potansiyel kötüye kullanıma açık hale getirmeden istemci tarafı yüklemelere nasıl izin verirsiniz?
Çoğu IPFS pinleme servisi sizi rahatsız edici bir seçimle karşı karşıya bırakır: ya tüm yüklemeleri sunucu tarafında işleyin (darboğazlar ve karmaşıklık yaratarak) ya da API anahtarınızı istemci koduna gömün (güvenlik kabusu). IPFS.NINJA bunu başka hiçbir pinleme servisinin sunmadığı benzersiz bir özellikle çözer: imzalı yükleme tokenları.

Geleneksel IPFS API Anahtarlarının Sorunu
IPFS’e yükleme yapması gereken istemci tarafı uygulamalar oluştururken, geliştiriciler genellikle birkaç güvenlik sorunuyla karşılaşır:
API Anahtarı Açığa Çıkma Riski
API anahtarlarını doğrudan tarayıcı JavaScript’ine gömmek, herkesin kaynak kodunuzu görüntüleyip kimlik bilgilerinizi çıkarabileceği anlamına gelir. Bu şunlara yol açabilir:
- Depolama kotanızı tüketen yetkisiz yüklemeler
- Pinleme servis hesabınızın potansiyel kötüye kullanımı
- Kurumsal ortamlarda güvenlik uyumluluk ihlalleri
Sunucu Tarafı Darboğazları
Alternatif olan tüm yüklemeleri backend’iniz üzerinden yönlendirme, birkaç sorun yaratır:
- Artan sunucu bant genişliği maliyetleri
- Kullanıcılar için daha yüksek gecikme
- Daha karmaşık altyapı gereksinimleri
- Potansiyel tek hata noktaları
Mobil Uygulama Güvenliği
Mobil uygulamalar benzer sorunlarla karşı karşıyadır; uygulama paketlerinde saklanan API anahtarları tersine mühendislik yoluyla çıkarılabilir.
IPFS Yükleme Tokenlarına Giriş
IPFS.NINJA’nın imzalı yükleme tokenları güvenli bir orta yol sağlar. İşte nasıl çalışırlar:
- Sunucu token oluşturur: Backend’iniz API anahtarınızı kullanarak süreli, imzalı bir token oluşturur
- İstemci tokeni alır: Token güvenli bir şekilde frontend uygulamanıza iletilir
- Doğrudan yükleme: İstemciler imzalı tokeni kullanarak doğrudan IPFS.NINJA’ya yükleme yapar
- Otomatik süre sonu: Tokenlar belirlenen süre sonunda otomatik olarak geçersiz olur, açığa çıkma penceresini sınırlar
Bu yaklaşım, sunucu tarafı kimlik doğrulamasının güvenliğini doğrudan istemci yüklemelerinin performans avantajlarıyla birleştirir.
Yükleme Token Güvenliğini Anlama
İmzalı yükleme tokenları, ana API anahtarınızı açığa çıkarmadan özgünlüğü sağlamak için kriptografik imzalar kullanır. Her token şunları içerir:
- Süre sonu zaman damgası: Belirtilen süre sonunda otomatik geçersiz kılma
- Kullanım kısıtlamaları: Dosya sayısı veya toplam boyut üzerinde isteğe bağlı limitler
- Kriptografik imza: Kurcalamayı veya sahtecilik yapmayı önler
- Yayıncı doğrulaması: Kimliği doğrulanmış hesabınıza bağlanır
API anahtarlarının aksine, yükleme tokenları istemci tarafı koduna güvenle gömülmek üzere tasarlanmıştır. Çıkarılsa bile, otomatik olarak süresi dolan sınırlı erişim sağlarlar.
Backend Uygulaması: Express.js Örneği
Güvenli istemci tarafı IPFS yüklemelerinin nasıl uygulanacağını gösteren eksiksiz bir örnek oluşturalım. İlk olarak, yükleme tokenları oluşturan Express.js backend’i:
// server.js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cors());
// Your IPFS.NINJA API key (keep this secure on server-side only)
const IPFS_API_KEY = 'bws_1234567890abcdef1234567890abcdef12345678';
// Generate a signed upload token
app.post('/api/generate-upload-token', async (req, res) => {
try {
const response = await fetch('https://api.ipfs.ninja/upload-tokens', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': IPFS_API_KEY
},
body: JSON.stringify({
expiresIn: '1h', // Token valid for 1 hour
maxUploads: 10, // Optional: limit number of uploads
maxSizeMB: 50 // Optional: limit total upload size
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const tokenData = await response.json();
res.json({
success: true,
uploadToken: tokenData.token,
expiresAt: tokenData.expiresAt
});
} catch (error) {
console.error('Token generation failed:', error);
res.status(500).json({
success: false,
error: 'Failed to generate upload token'
});
}
});
// Optional: Endpoint to verify uploads completed successfully
app.post('/api/verify-upload', async (req, res) => {
const { cid } = req.body;
try {
// Verify the file was pinned successfully
const response = await fetch(`https://api.ipfs.ninja/pins/${cid}`, {
headers: {
'X-Api-Key': IPFS_API_KEY
}
});
const pinData = await response.json();
res.json({
success: true,
verified: pinData.pinned,
metadata: pinData
});
} catch (error) {
res.status(500).json({
success: false,
error: 'Verification failed'
});
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});Frontend Uygulaması: Güvenli İstemci Yüklemesi
Şimdi, imzalı tokeni kullanarak dosyaları güvenle yükleyen frontend koduna bakalım:
<!DOCTYPE html>
<html>
<head>
<title>Secure IPFS Upload Demo</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
.upload-area { border: 2px dashed #ccc; padding: 20px; text-align: center; margin: 20px 0; }
.upload-area.dragover { border-color: #007cba; background: #f0f8ff; }
button { background: #007cba; color: white; border: none; padding: 10px 20px; cursor: pointer; }
.status { margin: 10px 0; padding: 10px; border-radius: 4px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.info { background: #d1ecf1; color: #0c5460; }
</style>
</head>
<body>
<h1>Secure IPFS Upload with Signed Tokens</h1>
<div class="upload-area" id="uploadArea">
<p>Drag & drop files here or click to select</p>
<input type="file" id="fileInput" multiple style="display: none;">
<button onclick="document.getElementById('fileInput').click()">Select Files</button>
</div>
<div id="status"></div>
<div id="results"></div>
<script>
class SecureIPFSUploader {
constructor() {
this.uploadToken = null;
this.tokenExpiry = null;
this.setupEventListeners();
}
setupEventListeners() {
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
// Drag and drop handlers
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('dragover');
this.handleFiles(Array.from(e.dataTransfer.files));
});
// File input handler
fileInput.addEventListener('change', (e) => {
this.handleFiles(Array.from(e.target.files));
});
}
async getUploadToken() {
// Check if we have a valid token
if (this.uploadToken && this.tokenExpiry && new Date() < new Date(this.tokenExpiry)) {
return this.uploadToken;
}
try {
this.showStatus('Generating secure upload token...', 'info');
const response = await fetch('/api/generate-upload-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`Failed to generate token: ${response.statusText}`);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'Token generation failed');
}
this.uploadToken = data.uploadToken;
this.tokenExpiry = data.expiresAt;
return this.uploadToken;
} catch (error) {
this.showStatus(`Token generation failed: ${error.message}`, 'error');
throw error;
}
}
async uploadFile(file) {
try {
const token = await this.getUploadToken();
// Convert file to base64 for JSON transport
const fileBase64 = await this.fileToBase64(file);
this.showStatus(`Uploading ${file.name} to IPFS...`, 'info');
const response = await fetch('https://api.ipfs.ninja/upload/new', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Signed ${token}`
},
body: JSON.stringify({
content: fileBase64,
description: `File uploaded via secure token: ${file.name}`,
metadata: {
filename: file.name,
fileType: file.type,
uploadedAt: new Date().toISOString(),
uploadMethod: 'signed-token'
}
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Upload failed: ${response.status} ${errorText}`);
}
const result = await response.json();
return {
success: true,
filename: file.name,
cid: result.cid,
size: result.sizeMB,
ipfsUri: result.uris.ipfs,
httpUrl: result.uris.url
};
} catch (error) {
return {
success: false,
filename: file.name,
error: error.message
};
}
}
async handleFiles(files) {
if (files.length === 0) return;
this.clearResults();
try {
// Upload files concurrently
const uploadPromises = files.map(file => this.uploadFile(file));
const results = await Promise.all(uploadPromises);
this.displayResults(results);
const successful = results.filter(r => r.success).length;
const total = results.length;
if (successful === total) {
this.showStatus(`✅ Successfully uploaded ${successful} file(s) to IPFS!`, 'success');
} else {
this.showStatus(`⚠️ Uploaded ${successful}/${total} files. Check results below.`, 'error');
}
} catch (error) {
this.showStatus(`Upload failed: ${error.message}`, 'error');
}
}
fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
// Remove the data:mime/type;base64, prefix
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = error => reject(error);
});
}
showStatus(message, type) {
const statusDiv = document.getElementById('status');
statusDiv.className = `status ${type}`;
statusDiv.textContent = message;
}
displayResults(results) {
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '<h3>Upload Results:</h3>' +
results.map(result => `
<div class="status ${result.success ? 'success' : 'error'}" style="margin: 10px 0;">
<strong>${result.filename}</strong><br>
${result.success ?
`✅ CID: ${result.cid}<br>
📊 Size: ${result.size} MB<br>
🔗 URL: <a href="${result.httpUrl}" target="_blank">${result.httpUrl}</a>` :
`❌ Error: ${result.error}`
}
</div>
`).join('');
}
clearResults() {
document.getElementById('results').innerHTML = '';
}
}
// Initialize the uploader
const uploader = new SecureIPFSUploader();
</script>
</body>
</html>İleri Düzey Güvenlik Değerlendirmeleri
IPFS yükleme güvenliğini imzalı tokenlarla uygularken, bu ek güvenlik önlemlerini göz önünde bulundurun:
Token Kapsam Sınırlamaları
Tokenları uygun kısıtlamalarla yapılandırın:
// Generate token with specific constraints
const restrictedToken = await fetch('https://api.ipfs.ninja/upload-tokens', {
method: 'POST',
headers: {
'X-Api-Key': IPFS_API_KEY
},
body: JSON.stringify({
expiresIn: '30m', // Short expiration
maxUploads: 5, // Limited upload count
maxSizeMB: 10, // Size restriction
allowedMimeTypes: ['image/jpeg', 'image/png'], // File type restrictions
ipWhitelist: ['192.168.1.0/24'] // IP-based access control
})
});İçerik Doğrulama
Yüklenen içeriği her zaman backend’inizde doğrulayın:
app.post('/api/validate-upload', async (req, res) => {
const { cid } = req.body;
try {
// Fetch and validate the uploaded content
const response = await fetch(`https://ipfs.ninja/ipfs/${cid}`);
const contentType = response.headers.get('content-type');
// Implement your validation logic
if (!isValidContentType(contentType)) {
// Remove invalid content
await deleteFromIPFS(cid);
return res.status(400).json({ error: 'Invalid content type' });
}
res.json({ success: true, validated: true });
} catch (error) {
res.status(500).json({ error: 'Validation failed' });
}
});Hız Sınırlama
Token oluşturma endpoint’inize ek hız sınırlaması uygulayın:
const rateLimit = require('express-rate-limit');
const tokenLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // Limit each IP to 10 token requests per windowMs
message: 'Too many token requests, please try again later'
});
app.use('/api/generate-upload-token', tokenLimiter);Geleneksel Yaklaşımlara Göre Avantajlar
İmzalı yükleme tokenları, alternatif IPFS yükleme güvenlik yöntemlerine göre birçok avantaj sağlar:
Sunucu Tarafı Proxy’ye Karşı
- Performans: Doğrudan yüklemeler sunucu bant genişliği kullanımını ortadan kaldırır
- Ölçeklenebilirlik: Yoğun yükleme dönemlerinde sunucu darboğazı olmaz
- Maliyet: Azaltılmış bant genişliği ve işleme maliyetleri
- Kullanıcı Deneyimi: Daha iyi yükleme hızları ve ilerleme takibi
İstemci Tarafı API Anahtarlarına Karşı
- Güvenlik: API anahtarı çıkarma veya kötüye kullanım riski yok
- Uyumluluk: Güvenlik denetimi gereksinimlerini karşılar
- Erişim Kontrolü: İnce ayarlı izinler ve otomatik süre sonu
- İzleme: Yükleme kaynaklarının ve kalıplarının daha iyi takibi
Diğer Pinleme Servislerine Karşı
IPFS.NINJA şu anda imzalı yükleme tokenları sunan tek büyük pinleme servisidir. Pinata gibi rakipler sunucu tarafı proxy ya da istemci tarafı API anahtarı açığa çıkarma gerektirir, bu da bu özelliği benzersiz bir farklılaştırıcı yapar.
IPFS.NINJA’nın diğer servislerle nasıl karşılaştırıldığı hakkında daha fazla bilgi için kapsamlı karşılaştırma kılavuzumuza göz atın.
Üretim Dağıtım İpuçları
İmzalı yükleme tokenlarını üretimde dağıtırken:
Ortam Yapılandırması
Hassas yapılandırmayı güvenli bir şekilde saklayın:
// Use environment variables for production
const config = {
ipfsApiKey: process.env.IPFS_API_KEY,
tokenExpiry: process.env.UPLOAD_TOKEN_EXPIRY || '1h',
maxFileSize: process.env.MAX_FILE_SIZE_MB || 50,
allowedOrigins: process.env.ALLOWED_ORIGINS?.split(',') || ['localhost:3000']
};İzleme ve Günlükleme
Güvenlik izlemesi için kapsamlı günlükleme uygulayın:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'upload-security.log' })
]
});
// Log token generation
logger.info('Upload token generated', {
userId: req.user.id,
clientIP: req.ip,
userAgent: req.get('User-Agent'),
expiresAt: tokenData.expiresAt
});Hata İşleme
Hassas bilgileri sızdırmayan sağlam hata işleme uygulayın:
app.use((error, req, res, next) => {
// Log full error details server-side
logger.error('Upload token error', {
error: error.message,
stack: error.stack,
userId: req.user?.id,
endpoint: req.path
});
// Send safe error message to client
res.status(500).json({
success: false,
error: 'An internal error occurred. Please try again.'
});
});Popüler Çerçevelerle Entegrasyon
İmzalı yükleme tokenları modern web çerçeveleriyle sorunsuz çalışır. İşte hızlı entegrasyon örnekleri:
React Hook
import { useState, useCallback } from 'react';
export function useSecureIPFSUpload() {
const [uploading, setUploading] = useState(false);
const [uploadToken, setUploadToken] = useState(null);
const getToken = useCallback(async () => {
if (uploadToken?.expiresAt && new Date() < new Date(uploadToken.expiresAt)) {
return uploadToken.token;
}
const response = await fetch('/api/generate-upload-token', {
method: 'POST'
});
const data = await response.json();
setUploadToken(data);
return data.uploadToken;
}, [uploadToken]);
const uploadFile = useCallback(async (file) => {
setUploading(true);
try {
const token = await getToken();
// Upload logic here...
} finally {
setUploading(false);
}
}, [getToken]);
return { uploadFile, uploading };
}Vue.js Composable
import { ref } from 'vue';
export function useSecureUpload() {
const uploading = ref(false);
const uploadProgress = ref(0);
const uploadFile = async (file) => {
uploading.value = true;
// Implementation here...
};
return {
uploading: readonly(uploading),
uploadProgress: readonly(uploadProgress),
uploadFile
};
}Sonuç
İmzalı yükleme tokenları, merkezi olmayan uygulama geliştirmede kritik bir güvenlik sorununu çözer. API anahtarlarını açığa çıkarmadan doğrudan istemci tarafı IPFS yüklemelerini etkinleştirmenin güvenli bir yolunu sağlayarak, modern web uygulamaları için yeni mimari olanaklar açarlar.
İster bir içerik yönetim sistemi, ister NFT pazaryeri veya güvenli dosya yükleme gerektiren herhangi bir uygulama oluşturuyor olun, IPFS.NINJA’nın yükleme tokenları ihtiyacınız olan güvenlik ve esnekliği sağlar. Uygulama basittir, güvenlik avantajları önemlidir ve performans kazançları önemli ölçüdedir.
IPFS temelleri hakkında daha fazla bilgi için IPFS pinleme nedir kılavuzumuza göz atın veya tam API eğitimimizi inceleyin. Farklı seçenekleri değerlendiren geliştiriciler için en iyi IPFS pinleme servisleri karşılaştırmamız kapsamlı bilgiler sunar.
Uygulamanızda güvenli istemci tarafı IPFS yüklemelerini uygulamaya hazır mısınız? Modern güvenlik uygulamaları ve merkezi olmayan depolama kombinasyonu, bu yaklaşımı güvenlik standartlarını korurken ölçeklenmesi gereken üretim uygulamaları için ideal kılar.
Pinlemeye başlamaya hazır mısınız? Ücretsiz hesap oluşturun — 500 dosya, 1 GB depolama, özel ağ geçidi. Kredi kartı gerekmez.
