CI Framework Security Class security.php source code Analysis _php Example

Source: Internet
Author: User
Tags base64 cdata eval md5 php script php source code script tag csrf attack

The CI security class provides a global defense against CSRF attacks and XSS attack policies that require only the configuration file to be opened:

Copy Code code as follows:

$config [' csrf_protection '] = TRUE;
$config [' global_xss_filtering '] = TRUE;

and provides a practical method:

Copy Code code as follows:

$this->security->xss_clean ($data);//The second argument is true to verify that the picture is secure
$this->security->sanitize_filename ()//filter file name

CI also provides a security function:

Xss_clean ()//XSS Filtration
Sanitize_filename ()//clean file name
Do_hash ()//md5 or SHA encryption
Strip_image_tags ()//remove unnecessary characters from picture labels
Encode_php_tags ()//force PHP script tag into entity object

Copy Code code as follows:



<?php if (! defined (' BasePath ')) exit (' No Direct script access allowed ');


/**


* Safety Class


*/


Class Ci_security {


Random hash value of URL


protected $_xss_hash = ';


Hash value of the cookie tag against the CSRF attack


protected $_csrf_hash = ';


Anti-CSRF cookie expiration Time


protected $_csrf_expire = 7200;


Anti-CSRF cookie name


protected $_csrf_token_name = ' Ci_csrf_token ';


Anti-CSRF Token name


protected $_csrf_cookie_name = ' Ci_csrf_token ';


Array of strings not allowed to appear


Protected $_never_allowed_str = Array (


' Document.cookie ' => ' [removed] ',


' document.write ' => ' [removed] ',


'. parentnode ' => ' [removed] ',


'. InnerHTML ' => ' [removed] ',


' Window.location ' => ' [removed] ',


'-moz-binding ' => ' [removed] ',


' <!--' => ' <!--',


'--> ' => '--> ',


' <! [cdata[' => ' <![ Cdata[',


' <comment> ' => ' <comment> '


);


Array of regular expressions that are not allowed to appear


Protected $_never_allowed_regex = Array (


' javascript\s*: ',


' Expression\s* (|&\ #40;) ',//CSS and IE


' vbscript\s*: ',//IE, surprise!


' redirect\s+302 ',


"([\"]) data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1? "


);


Constructors


Public Function __construct ()


{


CSRF protection is turned on


if (Config_item (' csrf_protection ') = = TRUE)


{


CSRF Configuration


foreach (Array (' Csrf_expire ', ' csrf_token_name ', ' csrf_cookie_name ') as $key)


{


if (FALSE!== ($val = Config_item ($key)))


{


$this->{' _ '. $key} = $val;


}


}


_csrf_cookie_name Plus Cookie Prefix


if (Config_item (' Cookie_prefix '))


{


$this->_csrf_cookie_name = Config_item (' Cookie_prefix '). $this->_csrf_cookie_name;


}


Set the hash value of the CSRF


$this->_csrf_set_hash ();


}


Log_message (' Debug ', "Security Class initialized");


}


// --------------------------------------------------------------------


/**


* Verify Cross Site Request forgery Protection


*


* @return Object


*/


Public Function csrf_verify ()


{


If it is not a POST request, set the CSRF cookie value


if (Strtoupper ($_server[' Request_method '))!== ' POST ')


{


return $this->csrf_set_cookie ();


}


Does the tokens exist in both the _post and _cookie arrays?


if (! isset ($_post[$this->_csrf_token_name], $_cookie[$this->_csrf_cookie_name])


{


$this->csrf_show_error ();


}


Token match?


if ($_post[$this->_csrf_token_name]!= $_cookie[$this->_csrf_cookie_name])


{


$this->csrf_show_error ();


}


We kill this since we do and we don ' t want to


Polute the _post array


unset ($_post[$this->_csrf_token_name]);


Nothing should last forever


unset ($_cookie[$this->_csrf_cookie_name]);


$this->_csrf_set_hash ();


$this->csrf_set_cookie ();


Log_message (' Debug ', ' CSRF token verified ');


return $this;


}


// --------------------------------------------------------------------


/**


* Set the CSRF cookie value


*/


Public Function Csrf_set_cookie ()


{


$expire = time () + $this->_csrf_expire;


$secure _cookie = (Config_item (' cookie_secure ') = = TRUE)? 1:0;


if ($secure _cookie && (Empty ($_server[' https ')) OR strtolower ($_server[' https ']) = = ' off ')


{


return FALSE;


}


Setcookie ($this->_csrf_cookie_name, $this->_csrf_hash, $expire, Config_item (' Cookie_path '), Config_item (' Cookie_domain '), $secure _cookie);


Log_message (' Debug ', ' CRSF cookie Set ');


return $this;


}


CSRF Save


Public Function Csrf_show_error ()


{


Show_error (' The action you have requested are not allowed. ');


}


Gets the hash value of the CSRF


Public Function Get_csrf_hash ()


{


return $this->_csrf_hash;


}


Gets the token value of the CSRF


Public Function Get_csrf_token_name ()


{


return $this->_csrf_token_name;


}


/**


* XSS Filtering


*/


Public Function Xss_clean ($str, $is _image = FALSE)


{


Whether it is an array


if (Is_array ($STR))


{


while (the list ($key) = each ($STR))


{


$STR [$key] = $this->xss_clean ($str [$key]);


}


return $str;


}


Remove the visible string


$str = Remove_invisible_characters ($STR);


Validating entity URLs


$str = $this->_validate_entities ($STR);


/*


* URL decoding


*


* Just in case stuff like this is submitted:


*


* <a href= "GoogleHttp://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D ">Google</a>


*


* Note:use Rawurldecode () so it does not remove plus signs


*


*/


$str = Rawurldecode ($STR);


/*


* Convert character entities to ASCII


*


* This permits we tests below to work reliably.


* We convert entities that are within tags since


* These are the ones that would pose security problems.


*


*/


$str = Preg_replace_callback ("/[a-z]+=" ([\ "]). *?\\1/si", Array ($this, ' _convert_attribute '), $STR);


$str = Preg_replace_callback ("/<\w+.*"? =>|<|$)/si ", Array ($this, ' _decode_entity '), $STR);


/*


* Remove Invisible Characters again!


*/


$str = Remove_invisible_characters ($STR);


/*


* Convert all tabs to spaces


*


* This prevents strings like This:ja vascript


* Note:we deal with spaces between characters later.


* Note:preg_replace is found to is amazingly slow here


* Large blocks of data, so we use Str_replace.


*/


if (Strpos ($str, "\ T")!== FALSE)


{


$str = Str_replace ("T", "", $str);


}


/*


* Capture converted string for later comparison


*/


$converted _string = $str;


Remove Strings that are never allowed


$str = $this->_do_never_allowed ($STR);


/*


* Makes PHP tags safe


*


* Note:xml tags are inadvertently replaced too:


*


* <?xml


*


* But It doesn ' t seem to pose a problem.


*/


if ($is _image = = TRUE)


{


Images have a tendency to have the PHP short opening and


Closing tags every so often so we skip those and


Do the long opening tags.


$str = Preg_replace ('/<\? PHP)/I ', "<?\\1", $str);


}


Else


{


$STR = str_replace Array ('??? ', '? ') > '), Array (';? ', '?> '), $STR);


}


/*


* Compact any exploded words


*


* This corrects words like:j a V a s C r i p t


* These words are compacted back to their correct state.


*/


$words = Array (


' JavaScript ', ' expression ', ' VBScript ', ' script ', ' base64 ',


' Applets ', ' alert ', ' document ', ' write ', ' cookie ', ' window '


);


foreach ($words as $word)


{


$temp = ';


for ($i = 0, $wordlen = strlen ($word); $i < $wordlen; $i + +)


{


$temp. = substr ($word, $i, 1). \s* ";


}


We are followed by a non-word character the It is want.


That's way valid stuff like ' dealer to ' does not become ' Dealerto '


$str = Preg_replace_callback ('. substr ($temp, 0,-3). " (\w) #is ', Array ($this, ' _compact_exploded_words '), $STR);


}


/*


* Remove disallowed Javascript in links or img tags


* We used to does some version comparisons and use the Stripos for PHP5,


* But it is dog slow compared to this simplified non-capturing


* Preg_match (), especially if the pattern exists in the string


*/


Todo


{


$original = $str;


if (Preg_match ("/<a/i", $str))


{


$str = Preg_replace_callback ("#<a\s+" ([^>]*?) (>|$) #si ", Array ($this, ' _js_link_removal '), $STR);


}


if (Preg_match ("/<img/i", $str))


{


$str = Preg_replace_callback ("#<img\s+" ([^>]*?) (\s?/?>|$) #si ", Array ($this, ' _js_img_removal '), $STR);


}


if (Preg_match ("/script/i", $str) OR preg_match ("/xss/i", $str))


{


$str = Preg_replace ("#<" (/*) (SCRIPT|XSS) (. *?) \> #si ", ' [removed] ', $str);


}


}


while ($original!= $str);


Unset ($original);


Remove evil attributes such as style, onclick and xmlns


$str = $this->_remove_evil_attributes ($str, $is _image);


/*


* Sanitize Naughty HTML elements


*


* If a tag containing any of the words in the list


* Below is found, the tag gets converted to entities.


*


* So this: <blink>


* Becomes: <blink>


*/


$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 ';


$str = Preg_replace_callback (' #< (/*\s*) ('. $naughty. ') ([^><]*) ([><]*) #is ', Array ($this, ' _sanitize_naughty_html '), $STR);


/*


* Sanitize Naughty scripting elements


*


* Similar to above, only instead of looking for


* tags it looks for PHP and JavaScript commands


* that are disallowed. Rather than removing the


* Code, it simply converts the parenthesis to entities


* Rendering the code un-executable.


*


* For Example:eval (' some code ')


* Becomes:eval (' some code ')


*/


$str = Preg_replace (' # alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents| Readfile|unlink) (\s*) \ ((. *?) \) #si ', "\\1\\2 (\\3)", $str);


Final Clean Up


This adds a bit of the extra precaution in case


Something got through the above filters


$str = $this->_do_never_allowed ($STR);


/*


* Images are Handled in a Special Way


*-Essentially, we want to know this after all of the character


* Conversion is do whether any unwanted, likely XSS, the code was found.


* If not, we return TRUE and as the image is clean.


* However, if the string post-conversion does not matched the


* String Post-removal of XSS, then it fails, as there was unwanted XSS


* Code found and removed/changed during processing.


*/


if ($is _image = = TRUE)


{


return ($str = = $converted _string)? True:false;


}


Log_message (' Debug ', "XSS filtering completed");


return $str;


}


// --------------------------------------------------------------------


A random hash value that protects a URL


Public Function Xss_hash ()


{


if ($this->_xss_hash = = ")


{


Mt_srand ();


$this->_xss_hash = MD5 (time () + mt_rand (0, 1999999999));


}


return $this->_xss_hash;


}


// --------------------------------------------------------------------


/**


* HTML Entity Transfer code


*/


Public Function Entity_decode ($str, $charset = ' UTF-8 ')


{


if (Stristr ($str, ' & ') = = FALSE)


{


return $str;


}


$str = Html_entity_decode ($str, Ent_compat, $charset);


$str = Preg_replace (' ~& #x (0*[0-9a-f]{2,5}) ~ei ', ' Chr (Hexdec ("\\1")) ', $str);


Return Preg_replace (' ~&# ([0-9]{2,4}) ~e ', ' Chr (\\1) ', $str);


}


// --------------------------------------------------------------------


Filter filename to ensure file name security


Public Function Sanitize_filename ($str, $relative _path = FALSE)


{


$bad = Array (


".. /",


"<!--",


"-->",


"<",


">",


"'",


'"',


' & ',


'$',


'#',


'{',


'}',


'[',


']',


'=',


';',


'?',


"%20",


"%22",


"%3C",//<


"%253c",//<


"%3e",//>


"%0e",//>


"%28",//(


"%29",//)


"%2528",//(


"%26",//&


"%24",//$


"%3f",//?


"%3b",//;


"%3d"//=


);


if (! $relative _path)


{


$bad [] = './';


$bad [] = '/';


}


$str = Remove_invisible_characters ($str, FALSE);


Return Stripslashes (Str_replace ($bad, ', $str));


}


Compress words like J A V a s C r I p t into JavaScript


protected function _compact_exploded_words ($matches)


{


Return preg_replace ('/\s+/s ', ', $matches [1]). $matches [2];


}


// --------------------------------------------------------------------


/*


* Remove some of the harmful HTML attributes


*/


protected function _remove_evil_attributes ($STR, $is _image)


{


All JavaScript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns


$evil _attributes = Array (' on\w* ', ' style ', ' xmlns ', ' formaction ');


if ($is _image = = TRUE)


{


/*


* Adobe Photoshop puts XML metadata into JFIF images,


* including namespacing, so we have to allow this for images.


*/


Unset ($evil _attributes[array_search (' xmlns ', $evil _attributes)]);


}


do {


$count = 0;


$attribs = Array ();


Find occurrences of illegal attributes strings with quotes (042 and 047 are octal)


Preg_match_all ('/implode (' | ', $evil _attributes). \s*=\s* (\042|\047) ([^\\2]*?) (\\2)/is ', $str, $matches, Preg_set_order);


foreach ($matches as $attr)


{


$attribs [] = preg_quote ($attr [0], '/');


}


Find occurrences of illegal attribute strings without quotes


Preg_match_all ('/implode (' | ', $evil _attributes). \s*=\s* ([^\s>]*)/is ', $str, $matches, Preg_set_order);


foreach ($matches as $attr)


{


$attribs [] = preg_quote ($attr [0], '/');


}


Replace illegal attribute strings that are inside an HTML tag


if (count ($attribs) > 0)


{


$str = Preg_replace ('/() (\/? [^><]+?] ([^a-za-z<>\-]) (.*?) ('. Implode (' | ', $attribs). (.*?) ([\s><]?) ([><]*)/I ', ' $1$2 $4$6$7$8 ', $str,-1, $count);


}


while ($count);


return $str;


}


// --------------------------------------------------------------------


/**


* Clean HTML, to complement the closed label


*/


protected function _sanitize_naughty_html ($matches)


{


Encode opening brace


$str = ' < '. $matches [1]. $matches [2]. $matches [3];


Encode captured opening or closing brace to prevent recursive


$str. = str_replace (Array (' > ', ' < '), array (' > ', ' < '),


$matches [4]);


return $str;


}


// --------------------------------------------------------------------


/**


* Filter Hyperlinks in JS


*/


protected function _js_link_removal ($match)


{


Return Str_replace (


$match [1],


Preg_replace (


' #href =.*? (Alert\ (|alert&\ #40; |javascript\:|livescript\:|mocha\:|charset\=|window\.| document\.| \.cookie|<script|<xss|data\s*:) #si ',


'',


$this->_filter_attributes (Array (' < ', ' > '), ', $match [1])


),


$match [0]


);


}


// --------------------------------------------------------------------


/**


* Filter the JS in the picture link


*/


protected function _js_img_removal ($match)


{


Return Str_replace (


$match [1],


Preg_replace (


' #src =.*? (Alert\ (|alert&\ #40; |javascript\:|livescript\:|mocha\:|charset\=|window\.| document\.| \.cookie|<script|<xss|base64\s*,) #si ',


'',


$this->_filter_attributes (Array (' < ', ' > '), ', $match [1])


),


$match [0]


);


}


// --------------------------------------------------------------------


/**


* Convert attributes to convert some characters to entities


*/


protected function _convert_attribute ($match)


{


return Str_replace (' > ', ' < ', ' \ \ \ '), Array (' > ', ' < ', ' \\\\ '), $match [0]);


}


// --------------------------------------------------------------------


Filter HTML Tag Properties


protected function _filter_attributes ($STR)


{


$out = ';


if (Preg_match_all (#\s*[a-z\-]+\s*=\s*) (\042|\047) ([^\\1]*?) \\1#is ', $str, $matches))


{


foreach ($matches [0] as $match)


{


$out. = Preg_replace ("#/\*.*?\*/#s", "", $match);


}


}


return $out;


}


// --------------------------------------------------------------------


HTML Entity Transfer code


protected function _decode_entity ($match)


{


return $this->entity_decode ($match [0], Strtoupper (Config_item (' CharSet '));


}


// --------------------------------------------------------------------


/**


* Verify URL Entity


*/


protected function _validate_entities ($STR)


{


/*


* Protect get variables in URLs


*/


901119url5918amp18930protect8198


$str = Preg_replace (' |\& ([a-z\_0-9\-]+) \= ([a-z\_0-9\-]+) |i ', $this->xss_hash (). " \\1=\\2 ", $STR);


/*


* Validate Standard character entities


*


* Add a semicolon if missing. We do the To enable


* The conversion of entities to ASCII later.


*


*/


$str = Preg_replace (' # &\#?[ 0-9a-z]{2,}) ([\x00-\x20]) *;? #i ', "\\1;\\2", $str);


/*


* Validate UTF16 two byte encoding (x00)


*


* Just as above, adds a semicolon if missing.


*


*/


$str = Preg_replace (' # (&\ #x?) ([0-9a-f]+);? #i ', "\\1\\2;", $STR);


/*


* Un-protect get variables in URLs


*/


$str = Str_replace ($this->xss_hash (), ' & ', $str);


return $str;


}


// ----------------------------------------------------------------------


Filter for strings that are not allowed to appear


protected function _do_never_allowed ($STR)


{


$str = Str_replace (Array_keys ($this->_never_allowed_str), $this->_never_allowed_str, $STR);


foreach ($this->_never_allowed_regex as $regex)


{


$str = preg_replace (' # '. $regex. #is ', ' [removed] ', $str);


}


return $str;


}


// --------------------------------------------------------------------


Set the hash value of the CSRF


protected function _csrf_set_hash ()


{


if ($this->_csrf_hash = = ")


{


If _csrf_cookie_name exists, direct as CSRF hash value


if (Isset ($_cookie[$this->_csrf_cookie_name]) &&


Preg_match (' #^[0-9a-f]{32}$ #iS ', $_cookie[$this->_csrf_cookie_name]) = = 1)


{


return $this->_csrf_hash = $_cookie[$this->_csrf_cookie_name];


}


Otherwise random a MD5 string


return $this->_csrf_hash = MD5 (Uniqid (rand (), TRUE);


}


return $this->_csrf_hash;


}


}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.