/** * Creates a new instance of EnterpriseSecurityException that includes a * root cause. * * @param string $userMessage The message displayed to the user * @param string $logMessage the message logged */ public function __construct($userMessage = '', $logMessage = '') { $cause = 0; if (empty($userMessage)) { $userMessage = null; } parent::__construct($userMessage); $this->logMessage = $logMessage; $this->logger = ESAPI::getAuditor("EnterpriseSecurityException"); if (!ESAPI::getSecurityConfiguration()->getDisableIntrusionDetection()) { ESAPI::getIntrusionDetector()->addException($this); } }
/** * The errorAction handles errors and exceptions. * * @return null */ public function errorAction() { $this->getResponse()->clearBody(); $errors = $this->_getParam('error_handler'); switch ($errors->type) { case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE: case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER: case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION: // 404 error -- controller or action not found $this->getResponse()->setHttpResponseCode(404); $this->view->message = 'The page requested was not found.'; break; default: // Log exceptions. EnterpriseSecurityException were automagically logged // so they are not logged here. if ($errors->exception instanceof EnterpriseSecurityException === false) { ESAPI::getIntrusionDetector()->addException($errors->exception); } // application error - if display_errors is off then the client // is redirected to the index controller error action where a // generic error message will be rendered. $bootstrap = $this->getInvokeArg('bootstrap'); if ($bootstrap->hasOption('phpsettings')) { $o = $bootstrap->getOption('phpsettings'); if (array_key_exists('display_errors', $o) && $o['display_errors'] !== '1') { if (Zend_Session::sessionExists()) { $ns = new Zend_Session_Namespace('Contact'); $ns->error = true; } $this->_helper->getHelper('redirector')->setCode(303)->gotoSimple('error', 'index', null, $this->_request->getParams()); return; } } $this->getResponse()->setHttpResponseCode(500); $this->view->message = 'Application error'; } // conditionally display exceptions if ($this->getInvokeArg('displayExceptions') == true) { $this->view->exception = $errors->exception; } $this->view->request = $errors->request; }
/** * The send action is the target for form submission. If the request does * not contain POST data then the response will be a redirect to the index * action where the form will be displayed. * POST data is validated and if successful an email will be sent before * redirecting the client away from the send action (to a success message). * If validation fails, the form is persisted in the session and the client * is redirected away from the send action to display the form with error * messages. * Whether or not the form is successfully validated, a user session will be * started so that the client can be tracked and certain thresholds enforced. * * @return null */ public function sendAction() { if (!$this->_request->isPost()) { $this->_helper->getHelper('redirector')->setCode(303)->gotoSimple('index', null, null, $this->_request->getParams()); } $ns = new Zend_Session_Namespace('Contact'); $ids = ESAPI::getIntrusionDetector(); // Is the form submission a valid one? $valid = $this->_form->isValid($this->_request->getPost()); // Check whether a csrf token is being re-used. This should not happen // often due to the POST-Redirect-GET design of this application. // If the token is being reused then throw an Intrusion Exception. if (isset($ns->history->token) && in_array($this->_form->token->getValue(), $ns->history->token)) { throw new IntrusionException('Form resubmission is not permitted.', 'Submitted token is one contained in the history of the current session.'); } if ($valid !== true) { // Add a formValidationErrors event to the client session. $ids->addEvent('ValidationErrorEvent', 'Form submission contained inputs that caused Validation errors.'); // There are certain validation errors that require an exception to // be thrown becuase errors for these elements is assumed to be // evidence of tampering. Throw IntrusionException if there are // errors in CSRFToken or recipientsMap. if ($this->_form->detectedTamper()) { throw new IntrusionException('The submitted form contained invalid information.', 'Form submission contained evidence of tampering!'); } // Log a warning about failed validation and include the error // messages. $validationErrMsgs = $this->_form->getMessages(null, true); $vmsgs = ''; foreach ($validationErrMsgs as $elem => $messageArray) { $vmsgs .= "[{$elem}:"; foreach ($messageArray as $validator => $message) { $vmsgs .= "{$validator}={$message};"; } $vmsgs .= "] "; } ESAPI::getAuditor('IndexController')->warning(Auditor::SECURITY, false, 'Validation failure messages: ' . $vmsgs); // Store the form in the session so that we can perform a redirect // away from the send action. // TODO expire it soon! $ns->submission = false; $ns->form = $this->_form; $this->_helper->getHelper('redirector')->setCode(303)->gotoSimple('index', null, null, $this->_request->getParams()); return; } // We have a valid form!! // Kill the CSRF cookie. setcookie(Form_Contact::CSRFCOOKIE, 'expired', 1, '/'); // Add token to map of submitted tokens if (is_array($ns->history->token)) { array_unshift($ns->history->token, $this->_form->token->getValue()); } else { $ns->history->token = array($this->_form->token->getValue()); } // extract the valid values from the form and send a mail $validValues = array(); $elements = $this->_form->getElements(); foreach ($elements as $key => $elem) { $validValues[$key] = $elem->getValue(); } // attempt to send a mail $successfulDelivery = $this->_helper->sendMail($validValues, $this->_recipientsConfig); // If mail delivery was not successful show a if ($successfulDelivery !== true) { ESAPI::getAuditor('IndexController')->warning(Auditor::SECURITY, false, 'Sending of mail failed - ' . $this->_helper->sendMail->getResponse()); $ids->addEvent('MailNotDeliveredEvent', 'successfully submitted valid contact form but mail was NOT sent.'); // TODO an encrypted logfile with failed email messages? // View helpful error message. throw new Exception('Successful form submission failed to be sent.'); } else { $ns->submission = true; $this->_helper->getHelper('redirector')->setCode(303)->gotoSimple('index', null, null, $this->_request->getParams()); return; } }
/** * This test will trigger IDS at a point which demonstrates the calculation * of event intervals. Using a threshold that triggers after 5 events * within 5 seconds, four events will occur at 1 second intervals, then a * pause of 3 seconds and then 3 more events in quick succession. IDS * should not trigger until the 7th event. * * * * e e e e eee * |-+-|-+-|-+-|-+-|-+-|-+-|-+-|-+-| * 0 1 2 3 4 5 6 7 8 * |___________________| * 5 second interval * * @return bool True on Pass. */ public function testSlidingInterval() { if ($this->_logFileLoc === false) { $this->fail('Cannot perform this test because the log file cannot be found.'); } $eventName = 'SlidingIntervalTestEvent'; $threshold = ESAPI::getSecurityConfiguration()->getQuota($eventName); $date = new DateTime(); $find = "User exceeded quota of {$threshold->count} " . "per {$threshold->interval} seconds for event {$eventName}." . sprintf(' Taking the following %d action%s - ', count($threshold->actions), count($threshold->actions) > 1 ? 's' : '') . implode(', ', $threshold->actions) . '.'; $m = 'Test attempts to detect IntrusionDetector' . ' action log message in logfile - %s'; // Generate 4 events at 1 sec intervals for ($i = 0; $i < 4; $i++) { ESAPI::getIntrusionDetector()->addEvent($eventName, 'This is a Test Event for IntrusionDetectorTest.'); usleep(1000000); } // Sleep for a further 2 secs (for a total of 3 secs between this and // the next event. usleep(2000000); // The following two events should not trigger... ESAPI::getIntrusionDetector()->addEvent($eventName, 'This is a Test Event for IntrusionDetectorTest.'); $this->assertFalse(fileContainsExpected($this->_logFileLoc, $find, $date, 10, $this->_logDateFormat), $m); ESAPI::getIntrusionDetector()->addEvent($eventName, 'This is a Test Event for IntrusionDetectorTest.'); $this->assertFalse(fileContainsExpected($this->_logFileLoc, $find, $date, 10, $this->_logDateFormat), $m); // OK this event SHOULD trigger! ESAPI::getIntrusionDetector()->addEvent($eventName, 'This is a Test Event for IntrusionDetectorTest.'); $this->assertTrue(fileContainsExpected($this->_logFileLoc, $find, $date, 10, $this->_logDateFormat), $m); }
/** * Request the delivery of emial via the mail transport defined in the mail * configuration file. * * @param array $values An array of name value pairs obtained from the * submitted form. {@see _compose} * * @return bool True if the request to the mail transport resulted in * successful delivery or False otherwise. */ public function request($values) { $this->_rawVals = $values; $defaultTransport = null; // get the bootstrap, need to retrieve configs $front = Zend_Controller_Front::getInstance(); $bs = $front->getParam('bootstrap'); // get mail configuration $mailConfigLoc = $bs->getOption('mailconfigloc'); $mailConfig = null; if (!empty($mailConfigLoc)) { $mailConfig = new Zend_Config_Ini($mailConfigLoc, APPLICATION_ENV, true); } if ($mailConfig instanceof Zend_Config === false) { $mailConfig = new Zend_config(array(), true); $this->Auditor->warning(Auditor::SECURITY, false, 'SendMail.request() cannot find mail configuration. Using defaults!'); } $transportType = 'sendmail'; $transportOpts = null; if (isset($mailConfig->transport->type)) { $transportType = $mailConfig->transport->type; unset($mailConfig->transport->type); $transportOpts = $mailConfig->transport; unset($mailConfig->transport); } $mailResource = new Zend_Application_Resource_Mail($mailConfig); if ($transportType == 'smtp') { $defaultTransport = new Zend_Mail_Transport_Smtp($transportOpts->host, $transportOpts->toArray()); } else { if (ini_get('safe_mode')) { $defaultTransport = new Zend_Mail_Transport_Sendmail(); } else { $defaultTransport = new Zend_Mail_Transport_Sendmail($transportOpts); } } Zend_Mail::setDefaultTransport($defaultTransport); // get recipients configuration $recipientConfigLoc = $bs->getOption('recipientsconfigloc'); $recipientConfig = null; if (!empty($recipientConfigLoc)) { $recipientConfig = new Zend_Config_Ini($recipientConfigLoc, APPLICATION_ENV, false); } if ($recipientConfig instanceof Zend_Config) { $this->_recipientConfig = $recipientConfig; } else { $this->_auditor->warning(Auditor::SECURITY, false, 'SendMail.request() cannot find any recipient data. Not sending mail!'); } // Compose Mail $mail = $this->_compose($mailConfig); // Make sure there's at least one recipient and bail if not. if ($this->_recipientConfig === null || sizeof($this->_recipientConfig) == 0) { $this->_response = 'No recipients of mail found!'; $m = $mail->getBodyText()->getContent(); $this->_auditor->info(Auditor::SECURITY, false, "No recipients of mail found. What do you want me to do with this: {$m}"); return false; } $cfg = null; if (sizeof($this->_recipientConfig) == 1) { $cfg = $this->_recipientConfig->current(); } else { $i = 0; $limit = $this->_recipientConfig->count(); while (++$i <= $limit) { $foo = $this->_recipientConfig->current()->display; if ($this->_rawVals['recipientMap'] === $this->_recipientConfig->current()->display) { break; } $this->_recipientConfig->next(); } $cfg = $this->_recipientConfig->current(); } foreach ($cfg as $_ => $rcpt) { if ($_ == 'display') { continue; } $mail->addTo($rcpt->address, $rcpt->name); } try { $mail->send(); } catch (Exception $e) { ESAPI::getIntrusionDetector()->addException($e); $this->_response = 'Call to mail.send threw an Exception: ' . $e->getMessage . '.'; return false; } if ($transportType == 'sendmail') { $this->_response = 'mail.send did NOT throw and exception using sendmail transport.'; $this->_auditor->info(Auditor::SECURITY, true, $this->_response); return true; } else { // get response and determine whether it represents success or failure. $connection = $defaultTransport->getConnection(); $response = $connection->getResponse(); $success = false; foreach ($response as $messageEntry) { $success = $this->_isSuccessMessage($messageEntry); $this->_auditor->info(Auditor::SECURITY, $success, "SMTP connection response: {$messageEntry}"); } if (sizeof($response, false) === 0) { // send got no reply... $this->_response = 'No Reply!'; $this->_auditor->info(Auditor::SECURITY, false, 'SMTP connection failed! No response.'); return $success; } else { if (sizeof($response, false) === 1) { // got one response. good. $this->_response = array_shift($response); return $success; } else { $this->_auditor->info(Auditor::SECURITY, false, 'SMTP connection returned multiple responses!'); $this->_response = 'Multiple SMTP responses, don\'t know what\'s happening...'; return false; } } } // unreached }