La notion d'hyperlien est centrale dans un wiki :
- une page est, idéalement, créée par un lien et n'a, en théorie du moins, aucune autonomie propre
- une syntaxe très simple permet de créer immédiatement un lien vers une autre page
- d'autres syntaxes permettent de créer simplement des liens externes ou des liens vers des sites connus, dits "liens interwikis"
Nous allons ici spécifier clairement la syntaxe des liens reconnus par
WikiNi.
Il faut faire une distinction soigneuse entre :
- les chaines de caractères reconnues par WikiNi comme des liens :
- ces chaines sont transformées par le code HTML <a href="/lien">lien</a>
- ces chaines sont analysées dans /formatter/wakka.php
- ce que WikiNi accepte de créer comme nom de page dans sa base de données
- ces chaines sont envoyées par le navigateur lorsque l'utilisateur clique sur un lien ou qu'il entre l'adresse dans le navigateur
- ces chaines sont traitées dans /wakka.php
Un nom peut être reconnu comme un lien sans pour autant être une chaine valide pour être créé dans la base de données.
1. Liens internes au site
1.1. Motifs reconnus comme des liens
Les
MotsWiki ont été l'une des innovations qui ont accompagné la naissance des wikis. Il s'agit d'une manière simplifiée de créer un lien, sans connaissance technique, en collant deux ou plusieurs mots l'un à l'autre. Certains wikis, comme wikipédia, les ont abandonné mais ils jouissent encore d'un succès.
WikiNi reconnait les
MotsWikis? ; si nous pouvons envisager d'autres techniques de fabrication de liens, et d'autres noms de page que les mots wikis, nous les conserveront sans doute au moins au titre de la compatibilité ascendante.
Les
MotsWiki sont actuellement reconnus dans
WikiNi (0.4.1) par l'expression rationnelle suivante (/formatters/wakka.php) :
^[A-Z][a-z]+[A-Z,0-9][A-Z,a-z,0-9]*$
C'est à dire un ensemble de caractères :
- commençant obligatoirement par une lettre majuscule,
- suivie de une ou plusieurs lettres minuscules,
- suivie(s) d'une lettre majuscule ou d'un chiffre,
- éventuellement suivi d'une ou plusieurs lettres ou chiffres.
Soit par exemple :
- AaAA?
- Aa11?
- Aa1a?
- AaAa?
- AaA?
- Aa1?
Ne fonctionnent pas :
Note : il y a, jusqu'à la version 0.4.1 inclue, un bug qui autorise d'utiliser des virgules dans les MotsWiki ; ceci sera corrigé dans les prochaines versions. -- ProgFou
Note 2 : il existe une limite de 50 caractères dans la base de données, mais pas dans le corps du script ! ce qui fait qu'un mot wiki de plus de 50 caractères est bien reconnu comme un MotWiki mais la page créée à partir de ce mot est elle limitée à 50 caractères (cf. TestsDeMotsWiki). Pour corriger ce problème, il faudrait :
- soit limiter la création de liens à des MotsWiki de 50 caractères maxi (ce qui n'empécherait pas les gens d'entrer à la main dans leur navigateur des URLs contenant un mot wiki de plus de 50 caractères)
- soit renvoyer une erreur explicite dans le cas d'une requête contenant un MotWiki de plus de 50 caractères (ce qui paraît être la meilleure solution)
-- CharlesNepote d'après ProgFou
Je propose d'appliquer la solution a) pour les raisons suivantes :
- ce n'est pas la peine de laisser entendre à l'utilisateur qu'il va pouvoir créer la page alors que ce n'est pas possible
- ça évite à l'utilisateur de se retrouver devant un message d'erreur
On verra les
TestsDeMotsWiki.
[à compléter]
Liens forcés (internes)
Les liens forcés sont utilisés pour deux raisons :
- soit pour changer l'intitulé d'un MotWiki : [[PagePrincipale Page d'accueil]] donne le lien : Page d'accueil
- soit pour faire référence à ou créer une page dont le nom n'est pas un MotWiki : [[SVG]] donne le lien SVG, bien que la chaine SVG ne soit pas un MotWiki.
Dans les versions 0.4.1 et inférieures,
WikiNi :
- reconnait comme lien n'importe quelle chaine (nombre de caractères en apparence illimité) du moment qu'elle soit entre deux crochets ;
- dans formatters/wakka.php, l'expression rationnelle permettant de les détecter est ainsi faite :
- ^\[\[(\S*)(\s+(.+))?\]\]$ c'est à dire :
- un ensemble de groupes de caractères
- séparés par des "blancs" (espace, tabulation, ...) ;
Par exemple :
- [[PagePrincipale Page principale]]
- [[dsqdqsf q$#fs{d@]]
Note : le '\s' représente un caractère "blanc" et '\S' représente l'inverse (tous les autres caractères). -- ProgFou
1.2. Motifs acceptés pour la création d'une page
Dans les versions 0.4.1 et inférieures,
WikiNi peut créer des pages de n'importe quel nom de moins de 50 caractères, créant ainsi des problèmes de sécurité ;
- la fonction SavePage() de /wakka.php ne fait pas de contrôle sur ce qui est sauvegardé
- dans /wakka.php, c'est le traitement "// split into page/method" qui récupère les arguments passés en paramètres de la requete HTTP. En l'occurence, l'expression rationnelle suivante indique ce qui est pris en compte dans ce traitement :
- par ailleurs, les noms de pages sont parfois affichés bruts dans le code HTML généré par WikiNi, provoquant alors un trou de sécurité
Note : la limite des 50 caractères est dans la base, mais pas dans le corps du script ! -- ProgFou
Ces fonctionnalités ont d'ailleurs donné lieu à la création de pages aux noms étranges qu'il conviendra peut-être de renommer :
(On peut voir toutes ces pages dans l'
IndexDesPagesBis.)
Proposition 1 : reconnaitre les caractères alphanumériques + le signe "_"
Dans les versions 0.4.2 et 0.5.0 nous proposons de corriger ce problème.
WikiNi :
- reconnaitrait toujours comme lien n'importe quelle chaine du moment qu'elle soit entre deux crochets (?) ;
- ne pourrait créer des pages que selon la syntaxe suivante : un caractère alphanumérique suivi d'au plus : 50 caractères alphanumériques ou le signe "_", ce qui donnerait l'expression rationnelle suivante (à intégrer dans la section "// split into page/method" dans /wakka.php) :
- /^[A-Za-z0-9][A-Za-z0-9_]{0,49}$/ (à vérifier)
Note : il n'est pas permis à un nom de page de commencer par un "_". -- CharlesNepote
Le code à modifier /wakka.php donne donc bien (j'ai testé) :
// Split into page/method
// (Note : it test if the wiki name doesn't contain some characters that should permit an XSS)
if (preg_match("#^([A-Za-z0-9][A-Za-z0-9_]{0,49})/([A-Za-z0-9_]*)$#", $wiki, $matches)) list(, $page, $method) = $matches;
else if (preg_match("#^([A-Za-z0-9][A-Za-z0-9_]{0,49})$#", $wiki, $matches)) list(, $page) = $matches;
else
{
echo "Interdit !";
exit;
}
--
CharlesNepote
Proposition 2 : reconnaitre tous les caractères
A la réflexion, d'un point de vue fonctionnel, tous les caractères devraient pouvoir être candidats à faire partie d'un nom de page. Chaque page d'un wiki représente un document ; à ce titre, une page titrée
<script>alert(document.name)</script> doit être possible.
D'un point de vue technique, il ne faut pas que le HTML généré par
WikiNi contienne du code non désirable interprétable par le navigateur : un nom de page doit rester un nom de page et non devenir un code exécutable. Il faut donc, à chaque affichage du nom d'une page, faire en sorte qu'il ne soit pas affiché de façon brute mais encodé à l'aide la fonction
htmlentites().
Je propose donc de lister tous les endroits susceptibles d'afficher le nom d'une page pour voir tous les endroits à modifier et évaluer comment les modifier :
- /actions/header.php : <?php echo $this->GetPageTag?(); ?>
- ...
(Dans la partie "Split into page/method", il ne suffirait donc plus que de limiter le nombre de caractères à 50.)
Sur le principe, cette solution a ma préférence.
--
CharlesNepote
2. Liens interwikis
Actuellement (version <= 0.4.1) :
dans
formatters/wakka.php :
^[A-Z][A-Z,a-z]+[:][A-Z,a-z,0-9]*$
Prochainement (version > 0.4.1) :
dans
formatters/wakka.php :
^[A-Z][A-Za-z0-9]+[:][A-Za-z0-9-_]*$
Note de CharlesNepote : étant donné que les liens interwikis concernent aussi des sites qui ne sont pas des wikis (exemple : RFC) ou bien même des wikis qui gèrent des possibilités de caractères plus étendues (exemple PhpWiki qui gère les liens caractères accentués (cf. CraoWiki)), pourquoi se limiter à [A-Za-z0-9-_] ?
- Je mettais ça par rapport à ce qui est déjà dans la future 0.5.0. Mais effectivement, je suis d'accord avec ta remarque : autant autoriser un maximum possible en partie droite du lien interwiki. Je propose que soit accepté n'importe quel caractère valide pour une URL et que la chaîne fournie soit passée telle quelle comme URL du lien. Une alternative étant d'accepter n'importe quel caractère (sauf espace puisque cela sert à séparer le lien de son intitulé) et de faire un urlencode sur la chaîne fournie, mais cette méthode ne permettrait pas d'avoir un espace dans un lien (puisqu'un %20 serait recodé en %2520). -- ProgFou
- Je préfère la deuxième solution (urlencodée) qui donnerai donc ^[A-Z][A-Za-z0-9]+[:]\S*$ (\S correspond à tout caractère sauf un espace). -- CharlesNepote
Note : attention, il ne faut pas que la partie après les deux points puisse commencer par //.
[à compléter]
3. Liens externes au site
[à réécrire]
Actuellement (version <= 0.4.3) :
dans
formatters/wakka.php :
^([a-z]+:\/\/\S+?)([^[A-Za-z0-9]^\/])?$
[à compléter]
Attention,
^([a-z]+: pose des problèmes car il permet
javascript://xxx .
Il faut donc pouvoir affiner cette partie. Je vois deux pistes.
1. Filtre positif : on n'accepte que des protocoles duement identifiés.
Cela donnerait quelquechose du genre :
^(http|https|ftp|ftps|gopher|irc|file|nfs):
2. Filtre négatif : on accepte tout sauf ce que l'on sait être dangereux.
Cela donnerait quelquechose du genre :
^([a-z]+|^javascript|^jscript|^script):
Le motif est reconnu dans
/formatters/wakka.php par l'expression
\b[[:lower:]]+:\/\/\S+ qui signifie :
- \b : limite d'un mot, c'est-à-dire [?]
- [[:lower:]]+ : toute suite de caractères en minuscule
- :\/\/ : la séquence de caractères ://
- \S+ : tout caractère différent de \s, ce dernier correspondant à n'importe quel blanc : espace, tabulation horizontale (\t), tabulation verticale (\v), nouvelle ligne (\n), retour charriot (\r) et nouvelle page (\f) (note : je ne suis pas sûr que \v et \f soient utilisés en PHP).
Or, ce motif, pour isoler correctement une url ne devraient pas reconnaître les caractères donnés comme "unsafe" par la RFC 1738 :
- le guillement simple : "
- "{", "}", "|", "\", "^", "~", "[", "]", and "`".
Note : les signes "%" et "#", notés "unsafe" sont particuliers dans le sens où ils sont utilisés comme caractères ayant une valeur sémantique dans l'URL : le "#" représente une ancre et "%" permet d'encoder d'autres caractères. Ces deux signes doivent donc êtres reconnus par
WikiNi.
Annexe 1 : note sur l'encodage des liens
Tant que l'on utilise des liens qui contiennent des caractères alphanumériques non accentués, il n'y a pas de problèmes.
Mais si nous souhaitons utiliser des caractères accentués ou des caractères non permis par la norme, il faut alors encoder les caractères (cf. fonction PHP urlencode) et éventuellement les décoder à la réception des URL (cf. fonction PHP
urldecode).
Annexe 2 : liens qui seraient dangereux
Pour éviter qu'un lien soit dangereux, il faut éviter que ce dernier puisse s'exécuter côté client, sur le navigateur de l'internaute.
Exemples de liens dangeureux :
- <a href="javascript:void(alert('Yep_Yep_j\'aurais_pu_transmettre_'+document.cookie))">Lien</a>
- <a href="http://www.wikini.net/wakka.php?wiki=%3Cscript%3Ealert(document.cookie);%3C/script%3E">Lien</a>
Note : j'y ai pensé aussi, mais je me suis dit qu'on pouvait de toutes façons le faire via du HTML pur (entre double-guillemets), donc... -- ProgFou
Note : Au sujet des doubles guillemets, on pourrait faire un option de WikiNi pour deux interprétations possibles : texte pur sans conversion (=> complètement ouvert) ou bien texte non interprété mais recodé pour s'afficher tel que saisis (=> fermé à l'interprétation HTML) via un fonction telle que htmlentities. -- ProgFou
- Oui. Il me paraît important de développer une telle fonctionnalité et de l'activer par défaut. Les gens qui utilisent WikiNi ont souvent peu de connaissances techniques et doivent pourvoir être protégés par défaut. -- CharlesNepote
Annexe 3 : références