Un chercheur trouve une méthode CSS pour suivre les mouvements de la souris,
qui pourrait être une méthode pour pister les internautes avec JS désactivé
Alors que les utilisateurs sont de plus en plus préoccupés par la qualité de la protection de leur vie privée et le pistage en ligne, ils ont commencé à utiliser des bloqueurs de publicité et des bloqueurs de script afin de bloquer les scripts de suivi JavaScript. Une nouvelle méthode a été découverte qui permet à un site de suivre les mouvements de la souris de ses visiteurs en utilisant uniquement HTML et CSS, ce qui peut contourner la protection érigée contre le pistage en ligne.
La plupart des suivis en ligne sont effectués à l'aide de scripts JavaScript chargés dans des sites Web et des publicités. Cela permet aux annonceurs et aux sites de savoir où vous allez sur le Web, comment vous utilisez un site ou tout autre comportement en ligne.
Ces scripts peuvent être bloqués à l'aide de bloqueurs de publicité, de l’activation de protection du suivi du navigateur comme Content Blocking de Firefox ou même le blocage de JavaScript.
Un chercheur a trouvé une nouvelle méthode permettant de suivre les mouvements de la souris d'un visiteur d'un site Web sur une page sans utiliser de code JavaScript, mais en utilisant uniquement le langage HTML et CSS. Cela rend très difficile le blocage du suivi effectué de cette manière.
Le chercheur en sécurité Davy Wybiral a récemment montré sur Twitter comment les sites Web peuvent utiliser HTML et CSS pour surveiller les mouvements de la souris se produisant dans une fenêtre du navigateur à partir d'une autre fenêtre du navigateur.
Wybiral a pu le faire en créant une grille de DIV HTML utilisant des sélecteurs CSS :hover pour demander une nouvelle image d’arrière-plan lorsque votre souris passe au-dessus d’un champ de la grille. Comme les demandes d'images sont effectuées en arrière-plan, le navigateur n'indique pas qu'ils sont en train d'établir une connexion. Par conséquent, toutes les demandes sont masquées à l'utilisateur.
Lorsqu'un utilisateur survole une boîte et qu'une nouvelle image d'arrière-plan est demandée, le script enregistre l'emplacement sur la grille survolé. Un utilisateur d'un autre navigateur peut ensuite utiliser l'URL /watch pour surveiller en temps réel la zone survolée.
« Il m'est apparu que vous pouviez surveiller à distance la position du curseur sans JS en utilisant des sélecteurs CSS :hover pour modifier les images d'arrière-plan masquées (provoquant une demande GET).
« Cela devrait également fonctionner sur Tor et pourrait constituer une approche intéressante pour suivre les visiteurs ». .
Pour mémoire, la pseudo-classe :hover permet de spécifier l'apparence d'un élément au moment où l'utilisateur le survole avec le pointeur, sans nécessairement l'activer.
Code CSS : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 /* Cible n'importe quel élément <a> lorsque */ /* celui-ci est survolé */ a:hover { background-color: gold; }
La mise en forme ciblée par cette pseudo-classe peut être surchargée par d'autres pseudo-classes relatives aux liens hypertextes comme :link, :visited, et :active, apparaissant dans des règles subséquentes. Pour décorer les liens sans effet de bord problématique, on placera la règle :hover après les règles :link et :visited mais avant la règle :active (l'ordre est :link — :visited — :hover — :active – un moyen mnémotechnique est de se souvenir des initiales LVHA) tandis que l'ordre de la règle :focus est indifférent.
La pseudo-classe :hover peut être appliquée à n'importe quel pseudo-élément.
La technique décrite par le chercheur peut être utilisée pour diverses raisons, notamment la détermination des zones qui suscitent le plus d’intérêts sur un site ou pour des études d'interface utilisateur.
Selon Wybiral, cette méthode peut être utile pour les tâches suivantes:
- l'analyse du mouvement, qui est un domaine de recherche actif
- déterminer les différentes positions de repos pour le curseur
- identifier le mouvement de la souris par rapport au touchpad devrait être possible
- peut donner un aperçu d'autres traits de comportement des visiteurs
Le chercheur a également indiqué que le sélecteur de survol n’est pas le seul à pouvoir être utilisé pour suivre le comportement du navigateur.
« En plus du suivi de la souris, de nombreux autres sélecteurs CSS pourraient donner des analyses pour le comportement de navigation. :focus, par exemple, devrait pouvoir contrôler les éléments sur lesquels l'utilisateur a le focus actif, et le sélecteur [value] est connu depuis un certain temps pour pouvoir interroger efficacement un élément d'entrée. Les règles autour de [value] ont été modifiées pour le rendre moins puissant, mais elles peuvent probablement toujours être utilisées simplement pour indiquer si l'utilisateur a commencé à taper ou si quelque chose a changé (je n’ai pas encore fait de PoC dessus, mais cela devrait être possible) ».
Pour rappel, la pseudo-classe :focus permet de cibler un élément lorsque celui-ci reçoit le focus (soit il est sélectionné à l'aide du clavier, soit il est activé avec la souris comme par exemple le champ d'un formulaire).
Code CSS : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 /* Cible n'importe quel élément <input> */ /* uniquement lorsqu'il a le focus */ input:focus { color: red; }
Cette pseudo-classe ne s'applique qu'aux éléments avec le focus, elle ne s'applique pas à ses parents (comme :checked, :enabled mais pas comme :active ou :hover).
La méthode de Wybiral n’est pas la seule à montrer comment CSS et HTML peuvent être utilisés pour suivre les utilisateurs sur des sites Web.
L'année dernière, un projet intitulé CrookedStyleSheets a été publié. Il permet aux sites de rassembler des informations telles que la résolution de l'écran, le navigateur utilisé, lorsqu'un utilisateur clique sur un lien et éventuellement le système d'exploitation utilisé en fonction des polices prises en charge.
Tout comme la méthode de Wybiral, tout est fait avec HTML et CSS. Elle n’utilise pas de JavaScript.
Pour ceux qui sont intéressés par le code du script de Wybiral, le voici
Regarder la vidéo de démonstration
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 // Tracking cursor position in real-time without JavaScript package main import ( "fmt" "net/http" "strings" ) const W = 50 const H = 50 var ch chan string const head = `<head> <style> *{margin:0;padding:0} html,body{width:100%;height:100%} p{ width:10px; height:10px; display:inline-block; border-right:1px solid #666; border-bottom:1px solid #666 } </style> </head>` func main() { ch = make(chan string) http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } func handler(w http.ResponseWriter, r *http.Request) { p := r.URL.Path if p == "/" { index(w, r) return } else if p == "/watch" { watch(w, r) return } else { if strings.HasPrefix(p, "/c") && strings.HasSuffix(p, ".png") { ch <- p[1 : len(p)-4] } } } func index(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") flusher, ok := w.(http.Flusher) if !ok { return } w.Write([]byte(head)) flusher.Flush() // Send <p> grid w.Write([]byte("<body>\n")) for i := 0; i < H; i++ { w.Write([]byte("<div>")) for j := 0; j < W; j++ { w.Write([]byte(fmt.Sprintf("<p id=\"c%dx%d\"></p>", i, j))) } w.Write([]byte("</div>\n")) } w.Write([]byte("</body>\n")) flusher.Flush() // Send CSS w.Write([]byte("<style>")) for i := 0; i < H; i++ { for j := 0; j < W; j++ { id := fmt.Sprintf("c%dx%d", i, j) s := fmt.Sprintf("#%s:hover{background:url(\"%s.png\")}", id, id) w.Write([]byte(s)) } } w.Write([]byte("</style>")) flusher.Flush() } func watch(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") flusher, ok := w.(http.Flusher) if !ok { return } w.Write([]byte(head)) flusher.Flush() // Send <p> grid w.Write([]byte("<body>\n")) for i := 0; i < H; i++ { w.Write([]byte("<div>")) for j := 0; j < W; j++ { w.Write([]byte(fmt.Sprintf("<p id=\"c%dx%d\"></p>", i, j))) } w.Write([]byte("</div>\n")) } w.Write([]byte("</body>\n")) flusher.Flush() // Listen to ch for updates and write to response for p := range ch { s := fmt.Sprintf("<style>#%s{background:#000}</style>\n", p) _, err := w.Write([]byte(s)) if err != nil { return } flusher.Flush() } }
Source : twitter, GitHub
Et vous ?
Que pensez-vous de sa méthode ?
Partager