Simple cross-site requests ovvero processare richieste in modo sicuro

MarcoGrazia

Utente Attivo
15 Dic 2009
852
20
28
62
Udine
www.stilisticamente.com
Ciao.
Prima di tutto spiego di cosa si tratta.
Come tutti sanno, quando da un browser si richiede una pagina web, si mette in moto un meccanismo complesso che permette al "sistema internet" di funzionare.
Il browser manda una serie di input sotto forma di messaggi codificati al server per richiedere quanto richiesto dall'utente e il server risponde in qualche modo.
Fin qui la base fin troppo semplificata :D

Saltando ogni precisazione, anche perché molti di voi già le conoscono, mi soffermo solo su due aspetti particolari della questione:
  1. mostrare la pagina
  2. inviare richieste GET o POST
La prima è perfino ovvia, ma mettiamo che questa pagina contenga un form di dati da inviare, per esempio una pagina di login, tanto per citare.
Se inseriamo all'inizio della nostra pagina, ovviamente scritta in PHP, qualcosa del genere:
PHP:
...
echo '<p>VARIABILE _SERVER</p><pre>';
var_dump($_SERVER);
echo '</pre>';
...
Otterremo qualche cosa del genere:
/home/server/upload.php:7:
array (size=32)
'HTTP_HOST' => string '192.168.56.1' (length=12)
'HTTP_CONNECTION' => string 'keep-alive' (length=10)
'HTTP_UPGRADE_INSECURE_REQUESTS' => string '1' (length=1)
'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' (length=115)
'HTTP_DNT' => string '1' (length=1)
...
eccetera
Cioè indicazioni riguardo la richiesta che abbiamo fatto al server.
Fino a qui nulla di strano, anzi è la norma.
Ma che succede se dalla stessa pagina inviamo una richiesta di tipo GET o POST?
La risposta è in una piccola ma significativa risposta nella variabile _SERVER che poi andremo a sfruttare per rendere più sicura la nostra applicazione.
Ecco il punto 2: inviando una richiesta con dati al server, questo risponde inserendo l'origine di chi ha fatta la richiesta.
/home/server/upload.php:7:
array (size=37)
'HTTP_HOST' => string '192.168.56.1' (length=12)
'HTTP_CONNECTION' => string 'keep-alive' (length=10)
'CONTENT_LENGTH' => string '611' (length=3)
'HTTP_CACHE_CONTROL' => string 'max-age=0' (length=9)
'HTTP_ORIGIN' => string 'http://192.168.56.1' (length=19)
'HTTP_UPGRADE_INSECURE_REQUESTS' => string '1' (length=1)
'HTTP_DNT' => string '1' (length=1)
'CONTENT_TYPE' => string 'multipart/form-data; boundary=----WebKitFormBoundaryIbOZ8b9bSRcpmbve' (length=68)
A dire il vero ne inserisce diverse di cose, ma ORIGIN è ciò che ci serve per verificare la richiesta.
Essa contiene l'origine da cui è stata fatta la richiesta.
Qui si vede l'indirizzo IP ma si può trovare il dominio se questo è settato; io ho il mio serverino casalingo che non ha settato un dominio, quindi mostra l'IP.
Fa lo stesso, l'importante è il dato, e noi lo sfrutteremo.
Lo script che presento, riguarda proprio la verifica dell'origine della richiesta e serve a verificare se un invio tramite GET o POST provenga proprio dal dominio a cui si sta cercando di loggarci.
Lo script è commentato, quindi spero che basti questo, in ogni caso mi fermo qui per ora, dato che come al solito mi sono già dilungato abbastanza. :rolleyes:

Script per evitare (mitigare) l'accesso indesiderato alla nostra applicazione:
file: login.php
PHP:
<?php
/*
 * Copyright 2019 Marco Grazia
 *
 * 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.
 *
 *
 */
session_start();
ob_start();
try {

$errore = '';  //    Un flag per mostrare un eventuale errore nella pagina.
//  Semplicemente la paginetta di login. Inserite la vostra
$htmlFile =<<<EOF
<!DOCTYPE html>
<html lang="it">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Login</title>
    </head>
 
    <body>
        <h1>Sign in</h1>
        $errore
        <form  action="login.php" method="POST">
            <p><label for="account">Account:</label><br>
            <input name="account" type="text" id="account" required value="" placeholder="Il tuo account"></p>
            <p><label for="password">Password:</label><br>
            <input name="password" type="password" id="password" required value=""></p>
            <p><input type="submit" value="Sign  in" name="invia"></p>
        </form>
    </body>
</html>\n
EOF;

//    Anti Cross-Origin (Se la richiesta viene da GET o POST, e da questo sito, prosegue)
//    Se è settato HTTP_ORIGIN all'interno della variabile _SERVER e se è settata con il nome del mio sito, proseguo...
if (isset($_SERVER['HTTP_ORIGIN']) === true && $_SERVER['HTTP_ORIGIN'] == 'http://mio_sito') {

                //  Invio gli header che dispongono l'accettazione del sito, ovvero della pagina.
                header ('Access-Control-Allow-Origin: http://tuo_sito');
                header ('Content-Type: text/html; charset=UTF-8');

                //  Quindi processo la richiesta, ovvero l'accesso al mio sito:
               if (filter_has_var(INPUT_POST, 'invia') && filter_has_var(INPUT_POST, 'invia') == 'Sign in')  {
                 
                    //  Qui, se i dati del modulo corrispondono, avviene il login.
                    //  Ma non è questo l'argomento di discussione, quindi evito di mostrare altro

               } else {
                   //    Se si verifica una bad request mostro un messaggio nella pagina di login,
                  //    settando la variabile $login.
                   $errore = '<h3 style="colore: red;">Si è verificato un errore processando i tuoi dati, riprova.</h3>';
                   echo $htmlFile;  //    Mostro la pagina con la minaccia :-)
              }
              //    Se invece la fase di login è andata a buon fine indirizzo l'utente alla pagina che cercava.
             header('location: http:://mio_sito/' . $pagina_destinazione);
             exit();
} elseif (isset($_SERVER['HTTP_ORIGIN']) === false) {
            //  E se arrivo qui direttamente dal sito?
           //  Secondo lo script mi rimanderebbe indietro, quindi processo pure il caso in cui HTTP_ORIGIN non settato.
           //  In questo caso, semplicemente mostro la pagina di login.
          header('Content-Type: text/html; charset=UTF-8');
          echo $htmlFile;
          //  E attendo fiducioso che l'utente svolga la fase di login.
} else {
    //    Questo è decisamente il caso peggiore: HTTP_ORIGIN esiste, ma il sito di provenienza non corrisponde all'origine.
    //    A questo punto bisogna dire al client browser che le cose non funzioneranno.
    header('Content-Type: text/html; charset=UTF-8');
    //    Creo al volo una paginetta di risposta.
    echo <<<EOF
<!DOCTYPE html>
<html lang="it">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Login</title>
    </head>
 
    <body>
        <h1>Sign in problem</h1>
        <h2>There is a problem with the Cross-Origin method</h2>
        <p>You are probably trying to log in from a domain other than <a href="http://mio_sito">mio_sito</a>.</p>
        <p>Bye!</p>
    </body>
</html>\n[/I]
EOF;
}
 //  Fine fase di controllo.
}  //  Fine try
catch (Exception $e) {
    do {
        printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
    } while($e = $e->getPrevious());
}
?>
Lo script è tutto qui, in pratica come si può vedere non fa altro che processare la richiesta del server HTTP_ORIGIN, se c'è ne verifica l'autenticità.
Ovvio che http://mio_sito va modificato al bisogno.
Io ci ho giocato per un po' inserendo nell'url anche l'indirizzo di localhost e mi ha bloccato perché non corrispondeva all'IP del server.
Ah! Quasi dimenticavo, è importante considerate anche il protocollo di destinazione, ovvero http://mio_sito e https:://mio_sito, non sono uguali ;-)
Non sarà ne perfetta e ne definitiva dato che per bloccare Cross-Site Request Forgery (CSRF) serve altro, ma è un inizio.
Lo script è ovviamente embrionale, quì è rilasciato sotto licenza, gradirei chi lo usa di mantenerla, grazie.
:confused:
 
Ultima modifica:

marino51

Utente Attivo
28 Feb 2013
3.203
207
63
Lombardia
ma ORIGIN è ciò che ci serve per verificare la richiesta
si incontrano subito due problemi,
il primo problema é generato dai browser che non gestiscono "origin"
il secondo problema é conseguente all'uso di un dato praticamente statico e in chiaro, quindi facilmente intercettabile da malintenzionati
ti chiedo quindi, perché hai adottato questa soluzione (poco sicura ?)
invece di usare una soluzione con token
PHP:
 <input type="hidden" name="token" value="<?php print GenerateToken(); ?>" />
che funziona con i vari browser e che puoi "personalizzare" legando la generazione del token all' utente specifico (se necessario per migliorare la sicurezza) ?

ps, modifica lo script, manca apice di chiusura
T, 'invia) &&
 

MarcoGrazia

Utente Attivo
15 Dic 2009
852
20
28
62
Udine
www.stilisticamente.com
Ciao, scusa il ritardo con cui rispondo.
In realtà cercavo un modo per identificare l'utente all'interno della LAN in cui lavoro.
E' un vizio brutto, ma qui gli indirizzi assegnati, lo sono dal server centrale che non cambia mai, quindi viene facile stare certi che la macchina è quella, ma è un vizio in effetti.
Il tuo sistema è più generico e quindi sicuramente applicabile al "mondo di fuori".

PS: modificato ;)
 

marino51

Utente Attivo
28 Feb 2013
3.203
207
63
Lombardia
Non puoi sapere se e quando ripartee il server, e dato che se riparte il server viene anche azzerata la memoria assegnata al PHP, persino il metodo da te segnalato andrebbe a farsi benedire, con blocco della pagina.
non mi sembra che il problema sia un blocco del server per ragioni "casuali"
ma il controllo degli indirizzi ip assegnati a specifici pc

se "cade" il server, non ce n'é per nessuno, lo sappiamo
ma se viene fatto ripartire un server o il dhcp, che azzera gli ip su cui viene fatto un controllo di validità,
ebbene qualche problema potrebbe esserci
la ripartenza di un server e/o dhcp é operazione rara, ma va messa in conto ….
 
Discussioni simili
Autore Titolo Forum Risposte Data
gandalf1959 formattazione carrello plug-in WP Simple Paypal Shopping cart WordPress 2
K Joomla: Modulo contatti in SP simple portfolio Joomla 0
M Simple Slideshow jQuery 1
felino Really Simple Captcha: errore 404 sull'immagine WordPress 4
J jsDatePick - A Simple Free Javascript Date Picker Javascript 0
C problema pagina web con collegamenti Simple Wiever HTML e CSS 3
T simple tabs Javascript 2
W cms made simple è in php help cartine PHP 1
R javascript lettura css cross-browser Javascript 1
D csrf : Cross Site Request Forgery in classic asp Classic ASP 0
otto9due Richieste AJAX cross-domain, vorrei capisrci qualcosa in più.. jQuery 0
R utilizzo di cors for cross domain requests Ajax 0
L Climpare un cavo di rete... Diretto o cross? Reti LAN e Wireless 1
S Consiglio per una grafica cross-browser (anche su browser obsoleti) HTML e CSS 12
MrClog i.e. ed il cross-browser HTML e CSS 7
Eruyomon cross browser HTML e CSS 3
M Ajax: eseguire chiamate cross-domain Ajax 1
davidec Disabilitare il filtro XSS (cross site scripting) via PHP PHP 3
C Cross-browser, problemi con la gestione degli eventi da tastiera Javascript 0
G problemi di cross browser - accessibilità ? HTML e CSS 2
L Cross-Browser | problema font tra FF e IE8 HTML e CSS 0
T Problema con il Cross-Browser HTML e CSS 3
R Vendita site market Supporto Mr.Webmaster 15
M [HTML] Ottimizzazioni immagini per Google Site Optimization HTML e CSS 1
Z vps per multi site Server Dedicati e VPS 3
ilsuomillennio mobile site in html/css HTML e CSS 4
L Cancellare web site Weebly CMS (Content Management System) 0
maxbossi Vendi i tuoi domini e/o siti web sul SITE MARKET Compravendita siti e domini 4
I Html 5 OnePage Site HTML e CSS 2
8 Eliminare weebly free site HTML e CSS 3
A cambiare la site map HTML e CSS 2
S Tutto pes site Presenta il tuo Sito 4
novello88 Pagine Gialle Visual Site Discussioni Varie 3
borgo italia site map google SEO e Posizionamento 3
J Super Awesome and Amazing MooTools Site Examples Javascript 0
Robby84 I giochi online del CFL site!! Presenta il tuo Sito 4
T Ecco il Rendering che cercavi! This is my site. Presenta il tuo Sito 0
sbobby Gioca online sul CFL site!! Presenta il tuo Sito 1
sbobby LDA site, lascia libera la mente!! Presenta il tuo Sito 5
G Web site in lingua russa e cinese PHP 4
M Omnis...The new Generation Site Presenta il tuo Sito 1
sbobby Nuovo indirizzo CFL site!! Presenta il tuo Sito 4
sbobby CFL site - il sito del divertimento!! Presenta il tuo Sito 21
J Google Page Rank, Adsense, PPC integrated with your site Google AdSense 1
J Anti Avril Lavigne Site Presenta il tuo Sito 2
mindsoul Hotel Selene Lignano web site Presenta il tuo Sito 12
M My web site HTML e CSS 10
K annuncio .. [importante] Site Altri Annunci 2
open-think Kool Flash Site Flash 1
A mio sito (NEXUS6 SITE) Presenta il tuo Sito 10

Discussioni simili