3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
20 * Define the threshold for the ids reactions.
23 private $threshold = [
37 * This function includes the IDS vendor parts and runs the
38 * detection routines on the request array.
44 public function check($route) {
45 if (CRM_Core_Permission
::check('skip IDS check')) {
49 // lets bypass a few civicrm urls from this check
50 $skip = ['civicrm/admin/setting/updateConfigBackend', 'civicrm/admin/messageTemplates'];
51 CRM_Utils_Hook
::idsException($skip);
52 $this->path
= $route['path'];
53 if (in_array($this->path
, $skip)) {
57 $init = self
::create(self
::createRouteConfig($route));
59 // Add request url and user agent.
60 $_REQUEST['IDS_request_uri'] = $_SERVER['REQUEST_URI'];
61 if (isset($_SERVER['HTTP_USER_AGENT'])) {
62 $_REQUEST['IDS_user_agent'] = $_SERVER['HTTP_USER_AGENT'];
65 require_once 'IDS/Monitor.php';
66 $ids = new \
IDS_Monitor($_REQUEST, $init);
68 $result = $ids->run();
69 if (!$result->isEmpty()) {
70 $this->react($result);
77 * Create a new PHPIDS configuration object.
79 * @param array $config
80 * PHPIDS configuration array (per INI format).
83 protected static function create($config) {
84 require_once 'IDS/Init.php';
85 $init = \IDS_Init
::init(NULL);
86 $init->setConfig($config, TRUE);
89 $reflection = new \
ReflectionProperty('IDS_Init', 'instances');
90 $reflection->setAccessible(TRUE);
91 $value = $reflection->getValue(NULL);
93 $reflection->setValue(NULL, $value);
99 * Create conservative, minimalist IDS configuration.
103 public static function createBaseConfig() {
104 $config = \CRM_Core_Config
::singleton();
105 $tmpDir = empty($config->uploadDir
) ? Civi
::paths()->getVariable('civicrm.compile', 'path') : $config->uploadDir
;
106 $pkgs = Civi
::paths()->getVariable('civicrm.packages', 'path');
110 'filter_type' => 'xml',
111 'filter_path' => "{$pkgs}/IDS/default_filter.xml",
112 'tmp_path' => $tmpDir,
113 'HTML_Purifier_Path' => $pkgs . '/IDS/vendors/htmlpurifier/HTMLPurifier.auto.php',
114 'HTML_Purifier_Cache' => $tmpDir,
116 'exceptions' => ['__utmz', '__utmc'],
122 * Create the standard, general-purpose IDS configuration used by many pages.
126 public static function createStandardConfig() {
144 'thankyou_footer_text',
151 'confirm_footer_text',
152 'confirm_email_text',
163 $result = self
::createBaseConfig();
165 $result['General']['exceptions'] = array_merge(
166 $result['General']['exceptions'],
174 * @param array $route
177 public static function createRouteConfig($route) {
178 $config = \CRM_Core_IDS
::createStandardConfig();
179 foreach (['json', 'html', 'exceptions'] as $section) {
180 if (isset($route['ids_arguments'][$section])) {
181 if (!isset($config['General'][$section])) {
182 $config['General'][$section] = [];
184 foreach ($route['ids_arguments'][$section] as $v) {
185 $config['General'][$section][] = $v;
187 $config['General'][$section] = array_unique($config['General'][$section]);
194 * This function reacts on the values in the incoming results array.
196 * Depending on the impact value certain actions are
199 * @param IDS_Report $result
203 public function react(IDS_Report
$result) {
205 $impact = $result->getImpact();
206 if ($impact >= $this->threshold
['kick']) {
207 $this->log($result, 3, $impact);
211 elseif ($impact >= $this->threshold
['warn']) {
212 $this->log($result, 2, $impact);
213 $this->warn($result);
216 elseif ($impact >= $this->threshold
['log']) {
217 $this->log($result, 0, $impact);
226 * This function writes an entry about the intrusion to the database.
228 * @param array $result
229 * @param int $reaction
233 private function log($result, $reaction = 0) {
234 // Include X_FORWARD_FOR ip address if set as per IDS patten.
235 $ip = $_SERVER['REMOTE_ADDR'] . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ?
' (' . $_SERVER['HTTP_X_FORWARDED_FOR'] . ')' : '');
238 $session = CRM_Core_Session
::singleton();
239 foreach ($result as $event) {
241 'name' => $event->getName(),
242 'value' => stripslashes($event->getValue()),
243 'page' => $_SERVER['REQUEST_URI'],
244 'userid' => $session->get('userID'),
245 'session' => session_id() ?
session_id() : '0',
247 'reaction' => $reaction,
248 'impact' => $result->getImpact(),
252 CRM_Core_Error
::debug_var('IDS Detector Details', $data);
259 * @param array $result
263 private function warn($result) {
268 * Create an error that prevents the user from continuing.
272 private function kick() {
273 $session = CRM_Core_Session
::singleton();
276 $msg = ts('There is a validation error with your HTML input. Your activity is a bit suspicious, hence aborting');
280 ["civicrm/ajax/rest", "civicrm/api/json"]
282 require_once "api/v3/utils.php";
283 $error = civicrm_api3_create_error(
286 'IP' => $_SERVER['REMOTE_ADDR'],
287 'error_code' => 'IDS_KICK',
288 'level' => 'security',
289 'referer' => $_SERVER['HTTP_REFERER'],
290 'reason' => 'XSS suspected',
293 CRM_Utils_JSON
::output($error);
295 CRM_Core_Error
::fatal($msg);