&mymail;"> ]> p4bl0's blog > Protection d'email contre le spam en XHTML

Protection d'email contre le spam en XHTML

Vous le savez, il ne faut jamais laisser une adresse email en clair sur une page web si on ne veut pas qu'un spambot la repère et que sa boîte de réception soit envahie de spams en tout genres.

EDIT (2010-10-10) : Allez aussi lire l'article de Gabriel Hautclocq.

Les solutions couramment utiliser pour contourner ce problème sont de remplacer le @ par [at], ou de mettre son adresse email sur une image par exemple.
Mais la première ne marche pas très bien : c'est facile de dire à un programme de détecter aussi bien les [at], _at_ et compagnie que les @.
Quand à la seconde méthode elle n'est pas pratique car il n'est du coup pas possible pour les visiteurs de copier-coller l'adresse email.
Une autre solutions est d'utiliser un JavaScript. C'est ce que j'ai fait jusqu'à maintenant. Mon adresse email n'apparait que dans dans un fichier .js et y est encodé en ROT13. Je l'affiche avec une fonction qui décode l'adresse sur le coup. Cette méthode viens du blog de Allan Odgaard.
Le code JavaScript de la fonction avec mon adresse email est :
 → Code : adresse email encodée en ROT13
  1 
  2 
  3 
  4 
function encoded_email (elem_id) { var email = document.createTextNode("cnoyb.enhml@tznvy.pbz".replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);})); document.getElementById(elem_id).appendChild(email); }
Sauf que comme c'est du JavaScript, il y a des gens chez qui ça ne marchera pas : JavaScript désactivé, navigateurs incompatibles...

La méthode des entités XML

Si vos pages sont en XHTML, et donc basée sur XML et non SGML, vous pouvez étendre un peu la DTD de XHTML pour y ajouter des entités.
Une entité XML c'est quoi ?
Une entité XML est une sorte de raccourci vers une chaîne de caractère prédéfinie, il y en a déjà cinq de déclaré dans XML :
  • &lt; pour <
  • &gt; pour >
  • &amp; pour &
  • &quot; pour "
  • &apos; pour '
À ces cinq là viennent s'ajouter toutes les entités HTML comme par exemple les caractères spéciaux (&eacute; pour é...).
Et bien c'est ce que nous allons utiliser pour protéger notre adresse email. Une fois cette protection mise en place il suffira d'écrire &contact; pour afficher notre adresse email avec un lien mailto: !
Comment étendre la DTD de XHTML ?
Cela se fait au moment de la déclaration du DOCTYPE au début de votre fichier. Par exemple pour XHTML 1.1, le DOCTYPE est le suivant :
 → Code : DOCTYPE de XHTML 1.1
  1 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
Pour l'étendre il suffit de mettre ses ajouts à la fin de la balise DOCTYPE entre crochets.
Une entité se déclare en utilisant la syntaxe suivante :
 → Code : syntaxe de déclaration d'une entité dans une DTD
  1 
<!ENTITY entity-name "entity-value">
Pour que notre adresse email ne soit en claire nulle par il faut déclarer trois entités : la première contiendra la partie locale de l'adresse email, la seconde son nom de domaine, et enfin la troisième et dernière sera &contact;.
Par exemple pour moi ça donne :
 → Code : exemple de déclarations des trois entités
  1 
  2 
  3 
<!ENTITY myname "pablo.rauzy"> <!ENTITY gmail "gmail.com"> <!ENTITY contact "<a href='mailto:&myname;@&gmail;'>&myname;@&gmail;</a>">
Il suffit donc maintenant de placer ce code au bon endroit dans la page, c'est à dire comme on l'a vu plus tôt : à la fin de la balise DOCTYPE entre crochets.
Donc au final on a le code suivant :
 → Code : extension de la DTD
  1 
  2 
  3 
  4 
  5 
  6 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [ <!ENTITY myname "pablo.rauzy"> <!ENTITY gmail "gmail.com"> <!ENTITY contact "<a href='mailto:&myname;@&gmail;'>&myname;@&gmail;</a>"> ]>

Et voilà le travail ! Maintenant il vous suffit d'utiliser l'entité &contact; pour afficher un lien vers votre adresse email : &contact;.
Ce lien s'affiche bien alors que j'ai juste écris &contact;, vous pouvez le voir dans la source de la page (par contre comme une grosse partie est générée par PHP donc l'indentation du code est plus que foireuse :-p).

Vous pouvez bien sûr utiliser cette technique pour plein d'autres choses. &logo; pourrait afficher un petit logo, &truc; pourrait afficher un truc (si si !)... On peut aussi s'en servir pour les éléments de présentations : &separateur; pourrait être /, -, |, • selon votre humeur par exemple :-p. Un autre exemple d'utilisation tout bête : &message.info; affiche un message d'information qu'on peut modifier à un endroit seulement (la déclaration de l'entité) et qui sera automatiquement mis à jour partout sur le site :-)
Tags : développement web, javascript, xml | 9 commentaires | #103 | Trackback

Commentaires

Ombre :

Le 13 Juillet 2007 à 11:37
Salut,

Personellement, j'ai utilisé le code html suivant :

&lt;span class="email"&gt;&lt;span class="p"&gt;Pseudo&lt;/span&gt; &lt;span class="u"&gt;nom&lt;/span&gt;(arobase)&lt;span class="h"&gt;founiseur&lt;/span&gt;(point)&lt;span class="d"&gt;fr&lt;/span&gt;&lt;/span&gt;


Avec ce script, pour le livre d'or du site de MamaCass. Ça a l'air de fonctionner. ;-)

Et c'est accessible aussi... ;-)
Dans le cas d'un livre d'or effectivement il est impossible d'utiliser cette technique. C'est juste pour une ou quelques adresses email prédéfinie, pas celles entrées par des visiteurs : là il faut utiliser une autre stratégie, moi je ne l'affiche pas du tout.
Par contre la phrase qui m'a fait quelque chose c'est Et c'est accessible aussi..., parce que (j'ai honte) je n'y avais pas du tout pensé, tout content que j'étais d'avoir trouvé cette méthode.

Ombre :

Le 13 Juillet 2007 à 11:44
C'est vrai qu'il n'y a pas le lien comme toi quand javascript est désactivé mais ça reste lisible et les gens comprennent directement de quoi il s'agit. En plus je ne peux pas faire autrement dans le cas du livre d'or sinon je devrais créer autant d'entités que d'adresses email.

Sinon ta méthode est vraiment chouette, ça marche aussi avec xhtml 1.0 et l'envoi en text/html?
Je viens d'essayer, et quelque soit le DOCTYPE (en restant en XHTML), il faut que la page soit envoyée en "application/xhtml+xml" pour que cela fonctionne :-)

Ombre :

Le 14 Juillet 2007 à 11:18
« Par contre la phrase qui m'a fait quelque chose c'est "Et c'est accessible aussi"..., parce que (j'ai honte) je n'y avais pas du tout pensé, tout content que j'étais d'avoir trouvé cette méthode. »

Pourquoi tu dis ça??? Elle est accessible ta méthode non? Quand j'ai dit ça je voulais dire que la méthode utilisée sur le livre d'or était accessible, comme la tienne. Rien de négatif donc. ;-)

Ou alors tu voulais dire que tu n'avais pas pensé à l'accessibilité? ;-)
Je voulais dire que je n'y avais pas du tout pensé. Mais oui, cette méthode est plutôt accessible (pas moins en tout cas que l'utilisation de &amp;eacute; pour é par exemple) :-)

Gabriel Hautclocq :

Le 14 Octobre 2008 à 16:22
As tu une solution pour faire fonctionner l'astuce des entités xml sur tous les navigateurs ?

Ton astuce ne fonctionne pas sous internet explorer.

Pour les autres navigateurs que IE, il faut que la page soit servie en application/xhtml+xml (c'est à dire dans l'entête http elle même, voir la fonction header de php), pas seulement dans la balise meta.

Pour faire fonctionner cette astuce sous IE, il faut regarder l'exemple de ce site : http://www.informit.com/library/content.aspx?b=STY_XML_21days&seqNum=157
En fait il s'agit de faire un document xml important la dtd du XHTML (même principe qu'un bon vieux application/xhtml+xml de toute façon)

Mais du coup cela ne fonctionne plus pour Safari et Chrome. Quel casse tête...
J'ai pas d'autre solutions que de gérer différemment les différents browser... Mais choisir entre les utilisateurs de WebKit et ceux de IE n'est pas très difficile... IE sucks.

Benoit Colin :

Le 05 Novembre 2008 à 14:43
Solution intéressante ! Je connaissais pas le coup de l'extension de la DTD. Par contre effectivement ce n'est pas très accessible.
Je peux proposer une autre soluce, en combinant une image (pour avoir l'adresse mail en visuel), qui comporte un texte ALT pour les navigateurs restreints, et un coup de javascript pour orienter le clic vers un mailto:
Une démo est visible ici
En fait le problème d'accessibilité viens du fait que ça ne fonctionne pas avec tout les browsers, même parmis les principaux, mais pour les lecteurs d'écran utilisé avec les browsers avec lesquels ça fonctionne, ça ne devrait pas posé de problèmes :-p.
Bon ouais c'est pas terrible :-D...
Je connaissais la solution de l'image, mais je ne trouve pas ça pratique car on ne peut pas sélectionner le texte ou un bout du texte :-/. Par contre c'est efficace ça c'est sûr :-).

Benoit Colin :

Le 05 Novembre 2008 à 14:45
Nota : ton flux RSS est cassé !
Oh? Tu peux me dire ce qui ne vas pas parce que chez moi tout fonctionne et il est toujours valide... :-/

Hautclocq Gabriel :

Le 29 Août 2010 à 06:30
Bonjour,

Petite mise à jour : j'ai réussi à faire fonctionner l'astuce des entités sur tous les navigateurs. J'ai également trouvé un moyen d'obfusquer les liens dans un site (si l'on ne souhaite pas partager un lien par exemple) et par la même occasion un moyen d'utiliser ses propres balises en conjonction avec les balises XHTML usuelles (même les liens fonctionnent). Les extraits de code ci-dessous montrent comment utiliser les entités seulement, voir l'exemple complet pour les balises personnalisées.

La technique est somme toute assez simple :

1. La page web est un fichier .xml

2. Voici l'entête de ma page web de test :

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet title="xslformating" type="text/xsl" href="test.xsl"?>
<!DOCTYPE html
[
  <!ENTITY mailto "mailto:">
  <!ENTITY username "gabriel">
  <!ENTITY arobase "@">
  <!ENTITY hostname "gabsoftware">
  <!ENTITY tld ".com">
  <!ENTITY http "http://">
  <!ENTITY www "www.">
  <!ENTITY email "&username;&arobase;&hostname;&tld;">
  <!ENTITY website "&http;&www;&hostname;&tld;">
]>
<html>
<!-- votre page web ici... -->
</html>

Notez que je n'ai pas inséré le doctype XHTML. Ceci est intentionnel et nécessaire pour que cela fonctionne sous IE et évite des problèmes avec Webkit.

3. Cette page web est transformée par un processeur XSL en un autre document .xml au niveau client (pas serveur, sinon on perd l'intérêt de l'obfuscation) et affichée dans le navigateur. Voici un extrait de la feuille de style XSL :

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml"
              indent="yes"
              media-type="application/xhtml+xml"
              omit-xml-declaration="no"
              encoding="utf-8"
              version="1.0"
              doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
              doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" />
  
  <!--basic xhtml structure-->
  <xsl:template match="/html">
    <xsl:element name="html" namespace="http://www.w3.org/1999/xhtml">
      <xsl:copy-of select="@*" />
      <xsl:attribute name="xml:lang" namespace="http://www.w3.org/XML/1998/namespace">en</xsl:attribute>
      <xsl:apply-templates/>
    </xsl:element>    
  </xsl:template>

  <!-- all tags -->
  <xsl:template match="//*">
    <xsl:element name="{name()}" namespace="http://www.w3.org/1999/xhtml">
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Et le tour est joué :)

Pour un exemple complet, voir ici :
test.xml, test.xsl, test.css.

Voilà, en espérant que cela puisse servir.

Cordialement,

Gabriel Hautclocq

PS : le formatage du code ne fonctionne pas bien en utilisant les doubles crochets, donc j'ai mis le code entre balises [code][/code]. Je vous conseille de ne pas copier le code depuis le site mais depuis la source en exemple.
Woaw merci pour cette super participation, ça me donne vraiment envie de me remettre à blogguer :-)
J'ai reformaté le code et mis des vrai lien vers les fichiers.

Gabriel Hautclocq :

Le 09 Septembre 2010 à 11:08
Merci beaucoup, en effet c'est plus clair maintenant !

J'ai mis à jour et expliqué ma méthode plus en détail à l'adresse suivante :
http://www.gabsoftware.com/tips/extending-xhtml-with-xml-xsl-transformations-entities-cdata-sections-javascript/
(c'est en anglais)
Crédit t'es bien entendu donné pour l'utilisation des entités XML en tant que moyen d'obfuscation des adresses email ;)

Dans la mise à jour, il n'y a par exemple plus besoin de préciser le namespace des éléments, ni de la première règle concernant /html.
Super détaillé (et super tout cours aussi) ton article, je link vers ton article dans le mien aussi du coup :-).

Gabriel Hautclocq :

Le 13 Octobre 2010 à 10:07
Merci de nouveau pour le lien! Ça fait plaisir.

J'ai continué un peu mes recherches et j'ai été confronté à des problèmes avec... IE. Notament avec IE6 qui active le mode quirks si le préambule XML est présent et autres joyeusetés, et même avec IE9 beta qui fait de son mieux pour ne pas fonctionner avec ma méthode.

Je suis donc en train de mettre au point une autre méthode qui utilise toujours XSLT et permettrait de générer des emails facilement sans être obligé de les déclarer en tant qu'entités dans le DOCTYPE. Ça fonctionne déjà sur ce site : http://www.wilduniverse.org mais ce n'est pas documenté dans mon article pour l'instant. Cette solution est plus compliquée à mettre en œuvre et il faut utiliser PHP pour que ça fonctionne sur tous les navigateurs, mais je l'expliquerai lorsque j'aurai un peu de temps libre :).

En attendant, voici un extrait de ce qu'un robot spammeur verra dans ma page (pour un peu qu'il visite les fichiers XML):
<hiddenmail
username="gabriel"
hostname="gabsoftware"
tld="com"
caption="équivalent de l'attribut title" />


ou encore

<hiddenmail
username="gabriel"
hostname="gabsoftware"
tld="com"
caption="équivalent de l'attribut title">Texte du lien</hiddenmail>


Pour plus de sécurité on peut même encoder chaque caractère en son entité XML en mixant mode décimal et hexadécimal au hasard (via une fonction écrite en PHP) :
<hiddenmail
username="&#x69;&#x6e;&#x66;&#111;"
hostname="&#119;&#x69;&#x6c;&#100;&#x75;&#110;&#105;&#118;&#101;&#x72;&#x73;&#x65;"
tld="&#111;&#114;&#103;"
caption="Click here to send us an email" />


Les lignes précédentes seront transformées en liens XHTML valides à l'aide d'une feuille de style XSL. La règle est la suivante :

<xsl:template match="//hiddenmail" priority="50">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="concat('mailto:', @username, '@', @hostname, '.', @tld)"/>
</xsl:attribute>
<xsl:if test="@caption">
<xsl:attribute name="title">
<xsl:value-of select="@caption"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="@id | @class | @name">
<xsl:copy-of select="@id | @class | @name"/>
</xsl:if>
<xsl:choose>
<xsl:when test="text()">
<xsl:value-of select="text()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(@username, '@', @hostname, '.', @tld)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>



Voilà je te tiendrai au courant lorsque mon article sera mis à jour :)

Note : les guillemets doubles ont été échappés par " dans mon post mais il ne faut bien entendu pas les échapper.
Utiliser XSL peut être une bonne idée mais je suis vraiment pas sûr que suffisement de browser le supporte correctement actuellement.

Ajouter un commentaire :

Formatage du texte : ##gras##, //italique//, --barré--, __souligné__.
Pour créer un lien, utilisez la syntaxe suivante : @[http://adresse/du/lien/](texte du lien).
Pour insérer du code, mettez le entre double crochets : [[votre code]].
Votre adresse email ne sera pas affichée.