2010-02-02 12 views
36

Diciamo che ci sono molti file html, css, js, img ed ecc all'interno di una directory sul tuo server. Normalmente, qualsiasi utente in internet-land può accedere a questi file semplicemente digitando l'URL completo in questo modo: http://example.com/static-files/sub/index.htmlUtilizzo di PHP/Apache per limitare l'accesso ai file statici (html, css, img, ecc.)

Ora, cosa succede se si desidera che solo gli utenti autorizzati possano caricare tali file? Per questo esempio, diciamo che i tuoi utenti accedono prima da un URL come questo: http://example.com/login.php

Come permetteresti all'utente connesso di visualizzare il file index.html (o qualsiasi file sotto "file statici") , ma limitare il file a tutti gli altri?

Sono venuto su con due possibili soluzioni così lontane:

Soluzione 1
creare il seguente file .htaccess in "static-files":

Options +FollowSymLinks 
RewriteEngine on 
RewriteRule ^(.*)$ ../authorize.php?file=$1 [NC] 

E poi nel Autorizza. php ...

if (isLoggedInUser()) readfile('static-files/'.$_REQUEST['file']); 
else echo 'denied'; 

Questo file authorize.php è eccessivamente semplificato, ma si e l'idea.

Soluzione 2
creare il seguente file .htaccess in "static-files":

Order Deny,Allow 
Deny from all 
Allow from 000.000.000.000 

E poi la mia pagina di login potrebbe aggiungere quel file .htaccess con un IP per ogni utente che accede a Ovviamente questo dovrebbe anche avere qualche tipo di routine di pulizia per eliminare gli IP vecchi o non più usati.


Mi preoccupo che la mia prima soluzione possa diventare piuttosto costosa sul server in quanto aumenta il numero di utenti e file a cui stanno accedendo. Penso che la mia seconda soluzione sarebbe molto meno costosa, ma è anche meno sicura a causa dello spoofing IP e così via. Mi preoccupo anche che scrivere questi indirizzi IP sul file htaccess possa diventare un collo di bottiglia dell'applicazione se ci sono molti utenti simultanei.

Quale di queste soluzioni suona meglio e perché? In alternativa, puoi pensare a una soluzione completamente diversa che sarebbe meglio di una di queste?

+1

ne dite di usare Amazon S3 servizio – sonam

risposta

34

Vorrei prendere in considerazione l'utilizzo di un caricatore PHP per gestire l'autenticazione e quindi restituire i file necessari. Ad esempio invece di fare <img src='picture.jpg' /> Fai qualcosa come <img src='load_image.php?image=picture.jpg' />.

Il caricatore di immagini può verificare sessioni, verificare le credenziali, ecc. E quindi decidere se restituire o meno il file richiesto al browser. Ciò ti consentirà di archiviare tutti i tuoi file protetti al di fuori della radice accessibile Web, in modo che nessuno possa solo WGET o navigare 'accidentalmente'.

Ricorda solo di restituire le intestazioni giuste in PHP e fare qualcosa come readfile() in php e che restituirà il contenuto del file al browser.

Ho usato questa installazione su diversi siti Web sicuri su larga scala e funziona come un fascino.

Modifica: il sistema attualmente in costruzione utilizza questo metodo per caricare Javascript, immagini e video, ma non siamo molto preoccupati con la protezione.

+1

Grazie Shane. Questo caricatore è fondamentalmente ciò che descrivo nella mia prima soluzione. La mia preoccupazione è la spesa del server, ma sono lieto di sapere che ha funzionato bene per te nel tuo "sito Web sicuro su larga scala". – Bart

+0

In genere non uso le regole .htaccess menzionate sopra (anche se non vedo ragioni per non farlo), creo solo alcune funzioni wrapper che creano le stringhe di query corrette e passano gli argomenti.Dato che il server in genere serve di nuovo i dati binari, l'unico overhead aggiuntivo è l'elaborazione PHP che (almeno per me) vale la sicurezza che guadagni specialmente rispetto al sovraccarico .htaccess di far controllare molti (hundereds | migliaia) di indirizzi ip per OGNI richiesta di pagina nel sistema. Penso che uno dei tanti modi per dare una pelle a questo gatto! Fammi sapere se ti imbatti in qualcos'altro! – Shane

+0

È corretto dire che nessuna delle immagini potrebbe essere memorizzata nella cache dal browser in questo caso? –

2

Mantenere il contenuto dei file htaccess sembra essere un incubo. Inoltre, il vostro obiettivo dichiarato è quello di evitare che non non autenticati indirizzi non autenticati utenti client IP di accedere questi contenuti - in modo che il metodo non è adatto allo scopo: può apparire

Più utenti di venire dallo stesso Indirizzo IP

È possibile che una singola sessione utente provenga da più indirizzi.

temo che la mia prima soluzione potrebbe ottenere abbastanza costoso sul server come il numero di utenti e dei file che accedono aumenta

Se si vuole evitare che il contenuto da lisciviazione e non si voglio usare l'authenitcation HTTP e quindi avvolgere tutti gli accessi ai file in un ulteriore livello di logica è l'unica scelta sensata. Inoltre, non sai che usare PHP per questo è un problema - l'hai provato? Penso che ti sorprenderebbe quanta velocità riusciresti a fornire, soprattutto se utilizzi una cache di opcode.

Immagino che la "semplificazione" del wrapper risolva problemi come il tipo mime e il caching.

C.

+0

PHP è sicuramente un problema per questo sui siti pesanti con molte chiamate. Non è solo il mettere i dati; l'intero processo di autenticazione dell'utente deve essere eseguito per ogni singola piccola risorsa. Questo di solito pesa pochi MB o RAM, e questo ogni volta per risorsa richiesta. –

+0

definisce "heavy duty"? Ho avuto degli script molto più complessi che elaborano mezzo milione di accessi al giorno su un celeron da 1ghz con 512 Mb di memoria (OK, in realtà 4 volte quel volume su 4 server) estrapolando dati da un DB e dando comunque tempi di risposta in media di 250 ms . – symcbean

+0

No, non l'ho ancora provato. Ma a prescindere dai dettagli, un server web che serve semplicemente un file deve essere meno costoso di PHP, eseguendo alcune funzioni del filesystem come 'is_file' e' stat', e infine serve il file tramite 'readfile'. – Bart

3

Crea una rewrite map che verifica le credenziali dell'utente e o li reindirizza alla risorsa appropriata o ad un "accesso negato" pagina.

+0

Sì! Ho giocato un po 'con questa stessa idea dopo aver scritto originariamente questa domanda. Una RewriteMap è stata riscritta all'URL originariamente richiesto se autenticata e una pagina negata se non autenticata. Per la vita di me non riuscivo a farlo funzionare. Non riuscivo nemmeno ad avviare Apache quando si specificava uno script PHP in PRG. Hai qualche esempio o consiglio per usare questo tipo di tecnica? La mia configurazione è: Apache 2.2/PHP 5.2/Windows Server 2008 – Bart

+0

Lo script deve essere eseguibile che su Windows significa che .php deve essere associato all'eseguibile CLI PHP. Inoltre, lo script dovrebbe richiamare "flush()" sull'output e dovrebbe tornare indietro e attendere ulteriori input; lo script viene avviato all'avvio di httpd e viene ucciso su httpd shutdown. –

5

Ho pensato molto allo stesso problema. Sono egualmente infelice con il motore PHP in esecuzione per ogni piccola risorsa offerta. Ho fatto una domanda nella stessa vena alcuni mesi fa here, anche se con un focus diverso.

Ma ho appena avuto un terribilmente idea interessante che potrebbe lavoro.

  • Mantenere una directory denominata /sessions da qualche parte sul server Web.

  • Ogni volta che un utente effettua il login, crea un file di testo vuoto con l'ID di sessione in /sessions. Per esempio. 123456

  • in PHP app, scontare immagini come questa: /sessions/123456/images/test.jpg

  • Nel file .htaccess, hanno due redirect comandi.

  • Uno che si traduce in /sessions/123456/images/test.jpg/sessions/123456?filename=images/test.jpg

  • A seconda che cattura tutte le chiamate a //sessions/(.*) e controlla se il file specificato esiste utilizzando il flag -f. Se /sessions/123456 non esiste, significa che l'utente ha effettuato il logout o la sua sessione è scaduta.In tal caso, Apache invia un 403 o reindirizza a una pagina di errore - la risorsa non è più disponibile.

In questo modo, abbiamo l'autenticazione di quasi sessione in mod_rewrite facendo solo un controllo "file exists"!

Non ho abbastanza routine per compilare le istruzioni mod_rewrite al volo, ma dovrebbero essere abbastanza facili da scrivere. (Sto cercando spera nella vostra direzione @Gumbo :)

Note e avvertimenti:

  • file Sessione scaduta dovrebbe essere cancellato velocemente utilizzando un job cron, a meno che non è possibile verificare la presenza di il file mtime in .htaccess (che potrebbe essere possibile).

  • L'immagine/risorsa è disponibile per qualsiasi client fino a quando la sessione esiste, quindi nessuna protezione al 100%. Potresti forse aggirare questo problema aggiungendo l'IP del client nell'equazione (= il nome del file che crei) e fai un ulteriore controllo per% {REMOTE_ADDR}. Questa è una conoscenza avanzata .htaccess ma sono abbastanza sicuro che sia fattibile.

  • Gli URL delle risorse non sono statici e devono essere richiamati ogni volta al momento del log-in, quindi nessun caching.

Sono molto interessato a feedback su questo, eventuali carenze o impossibilità forse ho trascurato, e tutte le implementazioni di successo (non ho il tempo adesso di istituire un test di me).

0

Ho scritto un'applicazione web dinamica e distribuito su WebShere Application Server, e qui è il modo in cui ho ottenuto i miei file statici:

ho aggiunto

<login-config id="LoginConfig_1"> 
    <auth-method>FORM</auth-method> 
    <realm-name>Form-Based Authentication</realm-name> 
     <form-login-config> 
     <form-login-page>/login.html</form-login-page> 
     <form-error-page>/login_error.html</form-error-page> 
     </form-login-config> 
</login-config> 

in web.xml che sarà comunicare al proprio server Web di utilizzare l'autenticazione basata su modulo (il codice per utilizzare l'accesso è indicato di seguito).

codice alla pagina di login:

<form id="form1" name="form1" method="post" action="j_security_check" style="padding: 0px 0px 0px 12px;"> 
     Username: 
      <label> 
      <input name="j_username" type="text" class="font2" /> 
     </label> 

     <br /> 
     <br /> 
     Password: 
     <span class="font2" > 
     <label> 
     <input name="j_password" type="password" class="font2" /> 
     </label> 
     </span> 
     <br /> 
     <br /> 
      <label> 
     <input type="submit" class="isc-login-button" name="Login" value="Login" /> 
     </label> 
    </form></td> 

Per rendere modulo basato login accadere è necessario configurare il server web di utilizzare un particolare registory utente che può essere LDAP o database.

È possibile dichiarare le risorse protette e ogni volta che un utente tenta di accedere a tali risorse, il contenitore verifica automaticamente se l'utente è autenticato o meno. Anche tu puoi collegare ruoli anche con le risorse sicure. Per fare questo ho aggiunto seguente codice nel mio web.xml

<security-constraint> 
     <display-name>Authenticated</display-name> 
     <web-resource-collection> 
      <web-resource-name>/*</web-resource-name> 
      <url-pattern>/*</url-pattern> 
      <http-method>GET</http-method> 
      <http-method>PUT</http-method> 
      <http-method>HEAD</http-method> 
      <http-method>TRACE</http-method> 
      <http-method>POST</http-method> 
      <http-method>DELETE</http-method> 
      <http-method>OPTIONS</http-method> 
     </web-resource-collection> 
     <auth-constraint> 
      <description>Auth Roles</description> 
      <role-name>role1</role-name>    
      <role-name>role2</role-name>    
     </auth-constraint> 
    </security-constraint> 

    <security-role> 
     <role-name>role1</role-name> 
    </security-role> 
    <security-role> 
     <role-name>role2</role-name> 
    </security-role> 

Quindi questo codice non permetterà all'utente di vedere qualsiasi tipo di file statici (dal/*) fino a quando non viene registrato in meno di ruolo Role1 e Role2. In questo modo puoi proteggere le tue risorse.

0

Se si utilizza apache, è possibile configurare, come di seguito, nel file .htaccess o httpd.conf. Di seguito è riportato un esempio per impedire l'accesso al file * .inc. Funziona molto per me.

<Files ~ "\.inc$"> 
Order allow,deny 
Deny from all 
</Files> 

Si rimanda per maggiori dettagli su: http://www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/.

+0

È già evidente che l'OP utilizza una configurazione PHP/Apache. – askmish

+0

Questo non risponde completamente alla domanda poiché l'OP ha bisogno che quei file siano accessibili in qualche modo da utenti autorizzati. – Tchoupi

7

X-Sendfile

C'è un modulo per Apache (e altri server HTTP), che consente di dire al server HTTP per servire il file specificato in un colpo di testa nel codice PHP: Quindi lo script php dovrebbe apparire come:

// 1) Check access rights code 
// 2) If OK, tell Apache to serve the file 
header("X-Sendfile: $filename"); 

2 possibili problemi:

  1. È necessario l'accesso a riscrivere le regole (.htaccess abilitato o l'accesso diretto ai file di configurazione)
  2. È necessario modulo mod_xsendfile aggiunto alla tua Apache installato

Ecco una buona risposta in un altro thread: https://stackoverflow.com/a/3731639/2088061

+1

Questa è sicuramente la migliore soluzione a questo problema. – mathieu

0

Si supponga che si desidera proteggere tutti i file statici e si deve server li da all'interno del webroot, è possibile proteggere tutti i metodi HTTP tranne HEAD. Se sei autorizzato, fai passare una richiesta di testa attraverso le intestazioni e invia il contenuto del file come corpo. Certo, questo è costoso, ma sei protetto e hai lo stesso comportamento.

0

Potrei avere un suggerimento basato su iframe e HTTP_REFERER ma non è a prova di proiettile e dipenderà da cosa esattamente si desidera proteggere con questo accesso.

Ma nel caso di prevenire una pagina statica completo da visualizzare senza autenticazione si può fare come segue:

1 - utilizzare una pagina PHP per autenticare l'utente

2 - reindirizzare a un'altra pagina PHP contenente una chiave nella URL e un iframe che collega al vostro contenuto statico nel corpo:

<iframe src="static/content.html" /> 

3 - Poi, nel tuo .htaccess si potrebbe verificare la chiave all'interno del HTTP_REFERER così:

RewriteEngine On 
RewriteCond %{HTTP_REFERER} !AUTH_KEY 
RewriteCond %{REQUEST_URI} ^/path/to/protected/page$ 
RewriteRule . - [F] 

4 - Infine, se si desidera renderlo più dinamico e non utilizzare lo stesso codice ogni volta che si potrebbe usare rewrite map come suggerito dalla risposta Ignacio Vazquez-Abrams' o creare un file utilizzando l'utente IP come il nome del file e di controllo se il file esiste utilizzando REMOTE_ADDR, rimuovere il file dopo qualche istante.

Ma tenere a mente che iframe + HTTP_REFERER comportamento potrebbe variare da una sessione browser per altro così come REMOTE_ADDR per cui il suo limitato ...

Problemi correlati