web-dev-qa-db-fra.com

Détecter Ajax dans PHP et en s'assurant que la demande venait de mon propre site web

J'utilise mon back-end PHP pour détecter les requêtes AJAX en recherchant une valeur dans $_SERVER['HTTP_X_REQUESTED_WITH'].

Cela me donne une détection fiable, en s'assurant que la demande est faite en utilisant les techniques AJAX.

Comment puis-je m'assurer que la demande provient de mon propre domaine et non d'un domaine/robot externe?

www.example.com/ajax?true pourrait permettre à quiconque de passer un appel AJAX et de supprimer les informations.

Je pourrais faire des sessions pour tous ceux qui entrent normalement sur mon site Web, puis autoriser les appels AJAX .. mais cela peut aussi être simulé.

Est-ce même important ces jours-ci?

46
Yossi

Laissez-vous contrôleur

  • générer un jeton d'accès
  • stocker en session pour une comparaison ultérieure

Dans votre vue

  • déclarer le jeton d'accès en tant que variable JS
  • envoyer le jeton à chaque demande

De retour dans votre contrôleur

  • valider HTTP_X_REQUESTED_WITH
  • valider le jeton

Vérifiez ces consignes de sécurité de OpenAjax .
Lisez également l'article sur codinghorror.com Annie lié.

32
Gordon

Vous pouvez vérifier le HTTP_REFERRER, mais tous les navigateurs ne le définissent pas. Le meilleur moyen est d'écrire un wrapper pour vos appels ajax du côté JavaScript, qui renvoie une partie de document.cookie au serveur - seul votre domaine a accès au cookie. Vous pouvez comparer le cookie dans les en-têtes de requête avec le cookie dans l'appel AJAX dans php.

En réponse à, "est-ce même important, ces jours-ci" - OUI, si! Lis ça .

23
Annie

En ce qui concerne votre dernière question: "Est-ce même important, de nos jours?" Ceci est une question au cas par cas. Si la requête ajax fait quelque chose qui ne nécessite pas de sécurité (par exemple, le chargement des dernières cotes boursières), l’important à mon humble avis n’importe pas. Si la demande charge des informations à sécuriser (par exemple, renvoyer des informations d’identification ou faire quelque chose sur le serveur), vous devez les traiter comme telles. 

Personnellement, je n'utilise pas les variables du serveur pour savoir quand quelque chose est une requête ajax. Au lieu de cela, je viens d'ajouter un paramètre de requête à l'appel ajax (par exemple, http://domain.com/?ajax=true ). Si j’ai besoin de sécuriser l’appel ajax, j’utiliserais les mêmes méthodes que pour sécuriser une requête de page classique (en utilisant à la fois le client et le serveur). Comme Lucas Oman l'a souligné, tout ce qui se passe du côté du client peut être simulé. En bout de ligne, vous ne faites confiance à aucune demande, même si vous pensez que cela provient de votre site ou de votre base de données. Suivez toujours le mantra "entrée de filtre - sortie d'échappement". 

6
Jim

David Walsh a une bonne solution

/* decide what the content should be up here .... */
$content = get_content(); //generic function;

/* AJAX check  */
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    /* special ajax here */
    die($content);
}

/* not ajax, do more.... */
3
Ben Shelock

Pour ce faire, le moyen le plus sûr consiste à utiliser, comme vous l’avez suggéré, des sessions côté serveur, car elles ne peuvent pas être conçues comme des cookies.

Certes, quelqu'un peut toujours pirater un ID de session, mais si vous stockez également l'adresse IP de l'utilisateur dans sa session et vérifiez-la à chaque demande, vous pouvez éliminer beaucoup de piratages. Seul un utilisateur du même réseau local ou du même proxy peut le pirater.

Toute autre méthode mentionnée - cookies, javascript, référenceur http - dépend des données côté client, qui ne sont pas sécurisées et doivent toujours être suspectées de falsification, de contrefaçon, de piratage et de construction malveillante.

2
Lucas Oman

Utilisez POST demandes de session sécurisées:

Dans la page Web (par exemple, index.php), nous devons stocker le sessionid

<?php
// Create Session
$session = session_id();
if(empty($session)) session_start();
?>
<head>
...
<script type="text/javascript">
  sid = '<?php echo session_id(); ?>';
</script>
<script type="text/javascript" src="ajaxrequest.js"></script>
...
</head>

Les requêtes ajax (ajaxrequest.js)

/* simple getAjax function 
 * @param $url       request url
 * @param $param     parameter (dont use ?)
 * @param callback  function on success
 */
var spinnerid = '#spinner'; // Spinner as long ajax requests running
$(document).ajaxStart(function() { $(spinnerid).show(); });
$(document).ajaxStop(function() { $(spinnerid).hide(); });
function getAjax( url, param, callback ) {
    var data = null;
    url += "?sid=" + sid + "&" + param;
    $.ajax({
        url: url,
        method: "POST", // uncomment to use GET, POST is secured by session
        cache: false,
        async: true,
        success : function(data){
      callback(data);
    },
}

getAjax( 'http://domain.com/', 'data=foo', function( data ) {
 // do stuf with data 
 var jsonobj = eval("(" + data + ")");
 var data = jsonobj[0][ 'data' ];
});

Côté php responsable:

if( isset( $_GET['sid'] ) ) $client_sid = $_GET['sid'];

if( session_id() == null ) session_start();

if( session_id() != $client_sid ) {
    // noID or wrongID, redirect to mainindex
    ignore_user_abort(true);
    header( "HTTP/1.1 403 Forbidden" );
    header("Connection: close", true);
    exit;
} else {

    // get data
    if( isset( $_GET['data'] ) ) {
        $data = $_GET['data'];
    } else if( isset( $_POST['data'] ) ) {
        $data = $_POST['data'];
    } else {
        $data = null;
    }

    // do stuff with data

    // return data as json
    $resp[0]['data'] = $data; 
    print_r( json_encode( $resp ) );
}
1
v4d

Vérifiez le $_SERVER['HTTP_REFERER']. Cela fonctionnera dans de nombreux cas, mais ne devrait pas être confondu pour une solution totalement sécurisée.

0
Sampson