· Nacho Coll · Guides  · 9 min lugemist

IPFS üleslaadimise tokenid: turvalised kliendipoolsed üleslaadimised ilma API võtmete paljastamiseta

Õppige, kuidas allkirjastatud üleslaadimise tokenid võimaldavad teil turvaliselt IPFS-i üles laadida brauseritest ja mobiilirakendustest ilma oma API võtit paljastamata.

Õppige, kuidas allkirjastatud üleslaadimise tokenid võimaldavad teil turvaliselt IPFS-i üles laadida brauseritest ja mobiilirakendustest ilma oma API võtit paljastamata.

Kaasaegsete veebirakenduste ehitamine nõuab sageli failide üleslaadimist otse kasutajate brauseritest pilvsalvestusse. Siiski seisavad arendajad IPFS üleslaadimise turvalisuse osas silmitsi keerulise dilemmaga: kuidas lubada kliendipoolseid üleslaadimisi ilma oma väärtuslikke API võtmeid potentsiaalsele väärkasutusele paljastamata?

Enamik IPFS kinnitamisteenuseid sunnivad teid ebamugavale valikule: kas käsitleda kõiki üleslaadimisi serveripoolselt (luues pudelikaelu ja keerukust) või manustada oma API võti kliendikoodisse (turvanõukogu). IPFS.NINJA lahendab selle ainulaadse funktsiooniga, mida ükski teine kinnitamisteenus ei paku: allkirjastatud üleslaadimise tokenid.

IPFS Ninja

Probleem traditsiooniliste IPFS API võtmetega

Kliendipoolsete rakenduste ehitamisel, mis vajavad IPFS-i üleslaadimist, seisavad arendajad tavaliselt silmitsi mitme turvaprobleemiga:

API võtme paljastamise risk

API võtmete otse brauseri JavaScripti manustamine tähendab, et igaüks saab teie lähtekoodi vaadata ja teie mandaadid välja tõmmata. See võib kaasa tuua:

  • Volitamata üleslaadimised, mis tarbivad teie salvestusmahtu
  • Teie kinnitamisteenuse konto potentsiaalne väärkasutus
  • Turvanõuete rikkumised ettevõtte keskkondades

Serveripoolsed pudelikaelad

Alternatiiv — kõigi üleslaadimiste suunamine läbi teie tagasüsteemi — tekitab mitmeid probleeme:

  • Suurenenud serveri ribalaiuse kulud
  • Kõrgem latentsus kasutajate jaoks
  • Keerukamad infrastruktuuri nõuded
  • Potentsiaalsed üksikud tõrkepunktid

Mobiilirakenduste turvalisus

Mobiilirakendused seisavad silmitsi sarnaste väljakutsetega, kus rakenduspakettidesse salvestatud API võtmeid saab pöördprojekteerimise teel välja tõmmata.

IPFS üleslaadimise tokenite tutvustamine

IPFS.NINJA allkirjastatud üleslaadimise tokenid pakuvad turvalist keskteed. Nii need töötavad:

  1. Server genereerib tokeni: teie tagasüsteem loob ajaliselt piiratud, allkirjastatud tokeni, kasutades teie API võtit
  2. Klient saab tokeni: token edastatakse turvaliselt teie esirakendusele
  3. Otsene üleslaadimine: kliendid laadivad otse IPFS.NINJA-sse, kasutades allkirjastatud tokenit
  4. Automaatne aegumine: tokenid aeguvad pärast määratud kestust, piirates paljastuse akent

See lähenemine ühendab serveripoolse autentimise turvalisuse kliendi otseüleslaadimise jõudluseeliste.

Üleslaadimise tokeni turvalisuse mõistmine

Allkirjastatud üleslaadimise tokenid kasutavad krüptograafilisi allkirju autentsuse tagamiseks ilma teie peamist API võtit paljastamata. Iga token sisaldab:

  • Aegumise ajatempel: automaatne kehtetuks muutumine pärast määratud kestust
  • Kasutuspiirangud: valikulised piirangud failide arvule või kogumahtule
  • Krüptograafiline allkiri: takistab rikkumist või võltsimist
  • Väljaandja kontroll: seostub tagasi teie autenditud kontoga

Erinevalt API võtmetest on üleslaadimise tokenid loodud turvaliseks manustamiseks kliendipoolsesse koodi. Isegi kui need välja tõmmatakse, pakuvad need piiratud juurdepääsu, mis automaatselt aegub.

Tagasüsteemi teostus: Express.js näide

Ehitame täieliku näite, mis näitab, kuidas teostada turvalisi kliendipoolseid IPFS üleslaadimisi. Esiteks, siin on Express.js tagasüsteem, mis genereerib üleslaadimise tokeneid:

// 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 {
    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');
});

Esirakenduse teostus: turvaline kliendi üleslaadimine

Nüüd, siin on esirakenduse kood, mis laadib faile turvaliselt üles, kasutades allkirjastatud tokenit:

<!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');
                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)); });
                fileInput.addEventListener('change', (e) => { this.handleFiles(Array.from(e.target.files)); });
            }
            async getUploadToken() {
                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();
                    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 {
                    const results = await Promise.all(files.map(file => this.uploadFile(file)));
                    this.displayResults(results);
                    const successful = results.filter(r => r.success).length;
                    if (successful === results.length) this.showStatus(`✅ Successfully uploaded ${successful} file(s) to IPFS!`, 'success');
                    else this.showStatus(`⚠️ Uploaded ${successful}/${results.length} 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 = () => { resolve(reader.result.split(',')[1]); }; reader.onerror = error => reject(error); }); }
            showStatus(message, type) { const s = document.getElementById('status'); s.className = `status ${type}`; s.textContent = message; }
            displayResults(results) {
                document.getElementById('results').innerHTML = '<h3>Upload Results:</h3>' + results.map(r => `<div class="status ${r.success ? 'success' : 'error'}" style="margin:10px 0;"><strong>${r.filename}</strong><br>${r.success ? `✅ CID: ${r.cid}<br>📊 Size: ${r.size} MB<br>🔗 URL: <a href="${r.httpUrl}" target="_blank">${r.httpUrl}</a>` : `❌ Error: ${r.error}`}</div>`).join('');
            }
            clearResults() { document.getElementById('results').innerHTML = ''; }
        }
        const uploader = new SecureIPFSUploader();
    </script>
</body>
</html>

Täiendavad turvakaalutlused

IPFS üleslaadimise turvalisuse teostamisel allkirjastatud tokenitega kaaluge neid lisameetmeid:

Tokeni ulatuse piirangud

Seadistage tokenid asjakohaste piirangutega:

// 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', maxUploads: 5, maxSizeMB: 10,
    allowedMimeTypes: ['image/jpeg', 'image/png'],
    ipWhitelist: ['192.168.1.0/24']
  })
});

Sisu valideerimine

Valideerige alati üleslaaditud sisu oma tagasüsteemis:

app.post('/api/validate-upload', async (req, res) => {
  const { cid } = req.body;
  try {
    const response = await fetch(`https://ipfs.ninja/ipfs/${cid}`);
    const contentType = response.headers.get('content-type');
    if (!isValidContentType(contentType)) {
      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' }); }
});

Kiirusepiirang

Rakendage oma tokeni genereerimise lõpp-punktile täiendav kiirusepiirang:

const rateLimit = require('express-rate-limit');
const tokenLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, max: 10,
  message: 'Too many token requests, please try again later'
});
app.use('/api/generate-upload-token', tokenLimiter);

Eelised traditsiooniliste lähenemisviiside ees

Allkirjastatud üleslaadimise tokenid pakuvad mitmeid eeliseid alternatiivsete IPFS üleslaadimise turvameetodite ees:

vs. serveripoolne proksimine

  • Jõudlus: otseüleslaadimised kõrvaldavad serveri ribalaiuse kasutamise
  • Skaleeritavus: serveripoolsed pudelikaelad puuduvad kõrge üleslaadimise perioodidel
  • Kulu: vähenenud ribalaiuse ja töötlemise kulud
  • Kasutajakogemus: parem üleslaadimiskiirus ja edenemise jälgimine

vs. kliendipoolne API võti

  • Turvalisus: API võtme väljavõtmise või väärkasutuse risk puudub
  • Vastavus: vastab turvaauditi nõuetele
  • Juurdepääsukontroll: peeneteralisne õiguste haldus ja automaatne aegumine
  • Jälgimine: parem üleslaadimisallikate ja -mustrite jälgimine

vs. teised kinnitamisteenused

IPFS.NINJA on praegu ainus suurem kinnitamisteenus, mis pakub allkirjastatud üleslaadimise tokeneid. Konkurendid nagu Pinata nõuavad kas serveripoolset proksimist või kliendipoolse API võtme paljastamist, muutes selle ainulaadseks eristajaks.

Lisateabe saamiseks IPFS.NINJA võrdluse kohta teiste teenustega vaadake meie põhjalikku võrdlusjuhendit.

Tootmisse juurutamise näpunäited

Allkirjastatud üleslaadimise tokenite tootmisse juurutamisel:

Keskkonna seadistamine

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']
};

Jälgimine ja logimine

const winston = require('winston');
const logger = winston.createLogger({
  level: 'info', format: winston.format.json(),
  transports: [new winston.transports.File({ filename: 'upload-security.log' })]
});
logger.info('Upload token generated', {
  userId: req.user.id, clientIP: req.ip, userAgent: req.get('User-Agent'), expiresAt: tokenData.expiresAt
});

Vigade käsitlemine

app.use((error, req, res, next) => {
  logger.error('Upload token error', { error: error.message, stack: error.stack, userId: req.user?.id, endpoint: req.path });
  res.status(500).json({ success: false, error: 'An internal error occurred. Please try again.' });
});

Integratsioon populaarsete raamistikega

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 };
}

Kokkuvõte

Allkirjastatud üleslaadimise tokenid lahendavad kriitilise turvaprobleemi detsentraliseeritud rakenduste arendamisel. Pakkudes turvalist viisi kliendipoolsete otseüleslaadimiste lubamiseks IPFS-i ilma API võtmete paljastamiseta, avavad need uusi arhitektuurseid võimalusi kaasaegsetele veebirakendustele.

Olenemata sellest, kas ehitate sisuhaldussüsteemi, NFT turgu või mis tahes rakendust, mis nõuab turvalisi failide üleslaadimisi, pakuvad IPFS.NINJA üleslaadimise tokenid teile vajalikku turvalisust ja paindlikkust. Teostus on lihtne, turvaeelised on märkimisväärsed ja jõudluse parandused on olulised.

IPFS põhitõdede kohta lisateabe saamiseks vaadake meie juhendit mis on IPFS kinnitamine või uurige meie täielikku API õpetust. Erinevaid valikuid hindavate arendajate jaoks pakub meie parimate IPFS kinnitamisteenuste võrdlus põhjalikke ülevaateid.

Valmis kinnitamist alustama? Looge tasuta konto --- 500 faili, 1 GB salvestusruum, spetsiaalne gateway. Krediitkaarti pole vaja.

Tagasi Blogisse