Security Implementation Analysis of ThinkPHP framework (1)
The ThinkPHP framework is one of the popular PHP frameworks in China. Although it cannot be compared with those frameworks outside China, it has the advantage that the Chinese manual is comprehensive. I recently studied SQL injection. I used to use the TP framework because the underlying layer provides security functions, so I didn't think about security issues during the development process. I want to know how TP implements SQL Injection prevention, so I read some source code. Combined with the vulnerabilities of phith0n Daniel on wooyun, I analyzed and sorted out some ideas ~~
I. I have to say I Function
The TP system provides the I function for filtering input variables. The significance of the entire function body is to obtain data in various formats, such as I ('get. '), I ('Post. and then use the htmlspecialchars function (by default) for processing. If you need to use other methods for security filtering, you can set it in/ThinkPHP/Conf/convention. php:
'Default _ filter' => 'strip _ tags', // You can also set multiple filtering methods 'default _ filter' => 'strip _ tags, stripslashes ',
You can find the I function from/ThinkPHP/Common/functions. php. The source code is as follows:
- /**
- * Filtering and default values are supported for retrieving input parameters.
- * Usage:
- * <Code>
- * I ('id', 0); get the id parameter to automatically judge get or post
- * I ('Post. name', '', 'htmlspecialchars'); get $ _ post ['name']
- * I ('get. '); get $ _ GET
- * </Code>
- * @ Param string $ name the variable name supports the specified type
- * @ Param mixed $ default value when the default value does not exist
- * @ Param mixed $ filter parameter Filtering Method
- * @ Param mixed $ datas the additional data source to be obtained
- * @ Return mixed
- */
- Function I ($ name, $ default = '', $ filter = null, $ datas = null ){
- Static $ _ PUT = null;
- If (strpos ($ name, '/') {// specifies the Modifier
- List ($ name, $ type) = explode ('/', $ name, 2 );
- } Elseif (C ('var _ AUTO_STRING ') {// forcibly converted to a string by default
- $ Type ='s ';
- }
-
- /* Get data in the format of $ name: first judge the source of the parameter, and then obtain data in various formats */
- If (strpos ($ name, '.') {list ($ method, $ name) = explode ('.', $ name, 2);} // specify the parameter Source
- Else {$ method = 'param';} // set to automatically get
- Switch (strtolower ($ method )){
- Case 'get': $ input = & $ _ get; break;
- Case 'post': $ input = & $ _ post; break;
- Case 'put':/* omitted here */
- Case 'param':/* omitted here */
- Case 'path':/* omitted here */
- }
-
- /* Filter the obtained data */
- If (''// get all variables
- $ Data = $ input;
- $ Filters = isset ($ filter )? $ Filter: C ('default _ filter ');
- If ($ filters ){
- If (is_string ($ filters) {$ filters = explode (',', $ filters);} // supports multiple filtering methods
- Foreach ($ filters as $ filter ){
- $ Data = array_map_recursive ($ filter, $ data); // loop Filtering
- }
- }
- } Elseif (isset ($ input [$ name]) {// value operation
- $ Data = $ input [$ name];
- $ Filters = isset ($ filter )? $ Filter: C ('default _ filter ');
- If ($ filters) {/* filters parameters and supports regular expression verification */
- /* Omitted here */
- }
- If (! Emptyempty ($ type) {// If the forced conversion type is set
- Switch (strtolower ($ type )){
- Case 'A': $ data = (array) $ data; break; // array
- Case 'D': $ data = (int) $ data; break; // number
- Case 'F': $ data = (float) $ data; break; // floating point
- Case 'B': $ data = (boolean) $ data; break; // boolean
- Case's ': // string
- Default: $ data = (string) $ data;
- }
- }
- } Else {// default variable value
- $ Data = isset ($ default )? $ Default: null;
- }
-
- Is_array ($ data) & array_walk_recursive ($ data, 'Think _ filter'); // If $ data is an array, use think_filter to filter the Array
- Return $ data;
- }
Well, the function is basically divided into three parts: the first one to obtain data in various formats. The second part is the cyclic encoding of the obtained data, whether it is a two-dimensional array or a three-dimensional array. The third block, that is, the second to the last line, calls think_filter to perform the last step of mysterious processing on the data.
Let's first trace the think_filter function:
- // Added the latest version 3.2.3 of row 1536
- Function think_filter (& $ value) {// filter and query special characters
- If (preg_match ('/^ (EXP | NEQ | GT | EGT | LT | ELT | OR | XOR | LIKE | NOTLIKE | not between | NOTBETWEEN | BETWEEN | NOTIN | not in | IN) $/I ', $ value )){
- $ Value. = '';
- }
- }
This function is very simple. It can be seen at a glance that a space is added after some specific keywords. But this is called the think_filter function. It only adds a space. What filtering function does it play?
We all know important logic verification, such as verifying whether a user has logged on, whether the user can buy a product, etc. It must be verified on the server side. If it is verified on the front end, it is easy to bypass. In the same way, in/exp logic structures in a program should also be controlled by the server.
When the data transmitted to the server is like this: id [0] = in & id [1] =, 3, if the think_filter function is not available, it will be parsed into 1 in the following table, it will be regarded as the server-side logic parsing. However, if it is changed to the following table 2, a space is added, and the parsing cannot be matched, the vulnerability is avoided.
- 1. $ data ['id'] = array ('in' => '1, 2, 3 ')
-
- // After being filtered by think_filter, it will look like:
- 2. $ data ['id'] = array ('in' => '1, 2, 3 ')