source: trunk/workflow/inc/class.utils.security.php @ 7673

Revision 7673, 9.1 KB checked in by douglasz, 11 years ago (diff)

Ticket #3236 - Correcoes para Performance: Function Within Loop Declaration.

  • Property svn:executable set to *
Line 
1<?php
2require_once('class.utils.php');
3 /**
4  * Filters input of stray or malicious PHP, Javascript or HTML tags.
5  * It can be used to prevent cross-site scripting (XSS) attacks.
6  * It should be used to filter input supplied by the user, such as an HTML code
7  * entered in form fields. You would create the filter object, configure it with your
8  * own settings, then call its process method to clean the form input values.
9  *
10  * @author: Daniel Morris
11  * @version: 1.2.2_php4/php5
12  * @package Workflow
13  * @license http://www.gnu.org/copyleft/gpl.html GPL
14  */
15class SecurityUtils extends Utils {
16
17        /**
18         * @var array $tagsArray default = empty array
19         * @access public
20         */
21        var $tagsArray;
22
23        /**
24         * @var array $attrArray  default = empty array
25         * @access public
26         */
27        var $attrArray;
28
29        /**
30         * @var $tagsMethod  default = 0
31         * @access public
32         */
33        var $tagsMethod;
34
35        /**
36         * @var $attrMethod  default = 0
37         * @access public
38         */
39        var $attrMethod;
40
41        /**
42         * @var $xssAuto  default = 1
43         * @access public
44         */
45        var $xssAuto;
46
47        /**
48         * @var array $tagBlacklist
49         * @access public
50         */
51        var $tagBlacklist = array('applet', 'body', 'bgsound', 'base', 'basefont', 'embed', 'frame', 'frameset', 'head', 'html', 'id', 'iframe', 'ilayer', 'layer', 'link', 'meta', 'name', 'object', 'script', 'style', 'title', 'xml');
52
53        /**
54         * @var array $attrBlackList
55         * @access public
56         */
57        var $attrBlacklist = array('action', 'background', 'codebase', 'dynsrc', 'lowsrc');  // also will strip ALL event handlers
58
59        /**
60          * Constructor for inputFilter class. Only first parameter is required.
61          * @access constructor
62          * @param Array $tagsArray - list of user-defined tags
63          * @param Array $attrArray - list of user-defined attributes
64          * @param int $tagsMethod - 0= allow just user-defined, 1= allow all but user-defined
65          * @param int $attrMethod - 0= allow just user-defined, 1= allow all but user-defined
66          * @param int $xssAuto - 0= only auto clean essentials, 1= allow clean blacklisted tags/attr
67          */
68        function SecurityUtils($tagsArray = array(), $attrArray = array(), $tagsMethod = 0, $attrMethod = 0, $xssAuto = 1) {
69                // make sure user defined arrays are in lowercase
70        $tagsArray_count = count($tagsArray);
71                for ($i = 0; $i < $tagsArray_count; ++$i)
72            $tagsArray[$i] = strtolower($tagsArray[$i]);
73        $attrArray_count = count($attrArray);
74                for ($i = 0; $i < $attrArray_count; ++$i)
75            $attrArray[$i] = strtolower($attrArray[$i]);
76                // assign to member vars
77                $this->tagsArray = (array) $tagsArray;
78                $this->attrArray = (array) $attrArray;
79                $this->tagsMethod = $tagsMethod;
80                $this->attrMethod = $attrMethod;
81                $this->xssAuto = $xssAuto;
82        }
83
84        /**
85          * Method to be called by another php script. Processes for XSS and specified bad code.
86          * @access public
87          * @param Mixed $source - input string/array-of-string to be 'cleaned'
88          * @return String $source - 'cleaned' version of input parameter
89          */
90        function process($source) {
91                // clean all elements in this array
92                if (is_array($source)) {
93                        foreach($source as $key => $value)
94                                // filter element for XSS and other 'bad' code etc.
95                                if (is_string($value)) $source[$key] = $this->remove($this->decode($value));
96                        return $source;
97                // clean this string
98                } else if (is_string($source)) {
99                        // filter source for XSS and other 'bad' code etc.
100                        return $this->remove($this->decode($source));
101                // return parameter as given
102                } else return $source;
103        }
104
105        /**
106          * Internal method to iteratively remove all unwanted tags and attributes
107          * @access protected
108          * @param String $source - input string to be 'cleaned'
109          * @return String $source - 'cleaned' version of input parameter
110          */
111        function remove($source) {
112                $loopCounter=0;
113                // provides nested-tag protection
114                while($source != $this->filterTags($source)) {
115                        $source = $this->filterTags($source);
116                        ++$loopCounter;
117                }
118                return $source;
119        }
120
121        /**
122          * Internal method to strip a string of certain tags
123          * @access protected
124          * @param String $source - input string to be 'cleaned'
125          * @return String $source - 'cleaned' version of input parameter
126          */
127        function filterTags($source)
128        {
129                return strip_tags($source);
130        }
131
132        /**
133          * Internal method to strip a tag of certain attributes
134          * @access protected
135          * @param Array $attrSet
136          * @return Array $newSet
137          */
138        function filterAttr($attrSet) {
139                $newSet = array();
140                // process attributes
141        $attrSet_count = count($attrSet);
142                for ($i = 0; $i < $attrSet_count; ++$i) {
143                        // skip blank spaces in tag
144                        if (!$attrSet[$i]) continue;
145                        // split into attr name and value
146                        $attrSubSet = explode('=', trim($attrSet[$i]));
147                        list($attrSubSet[0]) = explode(' ', $attrSubSet[0]);
148                        // removes all "non-regular" attr names AND also attr blacklisted
149                        if ((!preg_match('/^[a-z]*$/i',$attrSubSet[0])) || (($this->xssAuto) && ((in_array(strtolower($attrSubSet[0]), $this->attrBlacklist)) || (substr($attrSubSet[0], 0, 2) == 'on'))))
150                                continue;
151                        // xss attr value filtering
152                        if ($attrSubSet[1]) {
153                                // strips unicode, hex, etc
154                                $attrSubSet[1] = str_replace('&#', '', $attrSubSet[1]);
155                                // strip normal newline within attr value
156                                $attrSubSet[1] = preg_replace('/\s+/', '', $attrSubSet[1]);
157                                // strip double quotes
158                                $attrSubSet[1] = str_replace('"', '', $attrSubSet[1]);
159                                // [requested feature] convert single quotes from either side to doubles (Single quotes shouldn't be used to pad attr value)
160                                if ((substr($attrSubSet[1], 0, 1) == "'") && (substr($attrSubSet[1], (strlen($attrSubSet[1]) - 1), 1) == "'"))
161                                        $attrSubSet[1] = substr($attrSubSet[1], 1, (strlen($attrSubSet[1]) - 2));
162                                // strip slashes
163                                $attrSubSet[1] = stripslashes($attrSubSet[1]);
164                        }
165                        // auto strip attr's with "javascript:
166                        if (    ((strpos(strtolower($attrSubSet[1]), 'expression') !== false) &&        (strtolower($attrSubSet[0]) == 'style')) ||
167                                        (strpos(strtolower($attrSubSet[1]), 'javascript:') !== false) ||
168                                        (strpos(strtolower($attrSubSet[1]), 'behaviour:') !== false) ||
169                                        (strpos(strtolower($attrSubSet[1]), 'vbscript:') !== false) ||
170                                        (strpos(strtolower($attrSubSet[1]), 'mocha:') !== false) ||
171                                        (strpos(strtolower($attrSubSet[1]), 'livescript:') !== false)
172                        ) continue;
173
174                        // if matches user defined array
175                        $attrFound = in_array(strtolower($attrSubSet[0]), $this->attrArray);
176                        // keep this attr on condition
177                        if ((!$attrFound && $this->attrMethod) || ($attrFound && !$this->attrMethod)) {
178                                // attr has value
179                                if ($attrSubSet[1]) $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[1] . '"';
180                                // attr has decimal zero as value
181                                else if ($attrSubSet[1] == "0") $newSet[] = $attrSubSet[0] . '="0"';
182                                // reformat single attributes to XHTML
183                                else $newSet[] = $attrSubSet[0] . '="' . $attrSubSet[0] . '"';
184                        }
185                }
186                return $newSet;
187        }
188
189        /**
190          * Try to convert to plaintext
191          * @access protected
192          * @param String $source
193          * @return String $source
194          */
195        function decode($source) {
196                // url decode
197                $source = html_entity_decode($source, ENT_QUOTES, "ISO-8859-1");
198                // convert decimal
199                $source = preg_replace('/&#(\d+);/me',"chr(\\1)", $source);                             // decimal notation
200                // convert hex
201                $source = preg_replace('/&#x([a-f0-9]+);/mei',"chr(0x\\1)", $source);   // hex notation
202                return $source;
203        }
204
205        /**
206          * Method to be called by another php script. Processes for SQL injection
207          * @access public
208          * @param Mixed $source - input string/array-of-string to be 'cleaned'
209          * @return String $source - 'cleaned' version of input parameter
210          */
211        function safeSQL($source) {
212                // clean all elements in this array
213                if (is_array($source)) {
214                        foreach($source as $key => $value)
215                                // filter element for SQL injection
216                                if (is_string($value)) $source[$key] = $this->quoteSmart($this->decode($value));
217                        return $source;
218                // clean this string
219                } else if (is_string($source)) {
220                        // filter source for SQL injection
221                        if (is_string($source)) return $this->quoteSmart($this->decode($source));
222                // return parameter as given
223                } else return $source;
224        }
225
226        /**
227          * @author Chris Tobin
228          * @author Daniel Morris
229          * @access protected
230          * @param String $source
231          * @return String $source
232          */
233        function quoteSmart($source) {
234                // strip slashes
235                if (get_magic_quotes_gpc()) $source = stripslashes($source);
236                // quote both numeric and text
237                $source = $this->escapeString($source);
238                return $source;
239        }
240
241        /**
242          * @author Chris Tobin
243          * @author Daniel Morris
244          * @access protected
245          * @param String $source
246          * @return String $source
247          */
248        function escapeString($string) {
249                // depreciated function
250                if (version_compare(phpversion(),"4.3.0", "<")) mysql_escape_string($string);
251                // current function
252                else mysql_real_escape_string($string);
253                return $string;
254        }
255
256        /**
257         * @author Sidnei Augusto Drovetto Jr. - drovetto@gmail.com
258         * @param mixed $source A string or array of strings to be escaped
259         * @return mixed $source An object of the same type of the input, only escaped
260         * @access public
261         */
262        function escapeHTML($source)
263        {
264                $output = $source;
265                if (is_string($output))
266                        $output = htmlentities($output, ENT_QUOTES, 'ISO-8859-1');
267                else
268                        if (is_array($output))
269                                foreach ($output as &$element)
270                                        $element = $this->escapeHTML($element);
271
272                return $output;
273        }
274}
275
276?>
Note: See TracBrowser for help on using the repository browser.