[OSM-talk-fr] Bogue d'Osmose (codage XML invalide provenant du serveur Backend)

Frédéric Rodrigo fred.rodrigo at gmail.com
Ven 10 Fév 11:11:59 UTC 2012


Bonjour,
Sincèrement je n'ai pas tout lu (vraiment beaucoup trop long, tu
pourrais proposer un résumé de tes mails en introduction ;) ).
Mon dépôt osmose sur gitorious n'est pas vraiment une référence.
Regardes plutôt la branche dev de http://gitorious.org/osmose pour la
version de développement.

Frédéric

Le 10 février 2012 11:51, Philippe Verdy <verdy_p at wanadoo.fr> a écrit :
> Je viens de trouver un bogue dans Osmose, sur son serveur Backend.
>
> ==== Premier problème (le plus sérieux) ===
>
> Cela se situe ici:
>
> https://gitorious.org/~frodrigo/osmose/frodrigo-osmose-backend/blobs/master/modules/OsmSax.py
>
> Aux deux lignes suivantes du module SaxWriter lorsqu'il génère le code
> des valeurs d'attributs des élements XML :
>
> 369                 self._write(' %s=%s' % (name, quoteattr(value)))
> 378                 self._write(' %s=%s' % (name, quoteattr(value)))
>
> En effet, la fonction Python quoteattr() ne représente pas
> correctement le caractère "&" qu'il laisse sous cette forme, alors
> qu'il FAUT le réencoder sous la forme "&"
>
> La fonction quoteattr() est importée depuis le module Python
> "sax.saxutils", absent dans les sources GIT d'Osmose. C'est elle qui
> est ici en cause.
>
> Cela affecte la modification des éléments contenant un caractère "&"
> dans leur valeur (par exemple les relations contenant un tag "url", ou
> certains tags "name" parfaitement valides).
>
> L'effet de ce bogue est que le XML reçu par le client et éditable par
> "rawedit" est invalide, et ne peut pas être revalidé tel quel !
> Sinon on reçoit un message affiché en rouge en haut de l'écran
> rawedit: "XML parser can't parse this data", et les données ne sont
> pas enregistrées.
>
> Pour contourner le problème, il faut soit même corriger le code XML
> qui a été reçu en remplaçant les "&" affichés dans l'éditeur dans les
> valeurs de tags par "&" avant de valider, même si on n'a pas
> réellement touché à la valeur.
>
> Le risque subsiste que même sans y toucher, l'absence de modification
> manuelle pour faire la correction risque parfois d'être acceptés comme
> du XML valide (par exemple quand un "&" littéral est suivi de
> quelquechose qui ressemble à une référence numérique de caractère ou
> une référene d'entité XML définie dans le schéma XML utilisé), ce qui
> corrompra les données qui n'avaient pas lieu d'être modifiées.
>
> Je ne sais pas si c'est la fonction quoteattr() du module sax.saxutils
> qui devrait être corrigée, ou si une autre fonction devrait plutôt
> être définie ou utilisée ici, ou si un paramètre supplémentaire
> optionnel de quoteattr() permet de préciser la conformité avec XML
> (car quoteattr() n'est pas obligé de remplacer ces "&" si la fonction
> est utilisée pour générer du HTML ou du SGML): dans ce cas il faut
> passer ce paramètre oublié.
>
> A ce sujet, quoteattr() recode toutes les apostrophes ASCII (') sous
> la forme ' alors que c'est inutile (et peu lisible) ici, étant
> donné que la chaine retournée sera encadrée de guillemets doubles
> ASCII ("). En revanche les quatre caractères suivants doivent être mis
> sous forme de référence à une des quatre seules entité de caractères
> XML prédéfinie :
>
> - les guillemets doubles ASCII (") sous la forme "
> - le signe inférieur (<) sous la forme <
> - le signe supérieur (>) sous la forme >
> - le signe et commercial (&) sous la forme &
>
> Et c'est tout ! Tout le reste peut (et devrait) rester sous leur forme
> littérale (même l'apostrophe ici, bien que XML prédéfinisse aussi une
> cinquième entité "'" puisque la syntaxe XML permet aussi aux
> valeurs d'attributs d'être encadrées par des apostrophes ASCII au lieu
> de guillemets ASCII).
>
>
> ==== Deuxième problème (lié au premier) ===
>
> Enfin je note que le code Javascript envoyé au client utilise le
> constructeur: new XMLHttpRequest(), mais sans préciser le jeu de
> caractères qui sera utilisé pour dialoguer avec le serveur :
>
>  function ApiDo(action)
>  {
>    var myReq = new XMLHttpRequest();
>    if (myReq) {
>      myReq.onreadystatechange = function (evnt) { if(myReq.readyState == 4) {
>        res = myReq.responseText.split('\n');
>        document.getElementById('osm_msg').innerHTML = res[0];
>        tmp = res.shift();
>        document.getElementById('osm_data').value    = res.join('\n');
>        } }
>      myReq.open('POST', '/' + action + '/' + osm_type + '/' + osm_id, true);
>      myReq.setRequestHeader("Content-type",
> "application/x-www-form-urlencoded");
>      poststr = "osm_data=" +
> encodeURIComponent(document.getElementById("osm_data").value );
>      myReq.send(poststr);
>    }
>  }
>
> Rien n'oblige actuellement le navigateur à supposer que cette requête
> se fera en codage UTF-8, même si la page web et le code javascript
> sont eux-même codés en UTF-8. Dans les faits, cette requête telle
> qu'elle est envoyée au serveur ne précise rien du tout, ce qui demande
> alors que les données incluses dans la valeur "osm_data=" ne soient
> que de l'ASCII pur.
>
> Ici le problème est que pour s'assurer que ce sera uniquement de
> l'ASCII, ce javascript utilise encodeURIComponent(), dont le
> comportement dépend du navigateur : la source est bien de l'UTF-16,
> son résultat sera bien de l'ASCII compatible avec une syntaxe de
> composant URI, mais asolument rien n'indique dans quel jeu de
> caractères se fera la conversion de la chaine source UTF-16 vers un
> jeu restreint à 8 bits (avant ensuite de convertir les espaces ASCII
> sous la forme "+", et les octets non ASCII et non imprimables ou
> réservés par la syntaxe des URI sous la forme "%nn").
>
> En effet, le constructeur XMLHttpRequest crée un nouveau document
> totalement séparé du document source (hormi son domaine de sécurité)
> et communique même avec un serveur backend distinct du serveur
> frontend affichant la carte Osmose et l'interface d'édition. Il n'y a
> strictement rien dans le code qui indique que le backend utilise
> UTF-8, et cela pourrait expliquer pourquoi la base OSM contient
> maintenant des caractères mal réencodés (il suffit par exemple qu'un
> utilisateur utilise un navigateur configuré tel que UTF-8 n'est pas
> son codage par défaut, mais utilise par défaut ISO-8859-1,
> Windows-1252 voire aussi Mac-Roman).
>
> Il faudrait donc que le javascript précise bien le codage utilisé
> avant de les mettre dans les données qu'il envoie en POST-Data dans la
> valeur "osmdata", sous forme URL-encodée (même si la requête ici
> indique au serveur que les données sont supposées bien être au format
> "application/x-www-form-urlencoded", cela ne dispense pas le
> javascript de coder correctement sour cette forme).
>
> Ce problème existe même avec les navigateurs récents, pour peu que
> l'utilisateur n'a pas configuré son navigateur pour utiliser UTF-8
> comme codage par défaut, et selon d'autres réglages possibles de la
> façon d'interpréter les URI présentes dans de vieilles pages HTML non
> conformes XML/XHTML ni HTML5.
>
> Il n'est pas inintéressant de lire la doc officielle de la norme
> ECMAScript au sujet des mises en garde sur l'effet et la compatibilité
> de la fonction encodeURIComponent(), dès lors que la chaîne source en
> paramètre ne contient PAS UNIQUEMENT des caractères ASCII mais
> n'importe quel autre "caractère"
>
>
> === Note 1 : question de compatiblité des chaines en Javascript/ECMAScript ===
>
> Note : les "caractères" en Javascript, ceux qu'on énumère dans une
> chaine avec la méthode .charAt(n), ou qu'on compte avec la méthode
> .length(), ne sont PAS les caractères au sens Unicode, mais seulement
> des "unités de code" arbitraires sur 16 bits.
>
> Javascript n'oblige même pas en fait à ce que ses chaines soit
> nécessairement codées de façon interne en UTF-16, car ce pourrait
> aussi bien être un codage JIS sur 16 bits, voire n'importe quelle
> valeur binaire non textuelle, comme aussi en Java : il est
> parfaitement valide en Javascript d'insérer des codets nuls dans ces
> "chaines" ou un codet égal à 0xFFFF, qui ne correspond à rien de
> valide en UTF-16, ou encode d'y mettre un codet égal à 0xD800 isolé
> non suivi d'un codet entre 0xDC00 et DFFF, là encore invalide en
> UTF-16, et les chaines Javascript font la distinction entre différents
> codages de sauts de lignes. Javascript initialement n'obligeait même
> pas à ce que son codage interne soit avec des unités de code sur au
> moins 16 bits (ce n'est plus le cas depuis la norme ECMAScript qui
> précise bien que ces unités de code DOIVENT être sur 16 bits, mais
> n'oblige toujours pas à ce que ce soit uniquement de l'UTF-16 valide).
>
> Bref attention à la fonction encodeURIComponent(string) ! Lire à ce
> sujet ce qui a été fait dans jQuery pour résoudre ce problème de
> compatibilité entre navigateurs et selon leur configuration: je
> suggère donc d'utiliser jQuery dans le frontend, car il résoud bien
> des difficultés, et fournit une bibliothèque standard pour effectuer
> des requêtes XML fiables avec un serveur backend.
>
>
> === Note 2 : XMLHTtpRequest, et suggestion pour la sécurité ===
>
> D'ailleurs le constructeur XMLHtppRequest() a aussi des problèmes de
> sécurité répertoriés, comme aussi des problèmes mieux connus de
> compatiblité avec différents types de navigateurs.
>
> jQuery fournit une solution stable et sure, et même les organismes de
> surveillance de la sécurité sur le web recommandent de ne plus
> l'utiliser du tout et de passer aux requêtes JSON dès que possible car
> elles incluent une implémentation native avec des contraintes bien
> plus forte de sécurité (qui évitent par exemple des attaques de type
> "XSS", Cross-Site Scripting, ou des attaques directement sur la
> plateforme native du navigateur client, surtout avec les vieilles
> versions d'Internet Explorer où XMLHttpRequest n'existait que par un
> composant externe ActiveX).
>
> _______________________________________________
> Talk-fr mailing list
> Talk-fr at openstreetmap.org
> http://lists.openstreetmap.org/listinfo/talk-fr




Plus d'informations sur la liste de diffusion Talk-fr