TuttoPC.Info
  Home  |  Hardware  |  Tips & Tricks  |  Reti & Sicurezza  |  E-Commerce  |  Tecnologie Web  |  Connessioni Internet/EMail  |  Glossario  |  Marketing e Web Marketing  |  Script e moduli per ASP.NET
   Sei in:  
Home \ Knowledge Base \ 
Sommario
Hardware
Tips & Tricks
Reti & Sicurezza
E-Commerce
Tecnologie Web
Connessioni Internet/EMail
Glossario
Marketing e Web Marketing
Script e moduli per ASP.NET
Registrazione File Hosting BETA
Login File Hosting BETA
Verifica configurazione DNS
Utility varie
Nuovo Blog
Ricerca nel sito
Segnala il sito a un amico
Se hai trovato questa pagina interessante, scrivilo ad un amico, clicca qui
NEW!! GiDiNet Web Directory
GiDiNet Directory è una Web Directory divisa in più aree tematiche in cui potrete trovare comodamente siti che trattano argomenti di vostro interesse, continua...
Statistiche
Oggi 16/04/2024
sei il visitatore n.
per un totale di visitatori dal 23/04/2007
Hai un problema particolare? Non trovi quello che stai cercando? clicca qui!
Script anti-hotlinking - ASP.NET 2.0
Lo script pubblicato in questa pagina ha lo scopo di creare un sistema anti-hotlinking semi-automatico sfruttando le funzionalità del .NET Framework v2.0.

Il sistema sfrutta due caratteristiche tipiche di ASP.NET:
  • Di default ASP.NET 2.0 blocca il download da browser dei file con estensione .exclude
  • Tutte le richieste verso pagine aspx passano sempre attraverso gli http handler, anche se il file richiesto non esiste
Quindi sfruttando queste caratteristiche si può creare una semplice soluzione anti-hotlinking, che richiede minimi interventi sul sito, e soprattutto non richiede interventi di configurazione sul server web.

La protezione viene applicata richiamando dalla directory pubblica un file nella forma "nomefile.ext.aspx", il sistema restituisce il file "nomefile.ext.exclude" che viene prelevato dalla directory privata.

1. Installazione dello script

Per l'installazione dello script è sufficiente creare due file /App_Code/AntiLeechHandler.vb e /Web.config secondo quanto indicato di seguito
Se il file /Web.config fosse già presente sullo spazio web, basterà modificarlo inserendo quanto riportato in grassetto nelle sezioni indicate.
Scarica i sorgenti completi
Se avete ASP.NET 1.X potete trovare la versione modificata dello script su questa pagina.


Codice del file /App_Code/AntiLeechHandler.vb:
'Copyright (C) 2007 Daniele Iunco

'This program is free software; you can redistribute it and/or modify
'it under the terms of the GNU General Public License as published by
'the Free Software Foundation; either version 2 of the License, or
'(at your option) any later version.

'This program is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'GNU General Public License for more details.

'You should have received a copy of the GNU General Public License along
'with this program; if not, write to the Free Software Foundation, Inc.,
'51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Imports System
Imports System.Configuration
Imports System.Web
Imports System.IO

Namespace GiDiNet

    'AntiLeechHandler
    'Author: Daniele Iunco
    'Date: 6th May 2007
    Public Class AntiLeechHandler
        Implements IHttpHandler

        Private Shared _Settings As AntiLeechSettings
        Private Shared ReadOnly Property Settings() As AntiLeechSettings
            Get
                If _Settings Is Nothing Then _Settings = New AntiLeechSettings()
                Return _Settings
            End Get
        End Property

        Private Enum ReturnType
            PageMissing = 0
            ImageMissing = 1
            PageNoLeech = 2
            ImageNoLeech = 3
        End Enum

        Private Sub ProcessInvalidRequest(ByRef Context As HttpContext, ByVal myType As ReturnType)
            'TODO: Qui si potrebbe sviluppare un sistema per registrare le richieste respinte

            Select Case myType
                Case ReturnType.PageMissing
                    Context.Response.Redirect(Settings.AntiLeechModule_MissingPageURL)
                Case ReturnType.ImageMissing
                    Context.Response.Redirect(Settings.AntiLeechModule_MissingImageURL)
                Case ReturnType.PageNoLeech
                    Context.Response.Redirect(Settings.AntiLeechModule_NoLeechPageURL)
                Case ReturnType.ImageNoLeech
                    Context.Response.Redirect(Settings.AntiLeechModule_NoLeechImageURL)
            End Select

        End Sub

        Public Sub ProcessRequest(ByVal Context As HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
            Dim myRequestPath As String = Context.Request.Path.ToLower()

            'Prelevo la configurazione della directory richiesta, se non la trovo restituisco la pagina di errore
            Dim myDirectory As ProtectedDirectory = Settings.GetProtectedDirectory(myRequestPath)
            If myDirectory Is Nothing Then
                'Se non ho trovato una directory restituisco la pagina di errore
                ProcessInvalidRequest(Context, ReturnType.PageMissing)
                Exit Sub
            End If

            'Questo primo controllo serve per evitare di eseguire troppe verifiche inutili: 
            'Se l'estensione più corta è di 3 caratteri e aggiungo 7 caratteri, la lunghezza del percorso richiesto deve essere per forza maggiore di 10 caratteri (la richiesta è nella forma "/percorso/a.ext.aspx")
            If myRequestPath.Length < myDirectory.PublicPath.Length + 10 Then
                ProcessInvalidRequest(Context, ReturnType.PageMissing)
                Exit Sub
            End If

            'Queste tre righe fanno una verifica davvero semplice sul referer, si potrebbero anche usare le espressioni regolari, fare attenzione a gestire i referer nulli
            'Volendo posso verificare in modo più approfondito se il file "localPath" può essere davvero scaricato (es. verificando estensione, percorso, autorizzazioni, etc)
            Dim myReferer As String = Context.Request.ServerVariables("HTTP_REFERER")
            If myReferer Is Nothing Then myReferer = ""
            Dim bIsValidReferer As Boolean = Settings.IsValidReferer(myReferer)

            'Preparo la stringa col percorso reale
            Dim newPath As String = myDirectory.PrivatePath & myRequestPath.Substring(myDirectory.PublicPath.Length)
            newPath = newPath.Substring(0, newPath.LastIndexOf("."))

            'Qui avviene l'impostazione del content type, se necessario aggiungere gli altri tipi di file
            If newPath.Substring(newPath.LastIndexOf(".") + 1).ToLower = "gif" Then
                If Not bIsValidReferer Then ProcessInvalidRequest(Context, ReturnType.ImageNoLeech) : Exit Sub
                Context.Response.ContentType = "image/gif"
            ElseIf newPath.Substring(newPath.LastIndexOf(".") + 1).ToLower = "zip" Then
                If Not bIsValidReferer Then ProcessInvalidRequest(Context, ReturnType.PageNoLeech) : Exit Sub
                Context.Response.ContentType = "application/x-zip-compressed"
            ElseIf newPath.Substring(newPath.LastIndexOf(".") + 1).ToLower = "jpg" Then
                If Not bIsValidReferer Then ProcessInvalidRequest(Context, ReturnType.ImageNoLeech) : Exit Sub
                Context.Response.ContentType = "image/jpeg"
            ElseIf newPath.Substring(newPath.LastIndexOf(".") + 1).ToLower = "png" Then
                If Not bIsValidReferer Then ProcessInvalidRequest(Context, ReturnType.ImageNoLeech) : Exit Sub
                Context.Response.ContentType = "image/png"
            Else
                If Not bIsValidReferer Then ProcessInvalidRequest(Context, ReturnType.PageNoLeech) : Exit Sub
            End If

            Dim localPath As String = Context.Server.MapPath(newPath) & ".exclude"

            If Not File.Exists(localPath) Then ProcessInvalidRequest(Context, ReturnType.PageMissing) : Exit Sub

            'Imposto il nome del file
            Context.Response.AddHeader("Content-Disposition", "attachment; filename=" & newPath.Substring(newPath.LastIndexOf("/") + 1))

            'Invio il file al browser, su ASP.NET 2.0 posso usare Response.TransmitFile per ridurre il carico di lavoro sul server, su ASP.NET 1.x dovrò usare Response.WriteFile
            Context.Response.TransmitFile(localPath)
        End Sub

        Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
            Get
                Return True
            End Get
        End Property

    End Class

    Public Class ProtectedDirectory
        Private _PublicPath As String
        Public ReadOnly Property PublicPath() As String
            Get
                Return _PublicPath
            End Get
        End Property

        Private _PrivatePath As String
        Public ReadOnly Property PrivatePath() As String
            Get
                Return _PrivatePath
            End Get
        End Property

        Public Sub New(ByVal PublicPath As String, ByVal PrivatePath As String)
            _PublicPath = PublicPath
            _PrivatePath = PrivatePath
        End Sub
    End Class

    Public Class AntiLeechSettings
        Public ReadOnly Property AllowedDomains() As String()
            Get
                Return _AllowedDomains
            End Get
        End Property

        Public ReadOnly Property ProtectedDirectories() As ProtectedDirectory()
            Get
                Return _ProtectedDirectories
            End Get
        End Property

        Public ReadOnly Property AntiLeechModule_NoLeechImageURL() As String
            Get
                Return _AntiLeechModule_NoLeechImageURL
            End Get
        End Property

        Public ReadOnly Property AntiLeechModule_NoLeechPageURL() As String
            Get
                Return _AntiLeechModule_NoLeechPageURL
            End Get
        End Property

        Public ReadOnly Property AntiLeechModule_MissingImageURL() As String
            Get
                Return _AntiLeechModule_MissingImageURL
            End Get
        End Property

        Public ReadOnly Property AntiLeechModule_MissingPageURL() As String
            Get
                Return _AntiLeechModule_MissingPageURL
            End Get
        End Property

        Private _AllowedDomains As String()
        Private _ProtectedDirectories As ProtectedDirectory()

        Private _AntiLeechModule_NoLeechImageURL As String
        Private _AntiLeechModule_NoLeechPageURL As String

        Private _AntiLeechModule_MissingImageURL As String
        Private _AntiLeechModule_MissingPageURL As String

        Public Sub New()
            'Caricamento delle varie impostazioni dal file di configurazione
            Dim myDomainNumberString As String = ConfigurationManager.AppSettings("AntiLeechModule_DomainNumber")
            If IsNumeric(myDomainNumberString) Then
                ReDim _AllowedDomains(myDomainNumberString - 1)
            Else
                ReDim _AllowedDomains(0)
            End If
            For i As Integer = 1 To _AllowedDomains.Length
                Dim tmpItem As String
                tmpItem = ConfigurationManager.AppSettings("AntiLeechModule_AllowedDomain_" & i)
                If Not tmpItem Is Nothing AndAlso tmpItem.Length > 0 Then
                    _AllowedDomains(i - 1) = tmpItem.Trim.ToLower
                Else
                    _AllowedDomains(i - 1) = ""
                End If
            Next

            _AntiLeechModule_NoLeechImageURL = ConfigurationManager.AppSettings("AntiLeechModule_NoLeechImageURL")
            If _AntiLeechModule_NoLeechImageURL Is Nothing Then _AntiLeechModule_NoLeechImageURL = "/"
            _AntiLeechModule_NoLeechPageURL = ConfigurationManager.AppSettings("AntiLeechModule_NoLeechPageURL")
            If _AntiLeechModule_NoLeechPageURL Is Nothing Then _AntiLeechModule_NoLeechPageURL = "/"

            _AntiLeechModule_MissingImageURL = ConfigurationManager.AppSettings("AntiLeechModule_MissingImageURL")
            If _AntiLeechModule_MissingImageURL Is Nothing Then _AntiLeechModule_MissingImageURL = "/"
            _AntiLeechModule_MissingPageURL = ConfigurationManager.AppSettings("AntiLeechModule_MissingPageURL")
            If _AntiLeechModule_MissingPageURL Is Nothing Then _AntiLeechModule_MissingPageURL = "/"

            Dim myProtectedDirectoryNumberString As String = ConfigurationManager.AppSettings("AntiLeechModule_DirectoryNumber")
            If IsNumeric(myProtectedDirectoryNumberString) Then
                ReDim _ProtectedDirectories(myProtectedDirectoryNumberString - 1)
            Else
                ReDim _ProtectedDirectories(0)
            End If

            For i As Integer = 1 To _ProtectedDirectories.Length
                Dim tmpItem1, tmpItem2 As String
                tmpItem1 = ConfigurationManager.AppSettings("AntiLeechModule_DirectoryPublic_" & i)
                tmpItem2 = ConfigurationManager.AppSettings("AntiLeechModule_DirectoryPrivate_" & i)
                If Not tmpItem1 Is Nothing AndAlso tmpItem1.Length > 0 AndAlso Not tmpItem2 Is Nothing AndAlso tmpItem2.Length > 0 Then
                    _ProtectedDirectories(i - 1) = New ProtectedDirectory(tmpItem1, tmpItem2)
                Else
                    _ProtectedDirectories(i - 1) = New ProtectedDirectory("/", "/")
                End If
            Next

        End Sub

        Public Function GetProtectedDirectory(ByVal RequestPath As String) As ProtectedDirectory
            If RequestPath Is Nothing Then Return Nothing

            'Verifico se la directory della richiesta è una sottodirectory di un percorso protetto, e in questo caso restituisco i parametri di configurazione 
            For i As Integer = 0 To ProtectedDirectories.Length - 1
                If RequestPath.Substring(0, ProtectedDirectories(i).PublicPath.Length) = ProtectedDirectories(i).PublicPath Then Return ProtectedDirectories(i)
            Next

            Return Nothing
        End Function

        Public Function IsValidReferer(ByVal RefererString As String) As Boolean
            If RefererString Is Nothing Then Return False

            For i As Integer = 0 To AllowedDomains.Length - 1
                RefererString = RefererString.ToLower
                If RefererString.IndexOf(AllowedDomains(i)) >= 0 Then Return True
            Next

            Return False
        End Function

    End Class

End Namespace

Codice del file /Web.config:
Nota: Se sul server web è già presente un file web.config, modificare il file esistente inserendo le righe indicate in grassetto nelle rispettive sezioni (appSettings e httpHandlers)
<?xml version="1.0"?>
<configuration>
    <appSettings>
        <add key="AntiLeechModule_DomainNumber" value="3"></add>
        <add key="AntiLeechModule_AllowedDomain_1" value="http://www.primodominio.com"></add>
        <add key="AntiLeechModule_AllowedDomain_2" value="http://www.secondodominio.com"></add>
        <add key="AntiLeechModule_AllowedDomain_3" value="http://www.terzodominio.com"></add>
        <add key="AntiLeechModule_NoLeechImageURL" value="http://hostname.com/AlertImage.gif"></add>
        <add key="AntiLeechModule_NoLeechPageURL" value="http://hostname.com/AlertPage.htm"></add>
        <add key="AntiLeechModule_MissingImageURL" value="http://hostname.com/404.gif"></add>
        <add key="AntiLeechModule_MissingPageURL" value="http://hostname.com/404.htm"></add>
        <add key="AntiLeechModule_DirectoryNumber" value="2"></add>
        <add key="AntiLeechModule_DirectoryPublic_1" value="/directory1/"></add>
        <add key="AntiLeechModule_DirectoryPrivate_1" value="/directory1/secure/"></add>
        <add key="AntiLeechModule_DirectoryPublic_2" value="/directory2/"></add>
        <add key="AntiLeechModule_DirectoryPrivate_2" value="/directory2/secure/"></add>
    </appSettings>

    <system.web>
        <httpHandlers>
              <add verb="GET" path="*.zip.aspx" type="GiDiNet.AntiLeechHandler"></add>
              <add verb="GET" path="*.jpg.aspx" type="GiDiNet.AntiLeechHandler"></add>
              <add verb="GET" path="*.png.aspx" type="GiDiNet.AntiLeechHandler"></add>
              <add verb="GET" path="*.gif.aspx" type="GiDiNet.AntiLeechHandler"></add>
        </httpHandlers>
    </system.web>
</configuration>

2. Configurazione e uso dello script

Per la configurazione è necessario modificare i parametri nel file /Web.config, seguendo le istruzioni riportate di seguito:

Parametri generali:
AntiLeechModule_NoLeechImageURL: Indicare l'indirizzo di un'immagine da visualizzare per le richieste respinte.
AntiLeechModule_NoLeechPageURL: Indicare l'indirizzo di una pagina web da visualizzare per le richieste respinte.
AntiLeechModule_MissingImageURL: Indicare l'indirizzo di un'immagine da visualizzare per le richieste di file non esistenti.
AntiLeechModule_MissingPageURL: Indicare l'indirizzo di una pagina web da visualizzare per le richieste di file non esistenti.


Selezione dei domini autorizzati ad effettuare link alle risorse:
AntiLeechModule_DomainNumber: indicare il numero delle righe AntiLeechModule_AllowedDomain_N inserite e quindi il numero di domini da autorizzare
AntiLeechModule_AllowedDomain_1
AntiLeechModule_AllowedDomain_2
AntiLeechModule_AllowedDomain_N: Riportare per ciascun dominio una riga nella forma AntiLeechModule_AllowedDomain_N dove N è il numero della riga stessa, impostando come valore il dominio autorizzato.
Nell'esempio vogliamo autorizzare 3 domini (primodominio.com, secondodominio.com e terzodominio.com)


Selezione delle directory che possono contenere file protetti:
AntiLeechModule_DirectoryNumber: indicare il numero delle righe AntiLeechModule_DirectoryPublic_N/AntiLeechModule_DirectoryPrivate_N inserite e quindi il numero di directory da proteggere
Per ciascuna directory da proteggere è necessario inserire due righe: AntiLeechModule_DirectoryPublic_N e AntiLeechModule_DirectoryPrivate_N.
AntiLeechModule_DirectoryPublic_N dovrà contenere il percorso relativo della directory pubblica a cui linkare i file .ext.aspx
AntiLeechModule_DirectoryPrivate_N dovrà contenere il percorso relativo della directory privata che conterrà i file .ext.exclude

Nell'esempio vogliamo proteggere 2 directory: /directory1/ che preleva i file da /directory1/secure/ e /directory2/ che preleva i file da /directory2/secure/

Selezione delle estensioni di file da proteggere: Sarà necessario una riga <add verb=....></add> seguendo l'esempio, per ciascun tipo di file da proteggere.

3. Preparazione dei file da proteggere

In ciascuna directory protetta, sarà necessario rinominare i file aggiungendo la seconda estensione .exclude (ad es. nomefile.ext andrà rinominato in nomefile.ext.exclude) , a questo punto sarà possibile richiamare gli stessi file dalla directory pubblica aggiungendo l'estensione aspx (ad es. nomefile.ext andrà richiamato come nomefile.ext.aspx)

4. File supportati

Il sistema creato supporta i file .zip, .gif, .png, .jpg, è possibile inserire ulteriori estensioni seguendo le istruzioni riportate nei commenti del codice sorgente.

5. Problemi noti

Il sistema può funzionare in modo non corretto con il browser Internet Explorer 6, se viene attivata la compressione HTTP lato server per i file aspx.

Pubblicato da: Daniele Iunco il 06/04/2007


Sei interessato a ulteriori informazioni su un particolare argomento? Potete contattaci attraverso l'apposito modulo.

ATTENZIONE: Le operazioni elencate nel sito possono avere esiti negativi o diversi da quanto indicato. Si consiglia di procedere con cautela.
Decliniamo ogni responsabilità per eventuali danni e/o malfunzionamenti derivanti dall'applicazione di ciò che è riportato in queste pagine.
Realizzazione a cura di GiDiNet