È pericoloso passare l'input dell'utente alla funzione require in Node.js?

1

TL; DR: È pericoloso avere l'input dell'utente utilizzato in una funzione require in Node.js? Può essere utilizzato per leggere i file e, in caso affermativo, come posso proteggerlo?

Ad esempio, ho un server ExpressJS in esecuzione, con un'API. Il client può effettuare una chiamata a /api/login , che viene quindi richiesta come ./api/login(.coffee) :

require('coffee-script')
app = require('express')()

app.all '/api/:func?', (req, res) ->
  # Get API function
  func = req.params.func

  # Check if file exists
  fs = require 'fs'
  fs.access "./api/#{func}.coffee", fs.F_OK & fs.R_OK, (err) ->
    if err
      # Send error when invalid call
      api = require('./api/error')
    else
      # !!! Injection ?
      api = require('./api/' + func)

    # Call API
    api(req, res)

Suppongo che non si possa inviare una richiesta a http://example.net/api/../../../etc/passwd , ad esempio, ma l'ho verificato solo nel mio browser e non sono sicuro che il mio browser lo gestisca. Oltre a ciò, penso che la cosa peggiore che potrebbe accadere sarebbe che il nodo si arresti in modo anomalo perché non può richiedere un file di questo tipo.

Ci sono problemi di sicurezza qui e come bloccherò tali attacchi?

    
posta Charlie 08.06.2016 - 21:18
fonte

3 risposte

2

Se gli utenti richiedono file imprevisti, si otterrà un comportamento imprevisto. Anche se potrebbe non essere ovvio come un utente malintenzionato possa sfruttarlo per qualcosa di utile, è impossibile prevederne le conseguenze. Non va bene.

Per lo meno si apre una vulnerabilità DoS poiché un utente può facilmente bloccare il nodo e forzare un riavvio. Alcune richieste come quella al secondo e sei fuori dal mercato. Nel peggiore dei casi ... chi lo sa?

Quindi qual è la soluzione? Vedo due possibili approcci:

  1. Whitelist. Avere una matrice con i nomi di file consentiti e assicurarsi che func sia in quell'array prima che sia necessario.
  2. Assicurati di rimanere nella cartella API e assicurati che tutti i file possano essere inclusi in modo sicuro. Per sapere come fare, vedi questo mia domanda .
risposta data 08.06.2016 - 21:29
fonte
1

Non dovresti mai usare le esigenze dinamiche, a meno che tu non abbia strongmente disinfettato l'input (whitelist se possibile).

Node.js accetterà QUALSIASI estensione del file nella sua richiesta di chiamata. Non convalida che sia un file .js, E.g

require('malicious-uploaded-file')

Questo "file caricato male" potrebbe essere un file .png | .jpg pieno di JS dannoso.

In precedenza ho sfruttato questa falla usando un sistema di caricamento di file scritto male (non ho rinominato i file, o ho i permessi di directory corretti) che mi permise di caricare un file .png riempito il codice di shell inverso del Nodo. Ho quindi manipolato un requisito dinamico per utilizzare la directory traversal allo script caricato.

Ora questo particolare sistema aveva molti difetti ma questi 2 mi hanno permesso di prendere il controllo completo del sistema remoto.

    
risposta data 18.09.2017 - 12:37
fonte
0

Esporre la funzione require in questo modo è quasi come o altrettanto male di esporre eval

  • require('./api/good.js');eval('//xkcd.com/327');// < - Codice di iniezione
  • require('../../../dev/zero') < - DDoS
  • require('../../../var/upload/bad.js') < - Exploit remoto
  • require('../../../opt/proprietary-package/proprietary-code.js') < - Bad
risposta data 18.09.2017 - 16:23
fonte

Leggi altre domande sui tag