Added tipHash as security parameter to avoid XSS on links
authorNicole Cordes <cordes@cps-it.de>
Tue, 21 May 2013 18:05:19 +0000 (20:05 +0200)
committerNicole Cordes <cordes@cps-it.de>
Tue, 21 May 2013 18:05:19 +0000 (20:05 +0200)
ChangeLog
doc/manual.sxw
ext_emconf.php
pi1/class.tx_tipafriendplus_pi1.php
pi1/locallang.xml

index 70cd340..3777039 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,7 @@
 (add new changes on top of this file)
+2013-05-21     Nicole Cordes <cordes@cps-it.de>
+
+       * Added tipHash as security parameter to avoid XSS on links
 
 07-06-05   <>
 
index 6b828ed..433d859 100644 (file)
Binary files a/doc/manual.sxw and b/doc/manual.sxw differ
index 878642b..b7de775 100644 (file)
@@ -27,9 +27,9 @@ $EM_CONF[$_EXTKEY] = array(
        'modify_tables' => '',
        'clearcacheonload' => 0,
        'lockType' => '',
-       'author' => 'Erich Bircher',
-       'author_email' => 'typo3@internetgalerie.ch',
-       'author_company' => '',
+       'author' => 'Nicole Cordes',
+       'author_email' => 'cordes@cps-it.de',
+       'author_company' => 'CPS-IT GmbH',
        'CGLcompliance' => '',
        'CGLcompliance_note' => '',
        'constraints' => array(
index 23c65f2..fde35d8 100644 (file)
@@ -36,10 +36,15 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
        var $prefixId      = 'tx_tipafriendplus_pi1';           // Same as class name
        var $scriptRelPath = 'pi1/class.tx_tipafriendplus_pi1.php';     // Path to this script relative to the extension dir.
        var $extKey        = 'tipafriend_plus'; // The extension key.
-       var $pi_checkCHash = true;
-       
+       var $pi_checkCHash = TRUE;
+
        var $cObj;              // The backReference to the parent cObj object set at call time
-       
+
+       /**
+        * @var string
+        */
+       var $hmacSalt = 'tipafriend_plus';
+
        /**
         * The main method of the PlugIn
         *
@@ -49,18 +54,18 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
         */
 
         function main($content,$conf)  {
-               
+
        // code inserted to use free Captcha
                if (t3lib_extMgm::isLoaded('sr_freecap') ) {
              require_once(t3lib_extMgm::extPath('sr_freecap').'pi2/class.tx_srfreecap_pi2.php');
              $this->freeCap = t3lib_div::makeInstance('tx_srfreecap_pi2');
     }
        // code inserted to use free Captcha
-    
+
     $this->conf = $conf;
-    $this->pi_initPIflexForm();         
+    $this->pi_initPIflexForm();
          $this->pi_loadLL();
-                       
+
                $this->config['code'] = $this->cObj->stdWrap($this->conf['code'],$this->conf['code.']);
 
                        // template is read.
@@ -68,7 +73,7 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
                        // globally substituted markers, fonts and colors.
                $splitMark = md5(microtime());
 
-       
+
                        // TYpoLink
                $this->typolink_conf = $this->conf['typolink.'];
                $this->typolink_conf['additionalParams'] = $this->cObj->stdWrap($this->typolink_conf['additionalParams'],$this->typolink_conf['additionalParams.']);
@@ -79,7 +84,7 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
     else{
                    $codes=t3lib_div::trimExplode(',', $this->config['code']?$this->config['code']:$this->conf['defaultCode'],1);
         if (!count($codes))    $codes=array('');
-    }    
+    }
                while(list(,$theCode)=each($codes))     {
                        $theCode = (string)strtoupper(trim($theCode));
                        $this->theCode = $theCode;
@@ -107,132 +112,141 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
                }
                return $content;
        }
-       
+
                /**
         * [Describe function...]
         *
         * @return      [type]          ...
         */
        function tipform()      {
-               $GLOBALS['TSFE']->set_no_cache();
-               
-                               
+               $tipUrl = t3lib_div::_GP('tipUrl');
+               $tipHash = (string) t3lib_div::_GP('tipHash');
+               $calculatedHmac = t3lib_div::hmac($tipUrl, $this->hmacSalt);
 
-               $tipData = t3lib_div::_GP('TIPFORM');
-               $tipData['recipient'] = $this->getRecipients($tipData['recipient']);
-               list($tipData['email']) = explode(',',$this->getRecipients($tipData['email']));
-               $url = htmlspecialchars(strip_tags(t3lib_div::_GP('tipUrl')));
+               if ($tipHash !== $calculatedHmac) {
+                       // Show 404 error
+                       $GLOBALS['TSFE']->pageNotFoundAndExit($this->pi_getLL('no_valid_url'));
+               } else {
+                       $GLOBALS['TSFE']->set_no_cache();
 
-                       // Preparing markers
-               $wrappedSubpartArray=array();
-               $subpartArray=array();
 
-               $markerArray=array();
-               $markerArray['###FORM_URL###']=t3lib_div::getIndpEnv('REQUEST_URI');
-               $markerArray['###URL###']=$url;
-               $markerArray['###URL_ENCODED###']=rawurlencode($url);
-               $markerArray['###URL_SPECIALCHARS###']=htmlspecialchars($url);
-               $markerArray['###URL_DISPLAY###']=htmlspecialchars(strlen($url)>70 ? t3lib_div::fixed_lgd($url,30).t3lib_div::fixed_lgd($url,-30) : $url);
-
-    $markerArray['###TAF_LABEL_ERROR###']=$this->pi_getLL('error');
-    $markerArray['###TAF_ERROR_EXPL###']=$this->pi_getLL('error_expl');
-    $markerArray['###TAF_LABEL_NAME###']=$this->pi_getLL('name');
-    $markerArray['###TAF_LABEL_EMAIL###']=$this->pi_getLL('email');
-    $markerArray['###TAF_TITLE###']=$this->pi_getLL('title');
-    $markerArray['###TAF_LABEL_PATH###']=$this->pi_getLL('path');
-    
-    $markerArray['###TAF_LABEL_EMAIL_RECIPENT###']=$this->pi_getLL('email_recipent');
-    $markerArray['###TAF_LABEL_MESSAGE###']=$this->pi_getLL('message');
-    $markerArray['###TAF_LABEL_HTML###']=$this->pi_getLL('html');
-    
-    if (!$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'checkbox_html','sDEF')) $subpartArray['###HTML_INSERT###']='';
-    $markerArray['###TAF_LABEL_MUST###']=$this->pi_getLL('must');
-    $markerArray['###TAF_LABEL_SEND###']=$this->pi_getLL('send');
-    
-    $disclaimer =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'disclaimer_text','sDEF');
-    if (empty($disclaimer)) $disclaimer = $this->pi_getLL('disclaimer');
-    $markerArray['###TAF_DISCLAIMER###']= $disclaimer;
-    $markerArray['###TAF_CONFIRMATION###']=$this->pi_getLL('confirmation');
-    $markerArray['###TAF_LABEL_BACK###']=$this->pi_getLL('back');
-
-    $markerArray['###FORM_CAPTCHA_RESPONSE###'] = $this->pi_getLL('form_captcha_response');
-    
-    
-
-               $wrappedSubpartArray['###LINK###']=array('<a href="'.htmlspecialchars($url).'">','</a>');
-
-               
-               
-               // code inserted to use free Captcha
-               if (is_object($this->freeCap)) {
-                               $markerArray = array_merge($markerArray, $this->freeCap->makeCaptcha());
-               } else {
-                               $subpartArray['###CAPTCHA_INSERT###'] = '';
-               }
-    // code inserted to use free Captcha
 
+                       $tipData = t3lib_div::_GP('TIPFORM');
+                       $tipData['recipient'] = $this->getRecipients($tipData['recipient']);
+                       list($tipData['email']) = explode(',',$this->getRecipients($tipData['email']));
+                       $url = htmlspecialchars(strip_tags($tipUrl));
 
+                               // Preparing markers
+                       $wrappedSubpartArray=array();
+                       $subpartArray=array();
 
+                       $markerArray=array();
+                       $markerArray['###FORM_URL###']=t3lib_div::getIndpEnv('REQUEST_URI');
+                       $markerArray['###URL###']=$url;
+                       $markerArray['###URL_ENCODED###']=rawurlencode($url);
+                       $markerArray['###URL_SPECIALCHARS###']=htmlspecialchars($url);
+                       $markerArray['###URL_DISPLAY###']=htmlspecialchars(strlen($url)>70 ? t3lib_div::fixed_lgd($url,30).t3lib_div::fixed_lgd($url,-30) : $url);
 
+               $markerArray['###TAF_LABEL_ERROR###']=$this->pi_getLL('error');
+               $markerArray['###TAF_ERROR_EXPL###']=$this->pi_getLL('error_expl');
+               $markerArray['###TAF_LABEL_NAME###']=$this->pi_getLL('name');
+               $markerArray['###TAF_LABEL_EMAIL###']=$this->pi_getLL('email');
+               $markerArray['###TAF_TITLE###']=$this->pi_getLL('title');
+               $markerArray['###TAF_LABEL_PATH###']=$this->pi_getLL('path');
 
-                       // validation
-               $error=0;
-               $sent=0;
-               if (t3lib_div::_GP('sendTip'))  {
-   
-                       if ($this->validate($tipData,$url))     {
-                               $this->sendTip($tipData,$url);
-                               $sent=1;
+               $markerArray['###TAF_LABEL_EMAIL_RECIPENT###']=$this->pi_getLL('email_recipent');
+               $markerArray['###TAF_LABEL_MESSAGE###']=$this->pi_getLL('message');
+               $markerArray['###TAF_LABEL_HTML###']=$this->pi_getLL('html');
+
+               if (!$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'checkbox_html','sDEF')) $subpartArray['###HTML_INSERT###']='';
+               $markerArray['###TAF_LABEL_MUST###']=$this->pi_getLL('must');
+               $markerArray['###TAF_LABEL_SEND###']=$this->pi_getLL('send');
+
+               $disclaimer =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'disclaimer_text','sDEF');
+               if (empty($disclaimer)) $disclaimer = $this->pi_getLL('disclaimer');
+               $markerArray['###TAF_DISCLAIMER###']= $disclaimer;
+               $markerArray['###TAF_CONFIRMATION###']=$this->pi_getLL('confirmation');
+               $markerArray['###TAF_LABEL_BACK###']=$this->pi_getLL('back');
+
+               $markerArray['###FORM_CAPTCHA_RESPONSE###'] = $this->pi_getLL('form_captcha_response');
+
+
+
+                       $wrappedSubpartArray['###LINK###']=array('<a href="'.htmlspecialchars($url).'">','</a>');
+
+
+
+                       // code inserted to use free Captcha
+                       if (is_object($this->freeCap)) {
+                                       $markerArray = array_merge($markerArray, $this->freeCap->makeCaptcha());
                        } else {
-                               $error=1;
+                                       $subpartArray['###CAPTCHA_INSERT###'] = '';
                        }
-                       
-               }
-                       // Display form
-               if ($sent)      {
-                       $subpart = $this->cObj->getSubpart($this->templateCode,'###TEMPLATE_TIPFORM_SENT###');
+               // code inserted to use free Captcha
 
-                       $markerArray['###RECIPIENT###']=htmlspecialchars($tipData['recipient']);
 
-                       $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,$subpartArray,$wrappedSubpartArray);
-               } else {
 
-                       $captchaHTMLoutput = t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '';
 
-                               // Generate Captcha data and store string in session:
 
+                               // validation
+                       $error=0;
+                       $sent=0;
+                       if (t3lib_div::_GP('sendTip'))  {
 
-                       $subpart = $this->cObj->getSubpart($this->templateCode,'###TEMPLATE_TIPFORM###');
+                               if ($this->validate($tipData,$url))     {
+                                       $this->sendTip($tipData,$url);
+                                       $sent=1;
+                               } else {
+                                       $error=1;
+                               }
 
-                       $markerArray['###MESSAGE###']=htmlspecialchars($tipData['message']);
-                       $markerArray['###RECIPIENT###']=htmlspecialchars($tipData['recipient']);
-                       
-                       // Pre-fill form data if FE user in logged in
-      if (!$this->postvars && $GLOBALS['TSFE']->loginUser) {
-            $markerArray['###YOUR_EMAIL###'] = $GLOBALS['TSFE']->fe_user->user['email'];
-            $markerArray['###YOUR_NAME###'] = $GLOBALS['TSFE']->fe_user->user['name'];
-      } else {
-            $markerArray['###YOUR_EMAIL###']=htmlspecialchars($tipData['email']);
-            $markerArray['###YOUR_NAME###']=htmlspecialchars($tipData['name']);
-      } 
-      
-                       $markerArray['###HTML_MESSAGE###']=$tipData['html_message'] ? 'checked' : '';
-                       $markerArray['###CAPTCHA_HTML###']=$captchaHTMLoutput;
+                       }
+                               // Display form
+                       if ($sent)      {
+                               $subpart = $this->cObj->getSubpart($this->templateCode,'###TEMPLATE_TIPFORM_SENT###');
 
+                               $markerArray['###RECIPIENT###']=htmlspecialchars($tipData['recipient']);
 
-                       if (!$error)    {
-                               $subpartArray['###ERROR_MSG###']='';
-                       }
+                               $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,$subpartArray,$wrappedSubpartArray);
+                       } else {
 
+                               $captchaHTMLoutput = t3lib_extMgm::isLoaded('captcha') ? '<img src="'.t3lib_extMgm::siteRelPath('captcha').'captcha/captcha.php" alt="" />' : '';
 
-                               // Substitute
-                       $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,$subpartArray,$wrappedSubpartArray);
+                                       // Generate Captcha data and store string in session:
 
 
+                               $subpart = $this->cObj->getSubpart($this->templateCode,'###TEMPLATE_TIPFORM###');
+
+                               $markerArray['###MESSAGE###']=htmlspecialchars($tipData['message']);
+                               $markerArray['###RECIPIENT###']=htmlspecialchars($tipData['recipient']);
+
+                               // Pre-fill form data if FE user in logged in
+                 if (!$this->postvars && $GLOBALS['TSFE']->loginUser) {
+                               $markerArray['###YOUR_EMAIL###'] = $GLOBALS['TSFE']->fe_user->user['email'];
+                               $markerArray['###YOUR_NAME###'] = $GLOBALS['TSFE']->fe_user->user['name'];
+                 } else {
+                               $markerArray['###YOUR_EMAIL###']=htmlspecialchars($tipData['email']);
+                               $markerArray['###YOUR_NAME###']=htmlspecialchars($tipData['name']);
+                 }
+
+                               $markerArray['###HTML_MESSAGE###']=$tipData['html_message'] ? 'checked' : '';
+                               $markerArray['###CAPTCHA_HTML###']=$captchaHTMLoutput;
+
+
+                               if (!$error)    {
+                                       $subpartArray['###ERROR_MSG###']='';
+                               }
+
+
+                                       // Substitute
+                               $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,$subpartArray,$wrappedSubpartArray);
+
+
+                       }
+                       return $content;
                }
-               return $content;
        }
-       
+
        /**
         * [Describe function...]
         *
@@ -240,27 +254,27 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
         * @return      [type]          ...
         */
        function validate($tipData,$url)        {
-         
+
           // remove hmtl tags from url
          $url = strip_tags($url);
 
             // If the URL contains a '"', unset $url (suspecting XSS code)
         if (strstr($url,'"'))    {
-            $url = false;
+            $url = FALSE;
         }
             // check if the first part of the url is actually the server where tip-a-friend is installed. If not, unset $url.
         if(!preg_match('#\A'.t3lib_div::getIndpEnv('TYPO3_SITE_URL').'#',$url))    {
-            $url = false;
+            $url = FALSE;
         }
-        
-        $ret = true;
+
+        $ret = TRUE;
         if ( trim($tipData['name']) ) {
             if ( preg_match( '/[\r\n\f\e]/', $tipData['name'] ) > 0 )    {
                     // stop if there is a newline, carriage return, ...
                 $tipData['name'] = '';
-                $ret = false;
+                $ret = FALSE;
             } else {
-                $pattern = '/[^\d\s\w]/';    // search for characters that don't belong to one of the classes decimal, whitespace or word 
+                $pattern = '/[^\d\s\w]/';    // search for characters that don't belong to one of the classes decimal, whitespace or word
                 $tipData['name'] = trim( preg_replace( $pattern, '', $tipData['name'] ) );    // strip the mentioned characters
             }
         }
@@ -273,7 +287,7 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
                        $tipData['email'] &&
                        $tipData['recipient'] &&
                        ($this->freeCap->checkWord($tipData['captcha_response']))
-               
+
                        ) {
                                return 1;
                        }
@@ -297,7 +311,7 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
                }
                return implode(',',$listArr);
        }
-       
+
 
        /**
         * [Describe function...]
@@ -318,22 +332,22 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
                $markerArray['###YOUR_EMAIL###']=htmlspecialchars($tipData['email']);
                $markerArray['###YOUR_NAME###']=htmlspecialchars($tipData['name']);
                $markerArray['###URL###']=$url;
-               
+
                $subject =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'email_subject','sEmail');
     if (empty($subject)) $subject = $this->pi_getLL('mail_subject');
-    $markerArray['###TAF_MAIL_SUBJECT###']= $subject;  
+    $markerArray['###TAF_MAIL_SUBJECT###']= $subject;
     $link_text =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'email_link_text','sEmail');
     if (empty($link_text)) $link_text = $this->pi_getLL('mail_link');
-    $markerArray['###TAF_MAIL_LINK###']= $link_text;             
+    $markerArray['###TAF_MAIL_LINK###']= $link_text;
     $message =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'email_message_text','sEmail');
     if (empty($message)) $message = $this->pi_getLL('mail_message');
-    $markerArray['###TAF_MAIL_MESSAGE###']= $message;           
+    $markerArray['###TAF_MAIL_MESSAGE###']= $message;
     $footer =$this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'email_footer_text','sEmail');
     if (empty($footer)) $footer = $this->pi_getLL('mail_footer');
-    $markerArray['###TAF_MAIL_FOOTER###']= $footer;                            
-               
+    $markerArray['###TAF_MAIL_FOOTER###']= $footer;
+
+
 
-               
 
                        // Substitute in template
                $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,$subpartArray,$wrappedSubpartArray);
@@ -381,33 +395,45 @@ class tx_tipafriendplus_pi1 extends tslib_pibase {
 
        /**
         * [Describe function...]
-        * 
+        *
         * @return      [type]          ...
         */
        function tiplink()      {
                $url=t3lib_div::getIndpEnv('TYPO3_REQUEST_URL');
                $subpart = $this->cObj->getSubpart($this->templateCode,'###TEMPLATE_TIPLINK###');
 
-               $wrappedSubpartArray=array();
+               // Generate link configuration
                $tConf = $this->typolink_conf;
-               $tConf['additionalParams'].= '&tipUrl='.rawurlencode($url);
-               //debug($tConf);
-               $wrappedSubpartArray['###LINK###']= $this->cObj->typolinkWrap($tConf);
+               $tConf['additionalParams'] .= '&tipUrl='.rawurlencode($url) . '&tipHash=' . t3lib_div::hmac($url, $this->hmacSalt);
 
-               $markerArray=array();
-               $markerArray['###URL###']=$url;
-               $markerArray['###URL_ENCODED###']=rawurlencode($url);
-               $markerArray['###URL_SPECIALCHARS###']=htmlspecialchars($url);
-               
-    $markerArray['###TAF_LINK###']= $this->pi_getLL('link');
-               
-               
-               // Substitute
-               $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,array(),$wrappedSubpartArray);
-    return $content;
+               if (empty($subpart)) {
+                       // Support native link output for easier update
+                       if (!empty($this->conf['value'])) {
+                               $value = $this->cObj->stdWrap($this->conf['value'], $this->conf['value.']);
+                       } else {
+                               $value = $this->pi_getLL('link');
+                       }
+                       return $this->cObj->typoLink($value, $tConf);
+               } else {
+                       // Generate markerArray for template substitution
+                       $wrappedSubpartArray=array();
+                       $wrappedSubpartArray['###LINK###']= $this->cObj->typolinkWrap($tConf);
+
+                       $markerArray=array();
+                       $markerArray['###URL###']=$url;
+                       $markerArray['###URL_ENCODED###']=rawurlencode($url);
+                       $markerArray['###URL_SPECIALCHARS###']=htmlspecialchars($url);
+
+                       $markerArray['###TAF_LINK###']= $this->pi_getLL('link');
+
+
+                       // Substitute
+                       $content= $this->cObj->substituteMarkerArrayCached($subpart,$markerArray,array(),$wrappedSubpartArray);
+                       return $content;
+               }
        }
-       
-       
+
+
 }
 
 
index e89fcb1..a690af8 100644 (file)
@@ -9,6 +9,7 @@
     </meta>
     <data type="array">
         <languageKey index="default" type="array">
+                       <label index="no_valid_url">No valid url was given.</label>
              <label index="error">Error!</label>
              <label index="error_expl">You didn't fill in all required fields or the email addresses was not valid!</label>
              <label index="name">Your Name: *</label>
@@ -33,6 +34,7 @@
         <languageKey index="dk" type="array">
         </languageKey>
         <languageKey index="de" type="array">
+                       <label index="no_valid_url">Es wurde keine gültige URL übergeben.</label>
             <label index="error">Fehler!</label>
             <label index="error_expl">Sie haben nicht alle benötigten Felder ausgefüllt. Die mit einem * gekennzeichnete Felder müssen ausgefüllt werden!</label>
             <label index="name">Ihr Name: *</label>
@@ -55,7 +57,7 @@
             <label index="form_captcha_response">Code</label>
         </languageKey>
         <languageKey index="no" type="array">
-        </languageKey> 
+        </languageKey>
         <languageKey index="it" type="array">
              <label index="error">Errore!</label>
              <label index="error_expl">Non hai riempito tutti i campi obbligatori nel modulo o l'indirizzo email non e' valido!</label>
@@ -77,7 +79,7 @@
              <label index="mail_footer">Cordiali saluti</label>
              <label index="link">Segnala la pagina...</label>
              <label index="form_captcha_response">Codice</label>
-        </languageKey> 
+        </languageKey>
         <languageKey index="fr" type="array">
         </languageKey>
         <languageKey index="es" type="array">