XSSセキュリティ処理
48544 ワード
Security.class.phpファイル
呼び出し方法:
$SEC = new Security();$SEC->gprc_xss();$SEC = NULL;
1 <?php
2 class Security {
3
4 public $filename_bad_chars = array(
5 '../', '<!--', '-->', '<', '>',
6 "'", '"', '&', '$', '#',
7 '{', '}', '[', ']', '=',
8 ';', '?', '%20', '%22',
9 '%3c', // <
10 '%253c', // <
11 '%3e', // >
12 '%0e', // >
13 '%28', // (
14 '%29', // )
15 '%2528', // (
16 '%26', // &
17 '%24', // $
18 '%3f', // ?
19 '%3b', // ;
20 '%3d' // =
21 );
22 protected $_xss_hash = '';
23 protected $_never_allowed_str = array(
24 'document.cookie' => '[removed]',
25 'document.write' => '[removed]',
26 '.parentNode' => '[removed]',
27 '.innerHTML' => '[removed]',
28 '-moz-binding' => '[removed]',
29 '<!--' => '<!--',
30 '-->' => '-->',
31 '<![CDATA[' => '<![CDATA[',
32 '<comment>' => '<comment>'
33 );
34 protected $_never_allowed_regex = array(
35 'javascript\s*:',
36 '(document|(document\.)?window)\.(location|on\w*)',
37 'expression\s*(\(|&\#40;)', // CSS and IE
38 'vbscript\s*:', // IE, surprise!
39 'Redirect\s+302',
40 "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
41 );
42
43 public function gprc_xss(){
44 if($_POST)$_POST = $this->xss_clean($_POST);
45 if($_GET)$_GET = $this->xss_clean($_GET);
46 if($_COOKIE)$_COOKIE = $this->xss_clean($_COOKIE);
47 if($_REQUEST)$_REQUEST = $this->xss_clean($_REQUEST);
48 }
49
50 public function remove_invisible_characters($str, $url_encoded = TRUE){
51 $non_displayables = array();
52 if ($url_encoded) {
53 $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15
54 $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31
55 }
56 $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
57 do {
58 $str = preg_replace($non_displayables, '', $str, -1, $count);
59 }
60 while ($count);
61 return $str;
62 }
63
64 public function xss_clean($str, $is_image = FALSE){
65 if (is_array($str)){
66 while (list($key) = each($str)){
67 $str[$key] = $this->xss_clean($str[$key]);
68 }
69 return $str;
70 }
71 $str = $this->_validate_entities($this->remove_invisible_characters($str));
72 $str = rawurldecode($str);
73 $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
74 $str = preg_replace_callback('/<\w+.*/si', array($this, '_decode_entity'), $str);
75 $str = $this->remove_invisible_characters($str);
76 $str = str_replace("\t", ' ', $str);
77 $converted_string = $str;
78 $str = $this->_do_never_allowed($str);
79 if ($is_image === TRUE){
80 $str = preg_replace('/<\?(php)/i', '<?\\1', $str);
81 }else {
82 $str = str_replace(array('<?', '?'.'>'), array('<?', '?>'), $str);
83 }
84 $words = array(
85 'javascript', 'expression', 'vbscript', 'script', 'base64',
86 'applet', 'alert', 'document', 'write', 'cookie', 'window'
87 );
88 foreach ($words as $word){
89 $word = implode('\s*', str_split($word)).'\s*';
90 $str = preg_replace_callback('#('.substr($word, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
91 }
92 do{
93 $original = $str;
94 if (preg_match('/<a/i', $str))$str = preg_replace_callback('#<a\s+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str);
95 if (preg_match('/<img/i', $str))$str = preg_replace_callback('#<img\s+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
96 if (preg_match('/script|xss/i', $str))$str = preg_replace('#</*(?:script|xss).*?>#si', '[removed]', $str);
97 }
98 while ($original !== $str);
99 unset($original);
100 $str = $this->_remove_evil_attributes($str, $is_image);
101 $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
102 $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);
103 $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', '\\1\\2(\\3)', $str);
104 $str = $this->_do_never_allowed($str);
105 if ($is_image === TRUE)return ($str === $converted_string);
106 return $str;
107 }
108
109 public function xss_hash(){
110 if ($this->_xss_hash === '')$this->_xss_hash = md5(uniqid(mt_rand()));
111 return $this->_xss_hash;
112 }
113
114 public function entity_decode($str, $charset = NULL){
115 if (strpos($str, '&') === FALSE)return $str;
116 if (empty($charset))$charset = 'utf-8';
117
118 do{
119 $matches = $matches1 = 0;
120 $str = preg_replace('~(�*[0-9a-f]{2,5});?~iS', '$1;', $str, -1, $matches);
121 $str = preg_replace('~(&#\d{2,4});?~S', '$1;', $str, -1, $matches1);
122 $str = html_entity_decode($str, ENT_COMPAT, $charset);
123 }
124 while ($matches OR $matches1);
125 return $str;
126 }
127
128 public function sanitize_filename($str, $relative_path = FALSE){
129 $bad = $this->filename_bad_chars;
130 if ( ! $relative_path){
131 $bad[] = './';
132 $bad[] = '/';
133 }
134 $str = $this->remove_invisible_characters($str, FALSE);
135 do{
136 $old = $str;
137 $str = str_replace($bad, '', $str);
138 }while ($old !== $str);
139 return stripslashes($str);
140 }
141
142 public function strip_image_tags($str){
143 return preg_replace(array('#<img[\s/]+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img[\s/]+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $str);
144 }
145
146 protected function _compact_exploded_words($matches){
147 return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
148 }
149
150 protected function _remove_evil_attributes($str, $is_image){
151 $evil_attributes = array('style', 'xmlns', 'formaction');
152 if ($is_image === TRUE)unset($evil_attributes[array_search('xmlns', $evil_attributes)]);
153
154 do {
155 $count = 0;
156 $attribs = array();
157 preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is', $str, $matches, PREG_SET_ORDER);
158 foreach ($matches as $attr){
159 $attribs[] = preg_quote($attr[0], '/');
160 }
161 preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER);
162 foreach ($matches as $attr){
163 $attribs[] = preg_quote($attr[0], '/');
164 }
165 if (count($attribs) > 0)$str = preg_replace('/(<?)(\/?[^><]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><]?)([><]*)/i', '$1$2 $4$6$7$8', $str, -1, $count);
166 }
167 while ($count);
168 return $str;
169 }
170
171 protected function _sanitize_naughty_html($matches) {
172 return '<'.$matches[1].$matches[2].$matches[3].str_replace(array('>', '<'), array('>', '<'), $matches[4]);
173 }
174
175 protected function _js_link_removal($match){
176 return str_replace($match[1],
177 preg_replace('#href=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
178 '', $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1])) ),$match[0]);
179 }
180
181 protected function _js_img_removal($match){
182 return str_replace($match[1],
183 preg_replace('#src=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
184 '',$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
185 ),
186 $match[0]);
187 }
188
189 protected function _convert_attribute($match){
190 return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]);
191 }
192
193 protected function _filter_attributes($str){
194 $out = '';
195 if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)){
196 foreach ($matches[0] as $match){
197 $out .= preg_replace('#/\*.*?\*/#s', '', $match);
198 }
199 }
200 return $out;
201 }
202
203 protected function _decode_entity($match){
204 return $this->entity_decode($match[0], strtoupper('utf-8'));
205 }
206
207 protected function _validate_entities($str){
208 $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash().'\\1=\\2', $str);
209 $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', '\\1;\\2', $str);
210 $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i', '\\1\\2;', $str);
211 return str_replace($this->xss_hash(), '&', $str);
212 }
213
214 protected function _do_never_allowed($str){
215 $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str);
216 foreach ($this->_never_allowed_regex as $regex){
217 $str = preg_replace('#'.$regex.'#is', '[removed]', $str);
218 }
219 return $str;
220 }
221 /**
222 * @desc:
223 * */
224 public function gprc_sql(){
225 if(!get_magic_quotes_gpc()) {
226 if($_POST) $_POST = $this->daddslashes($_POST);
227 if($_GET) $_GET = $this->daddslashes($_GET);
228 if($_COOKIE) $_COOKIE = $this->daddslashes($_COOKIE);
229 if($_REQUEST) $_REQUEST = $this->daddslashes($_REQUEST);
230 }
231 }
232
233 public function daddslashes($string){
234 if(!is_array($string)) return addslashes($string);
235 foreach($string as $key => $val) $string[$key] = $this->daddslashes($val);
236 return $string;
237 }
238 }
呼び出し方法:
$SEC = new Security();$SEC->gprc_xss();$SEC = NULL;