Fixes XSRF vulnerabilities in password page, admin pages, and GoogleApps pages.
authorVincent Zanotti <vincent.zanotti@polytechnique.org>
Fri, 25 Apr 2008 15:34:51 +0000 (17:34 +0200)
committerVincent Zanotti <vincent.zanotti@polytechnique.org>
Fri, 25 Apr 2008 15:35:53 +0000 (17:35 +0200)
Signed-off-by: Vincent Zanotti <vincent.zanotti@polytechnique.org>
14 files changed:
classes/csvimporter.php
classes/pltableeditor.php
modules/admin.php
modules/email.php
modules/googleapps.php
modules/platal.php
templates/admin/ipwatcher.tpl
templates/admin/utilisateurs.tpl
templates/admin/valider.tpl
templates/core/table-editor.tpl
templates/emails/redirect.tpl
templates/googleapps/index.tpl
templates/include/csv-importer.tpl
templates/platal/motdepasse.tpl

index 6590df4..e065195 100644 (file)
@@ -330,6 +330,9 @@ class CSVImporter
                 $fields[]     = $key;
             }
             if ($current == 'valid' && Env::has('csv_valid')) {
+                if (!Session::has_xsrf_token()) {
+                    $page->kill("L'opération n'a pas pu être effectuée, merci de réessayer.");
+                }
                 $this->run($_SESSION['csv_action'], $insert, $update);
                 $page->assign('csv_done', true);
                 $this->cleanSession($sesfields);
index 7cfc2e8..cbd944a 100644 (file)
@@ -192,7 +192,8 @@ class PLTableEditor
     {
         $page->changeTpl('core/table-editor.tpl');
         $list = true;
-        if ($action == 'delete') {
+
+        if ($action == 'delete' && Session::has_xsrf_token()) {
             if (!isset($this->delete_action)) {
                 foreach ($this->jtables as $table => $j)
                     XDB::execute("DELETE FROM {$table} WHERE {$j['joinid']} = {?}{$j['joinextra']}", $id);
@@ -208,6 +209,8 @@ class PLTableEditor
             } else {
                 $page->trig("Impossible de supprimer l'entrée.");
             }
+        } else if ($action == 'delete') {
+            $page->trig("Impossible de supprimer l'entrée, merci de réessayer.");
         }
         if ($action == 'edit') {
             $r = XDB::query("SELECT * FROM {$this->table} WHERE {$this->idfield} = {?} AND {$this->whereclause}",$id);
@@ -237,7 +240,7 @@ class PLTableEditor
             }
             $list = false;
         }
-        if ($action == 'update') {
+        if ($action == 'update' && Session::has_xsrf_token()) {
             $values = "";
             $cancel = false;
             foreach ($this->vars as $field => $descr) {
@@ -286,6 +289,8 @@ class PLTableEditor
             if (!$this->auto_return) {
                 return $this->apply($page, 'edit', $id);
             }
+        } else if ($action == 'update') {
+            $page->trig("Impossible de mettre à jour, merci de réessayer.");
         }
         if ($action == 'sort') {
             $this->sortfield = $id;
index d878f03..336f848 100644 (file)
@@ -413,6 +413,9 @@ class AdminModule extends PLModule
 
             // Check if there was a submission
             foreach($_POST as $key => $val) {
+                if (!Session::has_xsrf_token()) {
+                    $page->kill("L'opération de modification de l'utilisateur a échouée, merci de réessayer.");
+                }
                 switch ($key) {
                     case "add_fwd":
                         $email = trim(Env::v('email'));
@@ -820,22 +823,27 @@ class AdminModule extends PLModule
 
         $page->assign('promo',$promo);
 
-        if ($validate) {
+        if ($validate && Session::has_xsrf_token()) {
             $new_deces = array();
             $res = XDB::iterRow("SELECT user_id,matricule,nom,prenom,deces FROM auth_user_md5 WHERE promo = {?}", $promo);
             while (list($uid,$mat,$nom,$prenom,$deces) = $res->next()) {
                 $val = Env::v($mat);
-            if($val == $deces || empty($val)) continue;
-            XDB::execute('UPDATE auth_user_md5 SET deces={?} WHERE matricule = {?}', $val, $mat);
-            $new_deces[] = array('name' => "$prenom $nom", 'date' => "$val");
-            if($deces=='0000-00-00' or empty($deces)) {
-                require_once('notifs.inc.php');
-                register_watch_op($uid, WATCH_DEATH, $val);
-                require_once('user.func.inc.php');
-                user_clear_all_subs($uid, false);   // by default, dead ppl do not loose their email
-            }
+                if($val == $deces || empty($val)) {
+                    continue;
+                }
+
+                XDB::execute('UPDATE auth_user_md5 SET deces={?} WHERE matricule = {?}', $val, $mat);
+                $new_deces[] = array('name' => "$prenom $nom", 'date' => "$val");
+                if($deces == '0000-00-00' || empty($deces)) {
+                    require_once('notifs.inc.php');
+                    register_watch_op($uid, WATCH_DEATH, $val);
+                    require_once('user.func.inc.php');
+                    user_clear_all_subs($uid, false);   // by default, dead ppl do not loose their email
+                }
             }
             $page->assign('new_deces',$new_deces);
+        } else if (!$validate) {
+            $page->trig("La mise à jour des dates de decès à échouée, merci de réessayer.");
         }
 
         $res = XDB::iterator('SELECT matricule, nom, prenom, deces FROM auth_user_md5 WHERE promo = {?} ORDER BY nom,prenom', $promo);
@@ -919,7 +927,11 @@ class AdminModule extends PLModule
 
         if(Env::has('uid') && Env::has('type') && Env::has('stamp')) {
             $req = Validate::get_typed_request(Env::v('uid'), Env::v('type'), Env::v('stamp'));
-            if($req) { $req->handle_formu(); }
+            if($req && Session::has_xsrf_token()) {
+                $req->handle_formu();
+            } else if ($req) {
+                $page->trig("L'opération a échoué, merci de réessayer.");
+            }
         }
 
         $r = XDB::iterator('SHOW COLUMNS FROM requests_answers');
@@ -1018,6 +1030,7 @@ class AdminModule extends PLModule
            $page->setRssLink('Changement Récents',
                              '/Site/AllRecentChanges?action=rss&user=' . S::v('forlife') . '&hash=' . S::v('core_rss_hash'));
         }
+
         // update wiki perms
         if ($action == 'update') {
             $perms_read = Post::v('read');
@@ -1100,8 +1113,12 @@ class AdminModule extends PLModule
         $page->assign('states', $states);
 
         switch (Post::v('action')) {
-        case 'create':
+          case 'create':
             if (trim(Post::v('ipN')) != '') {
+                if (!Session::has_xsrf_token()) {
+                    $page->trig("L'ajout d'une IP à surveiller a échoué, merci de réessayer.");
+                    break;
+                }
                 Xdb::execute('INSERT IGNORE INTO ip_watch (ip, mask, state, detection, last, uid, description)
                                           VALUES ({?}, {?}, {?}, CURDATE(), NOW(), {?}, {?})',
                              ip_to_uint(trim(Post::v('ipN'))), ip_to_uint(trim(Post::v('maskN'))),
@@ -1109,16 +1126,24 @@ class AdminModule extends PLModule
             };
             break;
 
-        case 'edit':
+          case 'edit':
+            if (!Session::has_xsrf_token()) {
+                $page->trig("L'édition de l'IP a échoué, merci de réessayer.");
+                break;
+            }
             Xdb::execute('UPDATE ip_watch
                              SET state = {?}, last = NOW(), uid = {?}, description = {?}, mask = {?}
                            WHERE ip = {?}', Post::v('stateN'), S::i('uid'), Post::v('descriptionN'),
                           ip_to_uint(Post::v('maskN')), ip_to_uint(Post::v('ipN')));
             break;
 
-        default:
+          default:
             if ($action == 'delete' && !is_null($ip)) {
-                Xdb::execute('DELETE FROM ip_watch WHERE ip = {?}', ip_to_uint($ip));
+                if (Session::has_xsrf_token()) {
+                    Xdb::execute('DELETE FROM ip_watch WHERE ip = {?}', ip_to_uint($ip));
+                } else {
+                    $page->trig("La suppression de l'adresse IP a échouée, merci de réssayer.");
+                }
             }
         }
         if ($action != 'create' && $action != 'edit') {
index c6200bb..2642477 100644 (file)
@@ -223,7 +223,7 @@ class EmailModule extends PLModule
             $redirect->modify_one_email_redirect($email, $rewrite);
         }
 
-        if (Env::has('emailop')) {
+        if (Env::has('emailop') && Session::has_xsrf_token()) {
             $actifs = Env::v('emails_actifs', Array());
             print_r(Env::v('emails_rewrite'));
             if (Env::v('emailop') == "ajouter" && Env::has('email')) {
@@ -234,6 +234,8 @@ class EmailModule extends PLModule
                 $page->assign('retour', $redirect->modify_email($actifs,
                     Env::v('emails_rewrite',Array())));
             }
+        } else if (Env::has('emailop')) {
+            $page->trig('L\'ajout d\'une nouvelle redirection a échoué, merci de réessayer.');
         }
 
         $res = XDB::query(
index fda080f..72e3488 100644 (file)
@@ -68,12 +68,18 @@ class GoogleAppsModule extends PLModule
                 } else if ($subaction == 'nosync') {
                     $account->set_password_sync(false);
                 } else if (Post::has('response2') && !$account->sync_password) {
-                    $account->set_password(Post::v('response2'));
+                    if (Session::has_xsrf_token()) {
+                        $account->set_password(Post::v('response2'));
+                    } else {
+                        $page->trig("Le changement de ton mot de passe Google Apps a échoué, merci de réessayer.");
+                    }
                 }
             }
 
             if ($action == 'suspend' && Post::has('suspend') && $account->active()) {
-                if ($account->pending_update_suspension) {
+                if (!Session::has_xsrf_token()) {
+                    $page->trig("La demande de suspension de ton compte a échouée, merci de réessayer.");
+                } else if ($account->pending_update_suspension) {
                     $page->trig("Ton compte est déjà en cours de désactivation.");
                 } else {
                     if ($redirect->modify_one_email('googleapps', false) == SUCCESS) {
@@ -101,8 +107,12 @@ class GoogleAppsModule extends PLModule
                     $password = Post::v('response2');
                 }
 
-                $account->create($password_sync, $password, $redirect_mails);
-                $page->trig("La demande de création de ton compte Google Apps a bien été enregistrée.");
+                if (Session::has_xsrf_token()) {
+                    $account->create($password_sync, $password, $redirect_mails);
+                    $page->trig("La demande de création de ton compte Google Apps a bien été enregistrée.");
+                } else {
+                    $page->trig("La demande de création de ton compte Google Apps a échouée, merci de réessayer.");
+                }
             }
         }
 
index 0fb4c19..a58398b 100644 (file)
@@ -187,7 +187,7 @@ class PlatalModule extends PLModule
     {
         global $globals;
 
-        if (Post::has('response2'))  {
+        if (Post::has('response2') && Session::has_xsrf_token())  {
             require_once 'secure_hash.inc.php';
 
             $_SESSION['password'] = $password = Post::v('response2');
@@ -216,6 +216,8 @@ class PlatalModule extends PLModule
 
             $page->changeTpl('platal/motdepasse.success.tpl');
             $page->run();
+        } else if (Post::has('response2')) {
+            $page->trig('Le changement de ton mot de passe a échoué, merci de réessayer.');
         }
 
         $page->changeTpl('platal/motdepasse.tpl');
index ae30afc..0a526b9 100644 (file)
@@ -59,7 +59,7 @@
     </td>
     <td class="right">
       <a href="admin/ipwatch/edit/{$ip.ip}">{icon name=page_edit title="Editer"}</a>
-      <a href="admin/ipwatch/delete/{$ip.ip}">{icon name=delete title="Supprimer"}</a>
+      <a href="admin/ipwatch/delete/{$ip.ip}?token={xsrf_token}">{icon name=delete title="Supprimer"}</a>
     </td>
   </tr>
   {/foreach}
@@ -67,6 +67,7 @@
 {elseif $action eq "create" || $action eq "edit"}
 [<a href="admin/ipwatch">Retour à la liste des IPs surveillées</a>]<br /><br />
 <form method="post" action="admin/ipwatch">
+{xsrf_token_field}
 <table class="tinybicol">
   <tr>
     <th colspan="2">Commenter une adresse IP</th>
index cca5bc1..6829909 100644 (file)
@@ -28,6 +28,7 @@
 
 {if $smarty.post.u_kill_conf}
 <form method="post" action="admin/user">
+  {xsrf_token_field}
   <div class="center">
     <input type="hidden" name="user_id" value="{$smarty.request.user_id}" />
     Confirmer la suppression de {$smarty.request.user_id}&nbsp;&nbsp;
@@ -37,6 +38,7 @@
 {else}
 
 <form method="post" action="admin/user">
+  {xsrf_token_field}
   <table class="tinybicol" cellspacing="0" cellpadding="2">
     <tr>
       <th>
@@ -117,6 +119,7 @@ function ban_read()
 {/literal}
 
 <form id="auth" method="post" action="admin/user">
+  {xsrf_token_field}
   <table cellspacing="0" cellpadding="2" class="tinybicol">
     <tr>
       <th colspan="2">
@@ -272,6 +275,7 @@ Ne pas utiliser [Désinscrire] si le but est d'exclure la personne.
 Pour ceci changer ses permissions en 'disabled'.
 </p>
 <form id="alias" method="post" action="admin/user">
+  {xsrf_token_field}
   <table class="tinybicol" cellpadding="2" cellspacing="0">
     <tr>
       <th class="alias" colspan="3">
@@ -319,6 +323,7 @@ Pour ceci changer ses permissions en 'disabled'.
 <p><strong>* à ne modifier qu'avec l'accord express de l'utilisateur !!!</strong></p>
 
 <form id="bans" method="post" action="admin/user">
+  {xsrf_token_field}
   <table cellspacing="0" cellpadding="2" class="tinybicol">
     <tr>
       <th colspan="4">
@@ -368,6 +373,7 @@ Pour ceci changer ses permissions en 'disabled'.
 {test_email forlife=$mr.forlife}
 
 <form id="fwds" method="post" action="admin/user#fwds">
+  {xsrf_token_field}
   <table class="bicol" cellpadding="2" cellspacing="0">
     <tr>
       <th colspan="4">
index 040473b..67ad572 100644 (file)
@@ -73,6 +73,7 @@ function toggleField(name, id, obj) {
   <tr {if $preview_id neq $valid->id()}style="display: none"{/if} id="edit_{$valid->id()}">
     <td colspan="2" class="center">
       <form enctype="multipart/form-data" action="{$platal->pl_self(0)}/edit/{$valid->id()}#valid{$valid->id()}" method="post">
+        {xsrf_token_field}
         <div>
           {include file=$valid->editor()}
           <input type="hidden" name="uid"    value="{$valid->uid}" />
@@ -106,6 +107,7 @@ function toggleField(name, id, obj) {
   <tr {if $valid->comments|@count eq 0}style="display: none"{/if} id="comment_{$valid->id()}">
     <td colspan='2' class='center'>
       <form action="admin/validate" method="post">
+        {xsrf_token_field}
         <div>
           <input type="hidden" name="uid"    value="{$valid->uid}" />
           <input type="hidden" name="type"   value="{$valid->type}" />
@@ -131,6 +133,7 @@ function toggleField(name, id, obj) {
   <tr>
     <td colspan='2' {popup caption="Règles de validation" text=$valid->ruleText()}>
       <form action="admin/validate" method="post">
+        {xsrf_token_field}
         <div>
           Réponse préremplie&nbsp;:
           <select onchange="this.form.comm.value=this.value">
index 7bd9a4f..df3b459 100644 (file)
@@ -75,7 +75,7 @@
   <td class="action">
     {if !$readonly}
     <a href="{$t->pl}/edit/{$idval}">{icon name=page_edit title='éditer'}</a>
-    <a href="{$t->pl}/delete/{$idval}">{icon name=delete title='supprimer'}</a>
+    <a href="{$t->pl}/delete/{$idval}?token={xsrf_token}">{icon name=delete title='supprimer'}</a>
     {/if}
   </td>
   {/if}
 {else}
 
 <form method="post" action="{$t->pl}/update/{$id}">
+  {xsrf_token_field}
   <table class="bicol">
     <tr class="impair">
       <th colspan="2">
index b492048..83cf386 100644 (file)
           Ajouter une adresse email&nbsp;:
           <input type="text" size="35" maxlength="60" name="email" value="" />
           &nbsp;&nbsp;<input type="submit" value="ajouter" name="emailop" />
+          {xsrf_token_field}
         </div>
         </form>
       </td></tr>
index 2c01f9e..f475428 100644 (file)
     {/if}
 
     <form action="googleapps/create" method="post" id="changepass2">
+    {xsrf_token_field}
     <tr class="pair">
       <td colspan="2"><b>Redirection des emails :</b></td>
     </tr>
       Si tu ne souhaites plus utiliser ton compte, tu peux le désactiver :<br /><br />
       <div class="center">
         <form action="googleapps/suspend" method="post">
+          {xsrf_token_field}
           <input type="submit" name="suspend" value="Désactiver mon compte Google Apps" />
         </form>
       </div>
             </table>
           </form>
           <form action="googleapps/password#password" method="post" id="changepass2">
+            {xsrf_token_field}
             <input type="hidden" name="response2"  value="" />
           </form><br />
           Pour une sécurité optimale, ton mot de passe circule de manière sécurisée (https).
index 506f4ef..0660a2c 100644 (file)
@@ -61,6 +61,7 @@
 {/literal}
 //]]></script>
 <form action="{$csv_path}" method="post" id="csv_form">
+  {xsrf_token_field}
   <div class="center" style="padding-bottom: 1em">
     Import d'un CSV&nbsp;:
     {if $csv_page eq 'source'}
index 6bd037b..390be6c 100644 (file)
@@ -67,6 +67,7 @@
 </form>
 <form action="{$smarty.server.REQUEST_URI}" method="post" id="changepass2">
 <p>
+{xsrf_token_field}
 <input type="hidden" name="response2"  value="" />
 </p>
 </form>