diff options
author | Dmitry <dmitry@dhtmlx.com> | 2012-05-22 16:51:16 +0200 |
---|---|---|
committer | Dmitry <dmitry@dhtmlx.com> | 2012-05-22 16:51:16 +0200 |
commit | 026ddb3374e533dbd26a3374eb316092e762e2a3 (patch) | |
tree | 89a9ee5f03b3c755d9498681c0ec64cf7eb45bb8 /codebase | |
parent | dff9912b9ee40fbac29c54b4cf67591e11b5e4cb (diff) | |
parent | 05ad07fee439616159c687a806270fd587af9abc (diff) | |
download | connector-php-026ddb3374e533dbd26a3374eb316092e762e2a3.zip connector-php-026ddb3374e533dbd26a3374eb316092e762e2a3.tar.gz connector-php-026ddb3374e533dbd26a3374eb316092e762e2a3.tar.bz2 |
Merge branch 'master' of 192.168.1.251:connector-php
Diffstat (limited to 'codebase')
-rw-r--r-- | codebase/data_connector.php | 30 | ||||
-rw-r--r-- | codebase/dataprocessor.php | 5 | ||||
-rw-r--r-- | codebase/xss_filter.php | 195 |
3 files changed, 225 insertions, 5 deletions
diff --git a/codebase/data_connector.php b/codebase/data_connector.php index 36cafa0..ac76c74 100644 --- a/codebase/data_connector.php +++ b/codebase/data_connector.php @@ -9,8 +9,13 @@ class CommonDataProcessor extends DataProcessor{ protected function get_post_values($ids){ if (isset($_GET['action'])){ $data = array(); - if (isset($_POST["id"])) - $data[$_POST["id"]] = $_POST; + if (isset($_POST["id"])){ + $dataset = array(); + foreach($_POST as $key=>$value) + $dataset[$key] = ConnectorSecurity::filter($value); + + $data[$_POST["id"]] = $dataset; + } else $data["dummy_id"] = $_POST; return $data; @@ -90,9 +95,13 @@ class DataConnector extends Connector{ public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ if (!$item_type) $item_type="CommonDataItem"; if (!$data_type) $data_type="CommonDataProcessor"; - $section = array(); + + $this->sections = array(); + $this->attributes = array(); + if (!$render_type) $render_type="RenderStrategy"; parent::__construct($res,$type,$item_type,$data_type,$render_type); + } protected $sections; @@ -100,6 +109,11 @@ class DataConnector extends Connector{ $this->sections[$name] = $string; } + protected $attributes; + public function add_top_attribute($name, $string){ + $this->attributes[$name] = $string; + } + protected function parse_request_mode(){ //do nothing, at least for now } @@ -130,12 +144,20 @@ class DataConnector extends Connector{ if (isset($_GET["start"]) && isset($_GET["count"])) $this->request->set_limit($_GET["start"],$_GET["count"]); + + $key = ConnectorSecurity::checkCSRF($this->editing); + if ($key !== "") + $this->add_top_attribute("dhx_security", $key); } /*! renders self as xml, starting part */ protected function xml_start(){ - $start = "<data>"; + $start = "<data"; + foreach($this->attributes as $k=>$v) + $start .= " ".$k."='".$v."'"; + $start.= ">"; + foreach($this->sections as $k=>$v) $start .= "<".$k.">".$v."</".$k.">\n"; return $start; diff --git a/codebase/dataprocessor.php b/codebase/dataprocessor.php index 348c8e2..8418d40 100644 --- a/codebase/dataprocessor.php +++ b/codebase/dataprocessor.php @@ -5,6 +5,9 @@ */ /*! Base DataProcessor handling **/ + +require_once("xss_filter.php"); + class DataProcessor{ protected $connector;//!< Connector instance protected $config;//!< DataConfig instance @@ -52,7 +55,7 @@ class DataProcessor{ if (sizeof($details)==1) continue; $name=$this->name_data($details[1]); - $data[$details[0]][$name]=$value; + $data[$details[0]][$name]=ConnectorSecurity::filter($value); } return $data; diff --git a/codebase/xss_filter.php b/codebase/xss_filter.php new file mode 100644 index 0000000..9018443 --- /dev/null +++ b/codebase/xss_filter.php @@ -0,0 +1,195 @@ +<?php + +// +----------------------------------------------------------------------+ +// | Copyright (c) 2001-2008 Liip AG | +// +----------------------------------------------------------------------+ +// | Licensed under the Apache License, Version 2.0 (the "License"); | +// | you may not use this file except in compliance with the License. | +// | You may obtain a copy of the License at | +// | http://www.apache.org/licenses/LICENSE-2.0 | +// | Unless required by applicable law or agreed to in writing, software | +// | distributed under the License is distributed on an "AS IS" BASIS, | +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | +// | implied. See the License for the specific language governing | +// | permissions and limitations under the License. | +// +----------------------------------------------------------------------+ +// | Author: Christian Stocker <christian.stocker@liip.ch> | +// +----------------------------------------------------------------------+ + + +//original name was lx_externalinput_clean +//renamed to prevent possible conflicts +class dhx_externalinput_clean { + // this basic clean should clean html code from + // lot of possible malicious code for Cross Site Scripting + // use it whereever you get external input + + // you can also set $filterOut to some use html cleaning, but I don't know of any code, which could + // exploit that. But if you want to be sure, set it to eg. array("Tidy","Dom"); + static function basic($string, $filterIn = array("Tidy","Dom","Striptags"), $filterOut = "none") { + $string = self::tidyUp($string, $filterIn); + $string = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $string); + + // fix &entitiy\n; + $string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $string); + $string = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $string); + + $string = html_entity_decode($string, ENT_COMPAT, "UTF-8"); + + // remove any attribute starting with "on" or xmlns + $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $string); + + // remove javascript: and vbscript: protocol + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*-moz-binding[\x00-\x20]*:#Uu', '$1=$2nomozbinding...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $string); + + //remove any style attributes, IE allows too much stupid things in them, eg. + //<span style="width: expression(alert('Ping!'));"></span> + // and in general you really don't want style declarations in your UGC + + $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])style[^>]*>#iUu', "$1>", $string); + + //remove namespaced elements (we do not need them...) + $string = preg_replace('#</*\w+:\w[^>]*>#i', "", $string); + + //remove really unwanted tags + do { + $oldstring = $string; + $string = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $string); + } while ($oldstring != $string); + + return self::tidyUp($string, $filterOut); + } + + static function tidyUp($string, $filters) { + if (is_array($filters)) { + foreach ($filters as $filter) { + $return = self::tidyUpWithFilter($string, $filter); + if ($return !== false) { + return $return; + } + } + } else { + $return = self::tidyUpWithFilter($string, $filters); + } + // if no filter matched, use the Striptags filter to be sure. + if ($return === false) { + return self::tidyUpModuleStriptags($string); + } else { + return $return; + } + } + + static private function tidyUpWithFilter($string, $filter) { + if (is_callable(array("self", "tidyUpModule" . $filter))) { + return call_user_func(array("self", "tidyUpModule" . $filter), $string); + } + return false; + } + + static private function tidyUpModuleStriptags($string) { + + return strip_tags($string); + } + + static private function tidyUpModuleNone($string) { + return $string; + } + + static private function tidyUpModuleDom($string) { + $dom = new domdocument(); + @$dom->loadHTML("<html><body>" . $string . "</body></html>"); + $string = ''; + foreach ($dom->documentElement->firstChild->childNodes as $child) { + $string .= $dom->saveXML($child); + } + return $string; + } + + static private function tidyUpModuleTidy($string) { + if (class_exists("tidy")) { + $tidy = new tidy(); + $tidyOptions = array("output-xhtml" => true, + "show-body-only" => true, + "clean" => true, + "wrap" => "350", + "indent" => true, + "indent-spaces" => 1, + "ascii-chars" => false, + "wrap-attributes" => false, + "alt-text" => "", + "doctype" => "loose", + "numeric-entities" => true, + "drop-proprietary-attributes" => true, + "enclose-text" => false, + "enclose-block-text" => false + + ); + $tidy->parseString($string, $tidyOptions, "utf8"); + $tidy->cleanRepair(); + return (string) $tidy; + } else { + return false; + } + } +} + +define("DHX_SECURITY_SAFETEXT", 1); +define("DHX_SECURITY_SAFEHTML", 2); +define("DHX_SECURITY_TRUSTED", 3); + +class ConnectorSecurity{ + static public $xss = DHX_SECURITY_SAFETEXT; + static public $security_key = false; + + static private $filterClass = null; + static function filter($value, $mode = false){ + if ($mode === false) + $mode = ConnectorSecurity::$xss; + + if ($mode == DHX_SECURITY_TRUSTED) + return $value; + if ($mode == DHX_SECURITY_SAFETEXT) + return filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); + if ($mode == DHX_SECURITY_SAFEHTML){ + if (ConnectorSecurity::$filterClass == null) + ConnectorSecurity::$filterClass = new dhx_externalinput_clean(); + return ConnectorSecurity::$filterClass->basic($value); + } + throw new Error("Invalid security mode:"+$mode); + } + + static function CSRF_detected(){ + LogMaster::log("[SECURITY] Possible CSRF attack detected", array( + "referer" => $_SERVER["HTTP_REFERER"], + "remote" => $_SERVER["REMOTE_ADDR"] + )); + LogMaster::log("Request data", $_POST); + die(); + } + static function checkCSRF($edit){ + @session_start(); + + if (ConnectorSecurity::$security_key){ + if ($edit=== true){ + if (!isset($_POST['dhx_security'])) + return ConnectorSecurity::CSRF_detected(); + $master_key = $_SESSION['dhx_security']; + $update_key = $_POST['dhx_security']; + if ($master_key != $update_key) + return ConnectorSecurity::CSRF_detected(); + + return ""; + } + //data loading + if (!array_key_exists("dhx_security",$_SESSION)){ + $_SESSION["dhx_security"] = md5(uniqid()); + } + + return $_SESSION["dhx_security"]; + } + } + +}
\ No newline at end of file |