Fork me on GitHub

Sujet deuxième session 17 juin 2015

Lorsqu’ils vous est demandé d’écrire du code, vous pouvez donner votre réponse en vous basant sur le framework Node.js+Express ou sur PHP+Silex, au choix.

Durée 2h. Ordinateurs et téléphones interdits. Seuls documents admis : 2 feuilles A4 manuscrites recto-verso.

Côté client – HMTL, CSS, JS

Le but de cette partie est d’écrire un formulaire html pour récupérer une réservation d’avion, afin de procéder à l’enregistrement en ligne du passager. Il y a deux critères de recherche :

  1. le premier (par PNR) est d’entrer le numéro de réservation à 6 caractères parmi A-Z et 0-9, et le nom de famille du passager,
  2. le second (par Eticket) est d’entrer le numéro de billet electronique à 13 ou 14 chiffres et le code à 3 lettres majuscules de l’aéroport de départ (par ex CDG).

La compagnie aérienne a défini un gestionnaire POST à l’url /checkin/pnr et un gestionnaire GET à l’url /checkin/ebillet. Le premier accepte comme paramètres uniquement deux chaînes nommées pnr et passengername. Le second prend comme paramètres deux chaînes nommées eticket et airport. (Les gestionnaires envoient un message d’erreur si on leur passe n’importe quel autre paramètre).

HTML et CSS

SANS UTILISER de JavaScript, écrivez le morceau de html/css produisant le rendu suivant. Ne mettez pas les en-têtes, allez directement à l’essentiel.

Les points suivants compteront dans la note :

div#checkinoptions {
  width: 100%;
  border: thin black dotted;
  text-align: center;
}
Accès par PNR
N° de reservation:
Nom de famille:
Accès par Eticket
N° de billet:
Aéroport:

JavaScript

Les utilisateurs ne connaissant pas les codes de tous les aéroports par coeur, la compagnie propose de mettre en ligne un fichier javascript comme celui-ci à l’url /data/airports.js :

var airports = {
'CDG' : 'Paris Charles de Gaulle, France',
'ORY' : 'Paris Orly, France',
'LAX' : 'Los Angeles, USA',
//[ ... etc (10000 lignes)...]
'YYZ' : 'Toronto, Canada'
};

window.onload = function() {
	//TODO: A compléter
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
  1. Donner la balise html qui permet de charger et executer ce code dans le document de la question précédente.

  2. Complétez le code de la fonction (à l’endroit de TODO: A compléter), de sorte que lors du chargement de la page, le champ de texte où l’utilisateur devait entrer le code 3 lettres de l’aeroport soit supprimé et remplacé par un avec autant d’options que d’aéroports, mais que le bouton fonctionne encore.

Côté serveur – Express/Silex

On considère une application web composée des deux gestionnaires suivants (donnés d’abord en Node.js, puis en Silex) :

app.get('/button', function(req, res) {
	db.query('SELECT COUNT(pushes) FROM button',
		     function(err, rows) {
				 res.render('button.twig', { count: rows[0].pushes });
			 });
});

app.get('/push', function(req, res) {
	db.query('INSERT INTO button VALUES (NOW())');
	res.redirect('/button');
});
$app->get('/button', function(Application $app) {
	$row = $app['db']->fetch('SELECT COUNT(pushes) FROM button');
	return $app['twig']->render('button.twig', array('count' => rows['pushes']);
});

$app->get('/push', function(Application $app) {
	$app['db']->query('INSERT INTO button VALUES (NOW())');
	return $app->redirect('/button');
});

On donne aussi un extrait du code du template button.twig :

<form method="post" action="/push">
	<input type="submit" value="Push me">
</form>
<!-- TODO à compléter -->



Web 1.0 : 4 points

  1. Il y a une erreur bête (en dehors du fait que les erreurs de la base de données ne sont pas gérées). Trouvez-la et proposez une correction.

  2. Que peut-on dire sur la structure de la table SQL button ?

  3. Compléter le template button.twig pour qu’il affiche le nombre de fois que le bouton a été cliqué.

  4. L’utilisateur visite l’URL /button et clique le bouton.

    Décrire les requêtes HTTP (URL et contenu) envoyées par le browser et le contenu des réponses données par le serveur.

AJAX : 3 points

  1. Modifier le gestionnaire de /push pour qu’il retourne le nombre de clics au format JSON, plutôt qu’une redirection.

  2. Modifier button.twig pour que, à la pression du bouton, le clic soit envoyé via une requête AJAX, et le nombre de clics mis à jour sans recharger la page.

    Vous pouvez utiliser un framework (par ex. JQuery) pour construire la requête AJAX et/ou modifier le DOM.

Note: La référence à https://www.reddit.com/r/thebutton n’est pas casuelle.

Théorie et sécurité

HTTP

  1. Repérer les erreurs dans la requête et la réponse HTTP suivantes.

    POST /toto/ HTTP/1.1
    Host: www.toto.com/toto
    Set-Cookie: toto=123
    
    200 OK HTTP/1.1
    Cookie: toto=123
    Host: www.toto.com
       
    Hello, toto!
    
  2. On considère l’échange HTTP suivant (la réponse est laissée intentionnellement incomplète).

    GET /home/ HTTP/1.1
    Host: www.example.com
    Cookie: sessid=abc
    Referer: http://www.example.com/
    
    HTTP/1.1
    Server:
    Location:
    
    
    
    
    
    GET /home/fr/ HTTP/1.1
    Host: www.example.com
    Cookie: sessid=123456
    Referer: http://www.example.com/home/
    

    Complétez la réponse du serveur (deuxième encadré) en sorte que la totalité de l’échange soit cohérente.

Injections

On considère les gestionnaires suivants (en Node.js et en Silex)

app.post('/:usr/insert', function(req, res) {
	db.query('INSERT INTO ' + req.params.usr + ' VALUES (?)',
		     [req.body.potatoes], ...);
});
			 
app.get('/:usr/list', function(req, res) {
	db.query('SELECT * FROM ' + req.params.usr,
		     function(err, rows) {
				 res.render('garden.twig', {
					 garden: rows,
					 user: req.params.usr });
			 });
});			 
$app->post('/{usr}/insert', function(Application $app, Request $req, $usr) {
	$app['db']->query('INSERT INTO ' . $usr . ' VALUES (?)',
		              array($req->request->get('potatoes')));
	...
});
			 
$app->get('/{usr}/list', function(Application $app, $usr) {
	$rows = $app['db']->query('SELECT * FROM ' + $usr);
	return $app['twig']->render('garden.twig',
		array('garden' => $rows, 'user': $usr ));
});			 

et l’extrait suivant du template garden.twig.

<h1>Jardin de {{ user }}</h1>
<ul>
{% for veg in {{ garden }} %}
	<li>{{ veg.potatoes | raw }}</li>
{% endfor %}
</ul>

Indiquer lesquelles des chaînes dans le tableau suivant donnent lieu à une injection, en précisant s’il s’agit d’une injection SQL ou XSS.

  /{usr}/insert req.query.potatoes /{usr}/list
''); DROP TABLE toto      
'); DROP TABLE toto      
toto VALUES (''); DROP TABLE toto      
toto; DROP TABLE toto      
<script>alert('xss');</script>      
"; alert('xss');      
</h1> alert('xss');      
</li><script>alert('xss')</script>