samedi 22 janvier 2011

sécuriser un wiki



Cet article décrit un ensemble de techniques pour sécuriser un wiki. Ces techniques ont été implémentées pour le Wiki Infond. Bien sûr, nous ne dévoilons ici qu'une partie des techniques de sécurisation que nous avons déployées.

Sécuriser /tmp

Le répertoire /tmp a une taille limitée et n'est pas exécutable.

# source: http://snippets.prendreuncafe.com/snippet/54

# create a 40MB block device which will be the /tmp file system
cd /root
dd if=/dev/zero of=l/root/tmpMnt bs=1024 count=40000
mkfs.ext3 -F /root/tmpMnt

# mount it at /tmp
mv /tmp /tmp.backup
mkdir /tmp
mount -o loop,noexec,nosuid,rw /root/tmpMnt /tmp
chmod 0777 /tmp

# make it so it is used on boot up
if ! grep -qai tmpMnt /etc/fstab ; then 
     echo "/root/tmpMnt /tmp ext3 loop,noexec,nosuid,rw  0 0" >> /etc/fstab
fi

# check your syntax is ok
mount -a

# check that programs in /tmp will not run
cp /bin/ls /tmp/
/tmp/ls

Apparence du Wiki

Vocabulaire

  • La bannière est un fichier png appelé fronton.png,
  • Le dossier du Wiki est /var/www/wiki/,
  • Le skin du Wiki est Monobook.

Afficher la bannière

Editer skins/Monobook.php,

A la place de :

........<div id="globalWrapper">.......


Ecrire :
........        <div id="p-banner">
                <div id="p-bannerG">
                        <a href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href'])?>">
                        <img src="infondskin2/frontonG.png"></a>
                </div>
                <div id="p-bannerD">
                        <img src="infondskin2/frontonD.png">
                </div>
        </div>

        <div id="globalWrapper">
.......

Mettre le site sous la bannière

Editer skins/monobook/main.css. Ajouter ou modifier les lignes suivantes :

#p-banner {
        position: relative;
        height: 74px;
        max-height: 74px;
}

#p-bannerG {
        position: absolute;
        left: 0;
        z-index: 2;
}

#p-bannerD {
        position: absolute;
        right: 0px;
        z-index: 1;
}

#globalWrapper
{
    ...
   position: relative;
    ...
}

Supprimer logo

Editer skins/MonoBook.php et commenter cette section (<!-- -->) :

<div class="portlet" id="p-logo">
<a style="">text('logopath') ?>);"
href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href'])?>"
title="<?php $this->msg('mainpage') ?>"></a>
</div>


Editer skins/monobook/main.css pour le modifier comme suit :

#column-one {
/* padding-top: 160px;*/
padding-top: 3em;
}


Cacher le footer

#footer
visibility: hidden;


Favicon

Pour modifier l'icone de la barre de navigation du navigateur, ajouter favicon.ico à la racine du site.


Configurer la Sidebar

http://monsite.com/index.php?title=MediaWiki:Sidebar&action=edit

Edit : Cette méthode est remplacée par l'extension SideBar. Cf à la fin de cet article.


Extension "Dynamic pages list"




Modifier la "secret key" dans LocalSettings.php 

Modifier $wgSecretKey = "";


Utiliser le mail pour vérifier les nouveaux comptes


apt-get install php-net-smtp
pear install Net_SMTP
pear install Mail




Captcha



VisualMathCaptcha

$ apt-get install php5-gd


VisualMathCaptcha crée une page spéciale appelée VisualMathCaptcha. Il faut donc l'ajouter dans l'extension Lockdown :

$wgSpecialPageLockdown['VisualMathCaptcha'] = array('*');


Utilisation avec ConfirmEdit :
   1. Ouvrir ConfirmEdit.php dans le répertoire de l'extension ConfirmEdit, et modifier la valeur $wgCaptchaClass en VisualMathConfirmCaptcha.
   2. Ajouter la ligne suivante dans LocalSettings.php, après le contenu copié depuis le fichier LocalSettings.part :

  $wgAutoloadClasses['VisualMathConfirmCaptcha'] = "$IP/extensions/VisualMathCaptcha/VisualMathConfirmCaptcha.class.php";


Sécuriser PHP

/etc/php5/apache2/php.ini
allow_url_fopen off (attention, cette fonction est nécessaire pour l'extension TitleBlackList).


Extension Lockdown

Dans Localsettings.php :

# extension Lockdown
require_once( "$IP/extensions/Lockdown/Lockdown.php" );
$wgSpecialPageLockdown['Listusers'] = array('sysop');
$wgSpecialPageLockdown['Search'] = array('*');
$wgSpecialPageLockdown['Userlogin'] = array('*');
$wgSpecialPageLockdown['Userlogout'] = array('*');
$wgSpecialPageLockdown['Preferences'] = array('*');
$wgSpecialPageLockdown['Watchlist'] = array('*');
$wgSpecialPageLockdown['Upload'] = array('uploadaccess');
$wgActionLockdown['history'] = array('sysop');
$wgSpecialPageLockdown['VisualMathCaptcha'] = array('*');
$wgSpecialPageLockdown['MultipleUpload'] = array('uploadaccess');
$wgSpecialPageLockdown['Confirmemail'] = array('*');
$wgSpecialPageLockdown['Invalidateemail'] = array('*');

$wgNamespacePermissionLockdown[NS_SPECIAL]['read'] = array('sysop');
$wgNamespacePermissionLockdown[NS_MEDIAWIKI]['read'] = array('sysop');
$wgNamespacePermissionLockdown[NS_USER]['read'] = array('sysop');
$wgNamespacePermissionLockdown[NS_TEMPLATE]['read'] = array('sysop');

Attention, pas de guillements autour de NS_SPECIAL !


Améliorer l'extension Lockdown


Nous ne suivons pas exactement ce tuto. Ajouter simplement les trois lignes suivantes :

Au lieu de :

        $ns = $title->getNamespace();
        if ( NS_SPECIAL == $ns ) {
                if ( $action != 'read' ) {

Ecrire :

        $ns = $title->getNamespace();

        $groups = @$wgNamespacePermissionLockdown[$ns][$action];
        if (!$groups) $groups = @$wgNamespacePermissionLockdown['*'][$action];
        if (!$groups) $groups = @$wgNamespacePermissionLockdown[$ns]['*'];

        if ( NS_SPECIAL == $ns ) {
                if ( $action != 'read' ) {
      

Cacher la boîte à outils pour les utilisateurs n'étant pas sysop

Edit : Cette méthode est remplacée par l'ajout de l'extension SideBar.php cf en fin de cet article : 
Trouver :

function toolbox() {
?>
<div class="portlet" id="p-tb">
<h5><?php $this->msg('toolbox') ?></h5>
...
</div>
</div>
<?php
}


Et le modifier par :

function toolbox() {
global $wgUser; 
?>
<div class="portlet" id="p-tb">
    <?php if (in_array( 'sysop', $wgUser->getGroups() ) == 1) { ?>
          <h5><?php $this->msg('toolbox') ?></h5>
...
</div>
<?php } ?>
</div>
<?php
}


LocalSettings.php : quelques astuces

Modifier wgSitename :

# disallow edit for non logged-in users
$wgGroupPermissions['*']['edit'] = false;

# must have confirmed email before edit
$wgEmailConfirmToEdit=true;


URLs courts



Enlever contributions et mytalks de la barre personnelle

Solution dans skins (bof !)

Dans skins/Monobook.php,

Remplacer :

<?php                   foreach($this->data['personal_urls'] as $key => $item) { ?>
                                <li id="<?php echo Sanitizer::escapeId( "pt-$key" ) ?>"<?php
                                        if ($item['active']) { ?> class="active"<?php } ?>><a href="<?php
                                echo htmlspecialchars($item['href']) ?>"<?php echo $skin->tooltipAndAccesskey('pt-'.$key) ?><?php
                                if(!empty($item['class'])) { ?> class="<?php
                                echo htmlspecialchars($item['class']) ?>"<?php } ?>><?php
                                echo htmlspecialchars($item['text']) ?></a></li>
<?php                   } ?>    


Par:

<?php                   foreach($this->data['personal_urls'] as $key => $item) {
                                if ( ($key!="mycontris") && ($key !="mytalk") ) { ?>
                                        <li id="<?php echo Sanitizer::escapeId( "pt-$key" ) ?>"<?php
                                                if ($item['active']) { ?> class="active"<?php } ?>><a href="<?php
                                        echo htmlspecialchars($item['href']) ?>"<?php echo $skin->tooltipAndAccesskey('pt-'.$key) ?><?php
                                        if(!empty($item['class'])) { ?> class="<?php
                                        echo htmlspecialchars($item['class']) ?>"<?php } ?>><?php
                                        echo htmlspecialchars($item['text']) ?></a></li>
<?php                           } ?>
<?php                   } ?>    



Solution plus esthétique

Créer une extension :

<pre>
<?php

$wgHooks['PersonalUrls'][] = 'persurl';

function persurl( &$personal_urls, &$title ) {
        global $wgUser;
        if ( in_array( 'sysop', $wgUser->getGroups() ) != 1) {
                unset($personal_urls['anontalk']);
                unset($personal_urls['mytalk']);
        }
        return true;
}


File upload


Attention de mettre les nouveaux droits de modification après les droits Lockdown.


Suppression historique, viewsource, talk pour users autres que sysop

Dans skin (moche !)

Dans skins/Monobook.php,

Au lieu de :

                                foreach($this->data['content_actions'] as $key => $tab) {
                                               echo '
                                       <li id="' . Sanitizer::escapeId( "ca-$key" ) . '"';
                                               if( $tab['class'] ) {
                                                       echo ' class="'.htmlspecialchars($tab['class']).'"';
                                               }
                                               echo '><a href="'.htmlspecialchars($tab['href']).'"';
                                               # We don't want to give the watch tab an accesskey if the
                                               # page is being edited, because that conflicts with the
                                               # accesskey on the watch checkbox.  We also don't want to
                                               # give the edit tab an accesskey, because that's fairly su-
                                               # perfluous and conflicts with an accesskey (Ctrl-E) often
                                               # used for editing in Safari.
                                               if( in_array( $action, array( 'edit', 'submit' ) )
                                               && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {
                                                       echo $skin->tooltip( "ca-$key" );
                                               } else {
                                                       echo $skin->tooltipAndAccesskey( "ca-$key" );
                                               }
                                               echo '>'.htmlspecialchars($tab['text']).'</a></li>';
                                } ?>


Lire :

                                global $wgUser;
                                foreach($this->data['content_actions'] as $key => $tab) {
                                        if ((($key!="nstab-main")&&($key!="talk")&&($key!="viewsource")&&($key!="history")||(in_array( 'sysop', $wgUser->getGroups() ) == 1)) {
                                                echo '
                                        <li id="' . Sanitizer::escapeId( "ca-$key" ) . '"';
                                                if( $tab['class'] ) {
                                                        echo ' class="'.htmlspecialchars($tab['class']).'"';
                                                }
                                                echo '><a href="'.htmlspecialchars($tab['href']).'"';
                                                # We don't want to give the watch tab an accesskey if the
                                                # page is being edited, because that conflicts with the
                                                # accesskey on the watch checkbox.  We also don't want to
                                                # give the edit tab an accesskey, because that's fairly su-
                                                # perfluous and conflicts with an accesskey (Ctrl-E) often
                                                # used for editing in Safari.
                                                if( in_array( $action, array( 'edit', 'submit' ) )
                                                && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {

                                                       echo $skin->tooltip( "ca-$key" );
                                                } else {
                                                        echo $skin->tooltipAndAccesskey( "ca-$key" );
                                                }
                                                echo '>'.htmlspecialchars($tab['text']).'</a></li>';
                                        }
                                } ?>


Via une extension (désuet dans 1.18)

<?php
$wgHooks['SkinTemplateContentActions'][] = 'caction';

function caction( &$content_actions ) {

       global $wgUser;

       if ( in_array( 'sysop', $wgUser->getGroups() ) != 1) {
                unset($content_actions['talk']);
                unset($content_actions['viewsource']);
                unset($content_actions['history']);
        }
        return true;
}


Multi languages


Utiliser ParserFunctions.

Verrouiller la page Template:Languages pour les admin uniquement


Extension SyntaxHighLight



Vous pouvez aussi éditer la fichier "SyntaxHighlight_GeSHi.class.php", aux alentours de la ligne 215 :

$css[] = "\tline-height: normal; border: 0px none white;";


Et le modifier ainsi :

$css[] = "\tline-height: normal; border: 1px dashed #2f6fab;";


Autre solution pour modifier l'apparence (celle-ci fonctionne):

Editer /var/lib/mediawiki/skins/infondskin2/main.css 

div.mw-geshi {
  padding: 1em; 
  border: 1px dashed #2f6fab;
  background-color: #F9F9F9;
  color: black;
  line-height: 1.1em;
}


Combattre le spam



Empecher les div hidden

Dans LocalSettings.php,

# antispam
$wgSpamRegex = "/\<.*style.*?(display|position|overflow|visibility|height)\s*:.*?>/i";


Blacklist d'IPs

#!/bin/bash
wget http://www.stopforumspam.com/downloads/bannedips.zip
unzip -u bannedips.zip
echo "<?php" > bannedips.php
echo \$"wgProxyList = array(" >> bannedips.php; echo -n "'" >> bannedips.php
sed -i 's/,/\x27,\n\x27/g' bannedips.csv
cat bannedips.csv >> bannedips.php
echo "');" >> bannedips.php
rm bannedips.csv
rm bannedips.zip*
chown root:www-data bannedips.php
chmod 740 bannedips.php
mv bannedips.php /var/www/wiki/extensions/bannedips.php
tail /var/www/wiki/extensions/bannedips.php

Ajouter dans LocalSettings.php :

require_once("$IP/extensions/bannedips.php");


DNS blacklists

Dans LocalSettings.php :

$wgEnableSorbs = true; 
$wgSorbsURL =   'http.dnsbl.sorbs.net.';


Extension EmailAddressImage



Extension SpamBlackList


require_once( "$IP/extensions/SpamBlacklist/SpamBlacklist.php" );
$wgSpamBlacklistFiles = array(
"http://meta.wikimedia.org/wiki/Spam_blacklist"
);


Extension TitleBlackList


require_once( "{$IP}/extensions/TitleBlacklist/TitleBlacklist.php" );
$wgTitleBlacklistSources = array(
    array(
         'type' => TBLSRC_URL,
         'src'  => 'http://meta.wikimedia.org/w/index.php?title=Title_blacklist&action=raw',
    )
);


MultiUpload


# extension MultiUpload
require_once("$IP/extensions/MultiUpload/MultiUpload.php");
$wgMaxUploadFiles = 10;

Ajouter dans TOOLBOX dans MediaWiki:Sidebar :

** Special:MultipleUpload|multiupload-toolbox ("Upload multiple files").

Attention de mettre les nouveaux droits de modification après les droits Lockdown

$wgSpecialPageLockdown['MultipleUpload'] = array('uploadaccess');


Sidebar

Version 1.16

Nous créons ici une extension pour modifier la Sidebar. Cette version ne fonctionne qu'à partir de 1.16.

$ cat extensions/SideBar.php

<?php
$wgHooks['SkinBuildSidebar'][] = 'efHideSidebar';

function efHideSidebar($skin, &$bar) {
        global $wgUser;

        // default bar, any user
        $navigation = array(
                        array(text => wfMsg('mainpage-description'),
                              href => 'Accueil',
                              id => 'n-mainpage-description',
                              active => ''),
                        array(text => 'Aide',
                              href => 'Aide',
                              id => 'n-Aide',
                              active => ''),
                        array(text => 'Contact',
                              href => 'Contact',
                              id => 'n-Contact',
                              active => ''),
        );

        // users logged in 
        $users = array(
                        array(  text => 'mindmeister',
                                href => 'http://www.mindmeister.com/fr/34461959/t0ka7a',
                                id => 'n-mindmeister',
                                active => ''),
        );

        // uploadaccess group
        $upload = array(
                         array( text => 'téléversement',
                                href => SpecialPage::getTitleFor( 'MultipleUpload' )->getLocalUrl(),
                                id => 'n-téléversement',
                                active => ''),
                );

        $bar = array();

        // every users (even not logged in)
        $bar[navigation] = $navigation;

        // if logged in
        if ( $wgUser->isLoggedIn() ) {
                $bar[users] = $users;
        }

        // if uploadaccess
        if ( in_array( 'uploadaccess', $wgUser->getGroups() ) == 1) {
                $bar[téléversement] = $upload;
        }

        return true;
}

Version 1.15

Cette solution nécessite de cacher la toolbox dans le skin !

<?php
$wgHooks['SkinBuildSidebar'][] = 'fnNewSidebarItem';

function fnNewSidebarItem( $skin, &$bar ) {
        global $wgUser;

        # any user
        $out = '<div class="pBody"><ul>';
        $out.= '<li id="n-mainpage-description"><a href="/wiki/Accueil">Accueil</a></li>';
        $out.= '<li id="n-help"><a href="/wiki/Aide:Accueil">Aide</a></li>';
        $out.= '<li id="n-contact"><a href="/wiki/Contact">Contact</a></li>';
        $out.= '<li id="feedlinks"><a title="Flux RSS pour cette page" class="feedlink" type="application/rss+xml" rel="alternate" href="/mediawiki/index.php?title=Sp%C3%A9cial:Modifications_r%C3%A9centes&amp;feed=rss" id="feed-rss">RSS </a><a title="Flux Atom pour cette page" class="feedlink" type="application/atom+xml" rel="alternate" href="/mediawiki/index.php?title=Sp%C3%A9cial:Modifications_r%C3%A9centes&amp;feed=atom" id="feed-atom">Atom</a></li>';
        // if logged in
        if ( $wgUser->isLoggedIn() ) {
                $out.= '<li id="n-print"><a accesskey="p" title="Version imprimable de cette page [alt-shift-p]" rel="alternate" href="/mediawiki/index.php?title=Accueil&amp;printable=yes">Version imprimable</a></a></li>';
        }
        $out.= '</ul></div>';
        $bar[ 'navigation' ] = $out;
                 
        # any user
        $out = '<div class="pBody"><ul>';
        $out.= '<li id="n-mindmeister"><a href="http://www.mindmeister.com/fr/34461959/t0ka7a">Mindmeister</a></li>';
        $out.= '</ul></div>';
        $bar[ 'liens' ] = $out;

        // if uploadaccess
        if ( in_array( 'uploadaccess', $wgUser->getGroups() ) == 1) {
                $out = '<div class="pBody"><ul>';
                $out.= '<li id="n-multipleupload"><a href="'.SpecialPage::getTitleFor( 'MultipleUpload' )->getLocalUrl().'">téléversement</a></li>';
                $out.= '</ul></div>';
                $bar['téléversement'] = $out;
        }

        // if sysop
        if ( in_array( 'sysop', $wgUser->getGroups() ) == 1 ) {
                $out = '<div class="pBody"><ul>';
                $out.= '<li id="t-specialpages"><a accesskey="q" title="Liste de toutes les pages spéciales [alt-shift-q]" href="/wiki/Sp%C3%A9cial:Pages_sp%C3%A9ciales">Pages spéciales</a></li>';
                $out.= '<li id="t-specialpages"><a accesskey="q" title="Liste de toutes les pages spéciales [alt-shift-q]" href="/wiki/Spécial:Modifications_récentes">Modifications récentes</a></li>';
                $out.= '</ul></div>';
                $bar['toolbox'] = $out;
        }


        return true;
}
                     
Puis nous ajoutons cette extension dans LocalSettings.php.

# extension SideBar
require_once("$IP/extensions/SideBar.php");


Confirmation E-mail

Dans LocalSettings.php,

Remplacer "false" par "true" :

$wgEmailAuthentication = true;

Lockdown = autoriser :

$wgSpecialPageLockdown['Confirmemail'] = array('*');
$wgSpecialPageLockdown['Invalidateemail'] = array('*');


Table des références d'articles

Extension cite


RSS

Dans /var/www/wiki/skins/infondlinux.php

Juste après <head>, ajouter :

<link rel="alternate" type="application/rss+xml" href="/mediawiki/index.php?title=Special:Newpages&feed=rss" title="infond">



Aucun commentaire:

Enregistrer un commentaire