Sujet première session 13 mai 2015
Rédigez la partie 1 (Côté client) sur une copie séparée. N’oubliez pas de mettre votre code barres sur chacune des copies.
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 (7 points)
On suppose que le client possède la feuille de style
./css/boites.css
suivante :
section {
border: thin black outset;
padding: 0px;
margin-bottom: 10px;
background-color: #eee; /* gris très clair */
}
section > h2:first-child {
padding: 0px;
margin: 0px;
background-color: #888; /* gris foncé */
color: white;
text-align: center;
}
.table2cols {
padding: 0px;
width: 500px;
border: 1px black dashed;
}
.table2cols td {
padding: 0px;
margin: 0px;
border: 1px black solid;
width: 50%;
text-align: center;
}
input, button {
/* Certains champs de formulaires ont le mauvais goût d'avoir
des bordures et un padding, ce qui complique inutilement
leur dimensionnement. Cette propriété CSS fait en sorte que
pour ces éléments, width et height incluent le padding et
la bordure. */
box-sizing: border-box;
}
HTML : 2 points
Ecrivez une page HTML 5 qui inclut cette feuille de style externe, qui l’utilise, et qui reproduit le contenu de l’encadré ci-dessous, tout en respectant les consignes suivantes :
- Ne définissez aucune autre règle de style supplémentaire (locale ou globale), et n’utilisez aucune balise de mise en forme.
- Donnez l’identifiant
todolist
à la liste numérotée dans la boîte “Ma TODO List”. - Attribuez la classe
actionbox
à la boîte “Actions”, qui contient les trois champs de formulaire. - Donnez respectivement les identifiants
todotext
,ajoutbtn
,erasebtn
aux trois champs de formulaire.
- Un premier truc
- Un second truc
- Un troisième truc
Lundi | Monday |
Mardi | Tuesday |
Mercredi | Wednesday |
Jeudi | Thursday |
CSS : 2 points
Note importante : Toutes les questions qui suivent necessitent entre 1 et 5 lignes de code maximum.
- Sans toucher au code html, ajouter une règle CSS de sorte que les champs de formulaires et les boutons qui sont dans la boîte Actions occupent désormais 100% de la largeur de la boîte et soient placés les uns au dessous des autres, comme dans l’encadré ci-dessous.
-
Ajouter une règle CSS pour la balise body de sorte que la largeur de son contenu soit 800px, entouré par une bordure bleue de 2pixels de large, un espace vide de 50pixels dans toutes les directions entre la bordure et le contenu, un espace de 10px en haut de la bordure, et un espace symmétrique à gauche et à droite de la bordure.
-
Ajouter des règles CSS qui changent la couleur de fond des lignes de la table des jours de la semaine : les lignes paires en blanc et les lignes impaires en gris clair (couleur
#ccc
) -
Ajouter une règle CSS qui met en gras et colore en rouge le texte des lignes de la table des jours de la semaine uniquement quand la souris passe dessus.
JS : 3 points
Note importante : Toutes les questions qui suivent necessitent entre 1 et 5 lignes de code JavaScript maximum. Vous avez le droit d’utiliser des frameworks (JQuery ou autres).
-
Ecrivez un gestionnaire d’évènements qui supprime tous les items de la TODO list lorsque l’on clique sur le bouton « Tout Effacer ».
-
Ecrivez un gestionnaire d’évènements qui ajoute ce que l’on a entré dans le champ de texte à TODO List quand on clique sur « Ajouter ». Efforcez-vous d’éviter les attaques XSS, injection html ou injection de script.
-
On souhaite écrire un gestionnaire d’événements qui supprime la ligne de la table des jours sur laquelle on clique. On suppose que chaque élément du DOM possède une methode
remove()
qui le supprime. On va choisir un gestionnaire d’évènement parmi les trois candidats suivants :
function removeRow_v1(event) {
event.target.remove();
}
function removeRow_v2(event) {
event.currentTarget.remove();
}
function removeRow_v3(event) {
var elem1 = event.target;
var elem2 = event.currentTarget;
if (elem1 === elem2) return;
while (elem1.parentNode !== elem2)
elem1 = elem1.parentNode;
elem1.remove();
}
précisez pour chacun s’il peut fonctionner, et si oui, à quel(s) élément(s) et à quel événement il faut l’attacher (donner la/les lignes JavaScript qui fait cela). Si un gestionnaire ne peut pas fonctionner correctement, préciser pourquoi.
Côté serveur – Express/Silex (7 points)
On considère une application web composée des deux gestionnaires suivants (donnés d’abord en Node.js, puis en Silex) :
app.get('/consulter', function(req, res) {
res.render('consulter.twig');
});
app.get('/inventaire', function(req, res) {
db.query('SELECT * FROM items WHERE name LIKE ? AND color=?',
[req.body.name, req.body.color],
function (err, rows) {
res.render('liste.twig', { 'items' : rows });
});
});
$app->get('/consulter', function(Application $app) {
return $app['twig']->render('consulter.twig');
});
$app->get('/inventaire', function(Application $app, Request $req) {
$rows = $app['db']->fetchAll(
'SELECT * FROM items WHERE name LIKE ? AND color=?',
[$req->request->get('name'), $req->request->get('color')]);
return $app['twig']->render('liste.twig', array('items' => $rows));
});
On donne aussi un extrait du code du template consulter.twig
:
<form method="get" action="/inventaire">
<input type="text" name="name">
<select name="color">
<option value="jaune">jaune</option>
<option value="rouge">rouge</option>
</select>
<input type="submit" value="Chercher">
</form>
et de liste.twig
:
<table>
{% for it in items %}
<tr>
<td>{{ it.name }}</td>
<td>{{ it.color }}</td>
<td>{{ it.size }}</td>
<td>{{ it.shape }}</td>
</tr>
{% endfor %}
</table>
Web 1.0 : 4 points
-
Il y a une erreur bête dans les gestionnaires. Trouvez-la et proposez une correction.
-
Que peut-on dire sur la structure de la table SQL
items
? -
L’utilisateur visite l’URL
/consulter
, remplit le champname
avec le texte « toto », choisit la couleur « rouge », et soumet le formulaire.Décrire la requête HTTP (URL et contenu) envoyée par le browser et le contenu de la réponse donnée par le serveur.
-
On définit une liste de couleurs permises dans un tableau global défini dans l’application. Par exemple, en JavaScript
var colors = ['jaune', 'rouge', 'vert', 'bleu'];
ou en PHP
$colors = array('jaune', 'rouge', 'vert', 'bleu');
Modifier le gestionnaire de
/consulter
et le templateconsulter.twig
pour que la liste des couleurs sélectionnables soit générée dynamiquement à partir du tableaucolors
.
AJAX : 3 points
-
Modifier le gestionnaire de
/inventaire
pour qu’il retourne les données au format JSON plutôt que dans une page HTML. -
Modifier le formulaire de
consulter.twig
pour que, à la pression du bouton, les données soient téléchargées de/inventaire
via une requête AJAX, et affichées dans la même page.Vous pouvez utiliser un framework (par ex. JQuery) pour construire la requête AJAX. Vous pouvez utiliser la fonction de bibliothèque suivante pour générer le tableau HTML.
function createTable(data) { var tab = docuement.createElement('table'); for (var i = 0; i < data.length; i++) { var ligne = document.createElement('tr'); ligne.innerHTML = "<td>" + data[i].name + "</td><td>" + data[i].color + "</td><td>" + data[i].size + "</td><td>" + data[i].shape + "</td>"; tab.appendChild(ligne); } return tab; }
Théorie et sécurité (7 points)
HTTP : 2 points
On Considère l’échange HTTP suivant (les requêtes sont alignées à gauche, les réponses à droite)
GET / HTTP/1.1
Host: www.example.com
Cookie: sessionid=123aef345ff90
HTTP/1.1 302 Found
Location: http://www.example.com/home
Set-Cookie: toto=titi
- Écrire la requête HTTP envoyée par le browser à la suite de cet
échange. Préciser, en particulier, le contenu des entêtes
Host
,Cookie
etReferer
.
Le serveur répond avec une nouvelle redirection :
HTTP/1.1 302 Found
Location: http://www.other.com/
- Même question qu’auparavant : Écrire la requête HTTP envoyée par le
browser. Préciser, en particulier, le contenu des entêtes
Host
,Cookie
etReferer
.
XSS : 2 points
On considère le template suivant
<html>
<head>
<script>
var name = "{{ name }}";
</script>
<script src="{{ user_script }}"></script>
</head>
<body>
<a href="{{ action | raw }}">Click me</a>
</body>
</html>
servi par la ligne de code (en PHP)
return $app['twig']->render('template.twig', array(
'name' => $req->request->name,
'user_script' => $req->request->user_script,
'action' => $req->request->action
));
ou bien (en Node.js)
res.render('template.twig', {
'name' : req.body.name,
'user_script' : req.body.user_script,
'action' : req.body.action
});
Pour chacune des chaînes suivantes, dire si elle permet de réaliser
une injection XSS, et dans ce cas à quelle(s) variable(s) (parmi
name
, user_script
et action
) elle peut être assignée pour mener
l’attaque :
"><script>alert('xss');</script>
,(function() { alert('xss'); })()
,https://www.evil.com/script.js
,";alert('xss')//
," alert('xss')//
,javascript:alert('xss')
.
Cross-domain policy : 3 points
L’URL http://www.example.com/
renvoie la page HTML suivante :
<html>
<head>
<link rel="stylesheet" href="style.css">
<link rel="alternate" type="application/atom+xml" href="feed.atom">
<script src="//some.api.com/maps.js"></script>
<script src="https://other.api.com/calendar.js"></script>
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://api.example.com/data.json");
xhr.responseType = "json";
xhr.send("hello");
function webbug() {
var img = new Image(0,0);
img.src = "img/chat.jpg";
document.body.appendChild(img);
}
sessionStorage.secret = 'toto';
</script>
</head>
<body onload="webbug">
<p><a href="/lorem/ipsum">Lorem ipsum</a>
<img src="img/chien.jpg"></p>
<iframe src="http://wiki.example.com/"></iframe>
<form method="get" action="https://identity.com/login">
<input type="submit">
</form>
</body>
</html>
-
Au moment du chargement de la page, quelles URLs sont automatiquement demandées par le browser ?
-
Quelles requêtes sont bloquées par des politiques de sécurité ? Quelles sont les politiques en question ?
-
Le script
maps.js
a-t-il accès à la valeur desessionStorage.secret
? Et le scriptcalendar.js
? Que change si la page est servie via HTTPS ? -
L’URL
https://wiki.example.com/
répond avec le code HTML suivant<html> <head> <script> console.log(sessionStorage.secret); </script> </head> <body> ... </body> </html>
Quelle valeur s’affiche dans la console JavaScript ?