[spip-dev] Sécurisation de l'accès aux pièces jointes

Bonjour à tous,

Désolé pour les pbs autour de la création de vignettes,
qui étaient dus à la mise en place d'une fonctionnalité nouvelle souvent demandée ces temps-ci:
la sécurisation de l'accès aux pièces jointes.

En m'inspirant des nombreuses méthodes et recommandations énoncées ici ou là,
voici la description de ce que je viens de poster sur le CVS:

1. en standard, tout est censé marcher comme auparavant.

2. dans les fonctions avancées de configuration, existe à présent une option de demande de sécurisation de ces accès.

3. lorsqu'on l'active, des fichiers htaccess de contenu "deny from all" seront créés dans les sous-répertoires de IMG recevant des fichiers envoyés par formulaires ou ftp
(point important: ceci ne concerne PAS IMG lui-même, ni ses sous répertoires d'icones et de vignettes, qui ne souffrent donc d'aucun surcoût d'accès; les répertoires concernés seront eux protégés sans une longue interprétation de RewriteRules).

4. la fonction generer_url_document a été rédéfinie dans les fichiers inc{-_}url-*. Si le mode de sécurisation n'est pas actif, elle continue comme avant à renvoyer le PATH du fichier associé au numéro de document transmis en argument. Si le mode est actif, elle renvoie l'url d'un script de controle d'acces, avec le numéro du document dans sa query-string. Rappelons que generer_url_document est appelé systématiquement dans tous les scripts de Spip accédant à la description d'un document.

5. la CVS contient une version minimale du script appelé par generer_url_document: il contrôle si le demandeur s'est authentifié dans l'espace privé ou si le numéro de document est associé à un article, une rubrique ou une brève publiée. Sinon il ne renvoie rien (mais le signale dans spip_log), si oui il renvoie le contenu du fichier avec les entêtes idoines (type, length, disposition). On peut évidemment redefinir generer_url_document pour qu'elle appelle des scripts plus élaborés. Un point intéressant est que disposer du numéro de document dispense de le retrouver dans les tables à partir du PATH du fichier, ce que la méthode à RewriteRule imposait.

Plusieurs remarques:

a. il y aura peut-etre un pb avec les documents qui sont utilisés AUSSI comme des vignettes; je ne maîtrise pas bien cette utilisation de Spip, il y aura peut-etre
des adaptations à faire ici.

b. pour le moment, chaque .htacces n'est créé qu'au prochain chargement d'un nouveau document du type donné: j'ai encore un peu de travail à faire pour recenser les sous-répertoires de IMG pouvant en contenir, afin de les créer tous dès l'activation.

c. symétriquement, la désactivation du mode ne détruira chaque .htacces qu'au chargement d'un nouveau document du type donné (même esuac, meme teffe).

d. ne sachant pas encore déclarer une nouvelle meta (ce qui semble exiger beaucoup de
précautions) cette nouvelle option prend lâchement la place de l'option htpasswd,
coupable de sentir trop le souffre. On ne peut donc avoir les deux options à la fois,
mais c'est provisoire.

e. cette solution n'avait jamais été tentée car le code initial de Spip supposait implicitement que generer_url_document retournait un Path commençant par IMG/ ce qui n'est plus le cas heureusement. Il n'est pas impossible que j'ai introduit des bugs dans les cas usuels en étendant les possibilités de reféfinition. Signaler alors les dysfonctionnements, mais vérifier d'abord que le pb ne vient pas de ce que votre code contournait cette limitation par des circonlocutions désormais obsolètes.

Bonne expérimentation à tous,

      Emmanuel

Bien bien tout ca.

Juste une remarque en passant (et surtout, avant d'avoir regardé le code
donc peut etre à cotè de la plaque ...) :
comment on fait pour faire un lien externe vers un document d'un article
publié ?
C'etait surtout pour cette raison que je m'etais appuyé sur les rewriterules
(d'une maniere générale, pour faire un systeme "transparent", ne s'appuyant
donc pas sur la generation d'url).

je suppose qu'on peut pointer directement sur le "wrapper" ou faire un
repertoire bidon avec la rewriterule qui va bien.

L'avantage des rewrites c'etait aussi de pouvoir s'appuyer sur le htpasswd
pour donner un accès direct aux redacteurs et admin authentifiés.
C'est vrai par contre que je ne m'était pas posé la question des perfs.
La, au moins, l'url generée est gardée en cache, ca evite de refaire les
regexp à chaque appel.

Une question aussi : comment ca se passe si je publie un article contenant
"inline" un document d'un article non publié ?
Jusqu'ici, ca marchait, la, logiquement, ca ne marchera plus.
Le principe me parait bon, mais ca fait une grosse difference fonctionnelle
et ca fait un lien "fort" entre l'article et ses documents.
Je pensais que les correspondances etaient maintenant stockée qqpart, mais
je n'ai pas vu ou, j'en ai donc conclu que la liste des documents "inline"
etait reconstruite en parsant le texte pour article_edit, c'est ca ?
Si c'est le cas, il faudrait peut etre stocker ca en base (comme c'est fait
pour les formulaires), non ?

comment on fait pour faire un lien externe vers un document d'un article
publié ?
C'etait surtout pour cette raison que je m'etais appuyé sur les rewriterules
(d'une maniere générale, pour faire un systeme "transparent", ne s'appuyant
donc pas sur la generation d'url).

je suppose qu'on peut pointer directement sur le "wrapper"

oui: de toutes façons l'URL que tu trouveras dans le code sera celle de ce script
avec le numero de document, il n'y a aucun moyen de savoir où il se trouve effectivement
si on n'a pas accès à la table SQL qui donne la correspondance

ou faire un
repertoire bidon avec la rewriterule qui va bien.

???

L'avantage des rewrites c'etait aussi de pouvoir s'appuyer sur le htpasswd
pour donner un accès direct aux redacteurs et admin authentifiés.

le script commence par regarder le cookie, ca revient au meme.

C'est vrai par contre que je ne m'était pas posé la question des perfs.
La, au moins, l'url generée est gardée en cache, ca evite de refaire les
regexp à chaque appel.

oui.

Une question aussi : comment ca se passe si je publie un article contenant
"inline" un document d'un article non publié ?
Jusqu'ici, ca marchait, la, logiquement, ca ne marchera plus.

Si ca marchera: le script verra que ce document est associé à un article publié,
même si par ailleurs il l'est aussi à un article non publié. Je trouve que c'était
aussi un pb avec les rewriterules: on a le fichier, mais quel article en a besoin ?
il y avait ambiguité, maitenant il n'y en a plus. Application utile: j'ai un sujet
d'examen qui porte sur une figure vu en cours; le cours est publié, l'examen pas
encore: je veux que la figure soit toujours dispo quand on visionne le cours (sinon c'est une indication a contrario sur l'examen).

Le principe me parait bon, mais ca fait une grosse difference fonctionnelle
et ca fait un lien "fort" entre l'article et ses documents.
Je pensais que les correspondances etaient maintenant stockée qqpart, mais
je n'ai pas vu ou, j'en ai donc conclu que la liste des documents "inline"
etait reconstruite en parsant le texte pour article_edit, c'est ca ?
Si c'est le cas, il faudrait peut etre stocker ca en base (comme c'est fait
pour les formulaires), non ?

??? la table des documents est celle de la correspondance entre un numéro de document et le fichier qui le contient, ca a toujours été ainsi. Les scripts d'ecrire analysent
effectivement les champs Texte pour fabriquer l'url des pièces jointes, ca aussi c'est depuis toujours comme ça. C'est pour cela qu'il y a aussi dans /ecrire un fichier inc_url qui ne se distingue de ceux au-dessus que par un ../ dans l'url (../IMG/ dans le cas ouvert, ../wrapper dans le cas sécurisé. C'est une des raisons d'une certaine lenteur dans l'espace privé, et mon nettoyage de ces derniers jours visait à limiter ça au minimum (n'appeler spip_image que s'il y a une vignette à construire, sinon insérer
tout de suite la vignette par défaut).

      Emmanuel

oui: de toutes façons l'URL que tu trouveras dans le code sera celle de
ce script
avec le numero de document, il n'y a aucun moyen de savoir où il se
trouve effectivement
si on n'a pas accès à la table SQL qui donne la correspondance

Arg !
par son numero, pas par son nom ?
donc les liens sont du type wrapper.php?id_document=12

ou faire un
repertoire bidon avec la rewriterule qui va bien.

???

L'idée, c'etait de faire un repertoire vide avec un rewrite qui transforme
/image/toto.doc en wrapper.php?doc=toto.doc.
Donc ca, ca ne marche pas, il faut faire des liens du genre /documents/doc12
(sans interet, autant pointer directement vers le wrapper)
Je dis ca parcque j'avais imaginé un fonctionnement mixte intranet/site
public.
Dans ce cas, on doit avoir du contenu "public", documents compris, donc
eventuellement la possibilité de faire un lien externe directement sur un
document.

le script commence par regarder le cookie, ca revient au meme.

OK, super

Si ca marchera: le script verra que ce document est associé à un
article publié,
même si par ailleurs il l'est aussi à un article non publié. Je trouve
que c'était
aussi un pb avec les rewriterules: on a le fichier, mais quel article
en a besoin ?
il y avait ambiguité, maitenant il n'y en a plus. Application utile:
j'ai un sujet
d'examen qui porte sur une figure vu en cours; le cours est publié,
l'examen pas
encore: je veux que la figure soit toujours dispo quand on visionne le
cours (sinon c'est une indication a contrario sur l'examen).

Bon, alors y a un truc que je n'ai pas suivi.
Jusqu'ici, j'ai l'article n°36, je lui attache un document, il prend le
n°12, ca créera le couple (36;12) dans la table documents_articles
Maintenant, rien ne m'empeche de mettre <doc12> dans l'article n°40.
Aux dernieres nouvelles, ca ne généré pas d'entrée dans documents_articles
(si ?).
Si l'article n°36 est proposé et l'article n°40 est publié, la ou j'en étais
resté, la seule info en base etait que ce document etait rattaché à un
document non publié.
D'après ce que tu decris, ca n'est plus le cas, c'est ca ?
depuis quand ?

Je parlais des formulaires car au moment ou on sauvegarde un article, les
entrées dans forms_articles sont recréées, je proposais donc de faire la
meme chose pour les documents et les images mais tu as l'air de dire que
c'est deja fait ...
Vous courrez vraiment trop vite pour moi !

Bon, faut vraiment que je regarde ca de pret.

oui: de toutes façons l'URL que tu trouveras dans le code sera celle de
ce script
avec le numero de document, il n'y a aucun moyen de savoir où il se
trouve effectivement
si on n'a pas accès à la table SQL qui donne la correspondance

Arg !
par son numero, pas par son nom ?
donc les liens sont du type wrapper.php?id_document=12

c'est que je dis depuis 3 mails :wink:

ou faire un
repertoire bidon avec la rewriterule qui va bien.

???

L'idée, c'etait de faire un repertoire vide avec un rewrite qui transforme
/image/toto.doc en wrapper.php?doc=toto.doc.
Donc ca, ca ne marche pas, il faut faire des liens du genre /documents/doc12
(sans interet, autant pointer directement vers le wrapper)
Je dis ca parcque j'avais imaginé un fonctionnement mixte intranet/site
public.
Dans ce cas, on doit avoir du contenu "public", documents compris, donc
eventuellement la possibilité de faire un lien externe directement sur un
document.

mon optique est différente: à terme, le répertoire IMG doit pouvoir etre n'importe quel répertoire, même par forcément dans l'arborescence http. A la limite, ça peut carréméent ne pas etre un répertoire, mais un serveur quelconque. Ma "mixité" est plus étendue que la tienne !

Jusqu'ici, j'ai l'article n°36, je lui attache un document, il prend le
n°12, ca créera le couple (36;12) dans la table documents_articles
Maintenant, rien ne m'empeche de mettre <doc12> dans l'article n°40.
Aux dernieres nouvelles, ca ne généré pas d'entrée dans documents_articles
(si ?).
Si l'article n°36 est proposé et l'article n°40 est publié, la ou j'en étais
resté, la seule info en base etait que ce document etait rattaché à un
document non publié.
D'après ce que tu decris, ca n'est plus le cas, c'est ca ?
depuis quand ?

Bon, je savais bien qu'il y aurait un cas que j'ignorais qui questionnerait.
Effectivement dans ce cas le document n'apparaîtra pas. Cela dit, sans vouloir me débiner, n'est-ce pas plus logique: je suis en cours de rédaction d'un article un peu long avec des documents iconographiques supers, et voila qu'un rédacteur du site les voit et publie illico une brève "Regardez les magnifiques documents que JE suis capable
de faire". Bon, je ne suis pas parano, mais si on veut un mode de sécurisé, au-delà
des pbs techniques, il y a des choix volontaires: qu'en mode sécurisé il ne soit pas possible qu'une balise "doc" référence un document avant qu'il ne soit publié me parait souhaitable. Non ?

      Emmanuel

c'est que je dis depuis 3 mails :wink:

Je suis un peu bouché en ce moment ...

mon optique est différente: à terme, le répertoire IMG doit pouvoir
etre n'importe quel répertoire, même par forcément dans l'arborescence
http. A la limite, ça peut carréméent ne pas etre un répertoire, mais
un serveur quelconque. Ma "mixité" est plus étendue que la tienne !

jusque la j'avais suivi et je suis evidement pour cette "abtraction" à 100%
Dans la meme idée, j'avais meme reflechi à déplacer (ou copier ...) les
documents "publics" dans un repertoire sans sécurité.
Ca reste envisageable comme tu l'as codé je pense (quitte à faire un
redirect quand le document est en acces libre)

Bon, je savais bien qu'il y aurait un cas que j'ignorais qui
questionnerait.
Effectivement dans ce cas le document n'apparaîtra pas. Cela dit, sans
vouloir me débiner, n'est-ce pas plus logique: je suis en cours de
rédaction d'un article un peu long avec des documents iconographiques
supers, et voila qu'un rédacteur du site les voit et publie illico une
brève "Regardez les magnifiques documents que JE suis capable
de faire". Bon, je ne suis pas parano, mais si on veut un mode de
sécurisé, au-delà
des pbs techniques, il y a des choix volontaires: qu'en mode sécurisé
il ne soit pas possible qu'une balise "doc" référence un document avant
qu'il ne soit publié me parait souhaitable. Non ?

Alors, dans le "truc" que j'avais fait, j'avais tranché comme ca :
Tant que le document de reference est "en cours de rédaction", il n'est
accessible qu'à son auteur (j'avais du ajouté aussi les admins, mais c'est
juste de la parano ...)
Quand un document est proposé, il est accessible à tous les rédacteurs qui
sont donc libres de l'utiliser dans des articles et donc succeptibles d'etre
publiés.
Un document publié est public donc sans sécurité (enfin, dans mon cas, lié à
la sécurité de l'article auquel il est attaché).

La plus grosse limitation etait (reste ...) pour moi l'absence de lien en
base dans les insertions "inline".
Les formulaires du lab amenent une solution qui me parait très propre (meme
si ca doit plomber un peu les perf, c'est juste à la sauvegarde, ca ne me
derange pas) : reconstruire les liens à la sauvegarde de l'article.

Reste à determiner si ces liens sont "aussi fort" que l'attachement initial
ou non ...
Pour moi, si un article est publié, c'est que son contenu correspond à la
"ligne editoriale" que se sont fixés les admins, document(s) compris.
Il n'y a donc pas de raison de "retirer" un document si un article est
retiré (qu'il soit l'article d'origine ou simplement un article l'utilisant
"inline")
Après, on peut se poser effectivement des questions de propriété, mais je
pars du principe qu'un redacteur qui "propose" du contenu souhaite le voir
publié, c'est pour ca que j'avais protégé uniquement les contenus "en cours
de rédaction".
En toute logique, un "pompeur" doit donc attendre que l'article soit proposé
pour avoir accès aux documents et proposer son article à son tour ... après
c'et des histoires d'admin.

C'est ce que j'avais trouvé de plus cohérent avec la philosophie de l'outil,
mais bon, c'est forcement un compromis discutable.

Bon, ca me rassure, je suis un peu moins largué que ce que j'ai cru à un
moment.

@++