CI框架学习一(参数输入/数据库操作)

对于代码审计来讲,比较重要的是了解其参数输入及数据库操作方式。在阅读了CI开发手册后,我总结了下面的笔记。

参数输入

1. CI自带输入类

输入类有两个用途:

为了安全性,对输入数据进行预处理

提供了一些辅助方法来获取输入数据并处理

在CI框架中,在/application/config/config.php中可以选择开启全局过滤xss

1
$config['global_xss_filtering'] = TRUE;

最常见调用方法如下,第二个参数为TRUE时,可加载xss_clean函数对输入的参数进行过滤,当然只是过滤xss,xss_clean函数定义在/system/core/Security.php,没有针对sql injection做对于的过滤措施。

1
2
3
4
$this->input->post($index (mixed),[, $xss_clean = NULL]])
$this->input->get()
$this->input->cookie()
$this->input->server()

其它的较少使用的如

1
2
3
4
5
6
$this->input->get_post('some_data', TRUE);  //先get再post
$this->input->post_get('some_data', TRUE);
$this->input->ip_address();
$this->input->user_agent();
$this->input->request_headers();
....

2. URI 分段传递

当URI多于两个段,多余的段将作为参数传递到你的方法中。例如你的URI是这样
/index.php/news/view/test
那么view方法会接受”test”作为参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
public function view($slug = Null)
{

$data['news'] = $this->news_model->get_news($slug);
$data['title'] = "The detail news";

if (empty($data['news']))
{
show_404();
}
$this->load->view('templates/header', $data);
$this->load->view('news/index', $data);
$this->load->view('templates/footer');
}

在/application/config/config.php中,定义了全局的URI参数

1
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';

开启后,可自定义允许的URI字符的白名单。利用这种方式传入的参数由于利用的是URI,不会被服务器urldecode,如果其他字符没有被过滤的话,可以用下面的语句测试是否注入: (3)and(sleep(5))

3. URI类方法获取

最常用调用方法如下:

1
$this->uri->segment(n, [, $no_result = NULL]))

用于从 URI 中获取指定段。参数 n 为你希望获取的段序号,URI 的段从左到右进行编号。 例如,如果你的完整 URL 是这样的:
/index.php/news/view/test,那么从index.php开始为0,要获取“test”值,代码如下

1
$this->uri->segment(3)

还有一个比较好用的方法

1
$this->uri->uri_to_assoc([$n = 3[, $default = array()]])

该方法用于将 URI 的段转换为一个包含键值对的关联数组,第一个参数为位移,默认为3(前两段为控制器和方法)。如下URI index.php/user/search/cid/1/sid/2

1
2
3
array (size=2)
'sid' => string '1' (length=1)
'cid' => string '2' (length=1)

这种方法获取参数也受permitted_uri_chars的影响。

4. 典型的PHP方法

大家最熟悉的$_GET[], $_POST[], $_POST[]等。

数据库操作

1. 基本查询

在CI中提供了一个查询的类库database,需要手工去加载(autoload中未自动加载的话)

1
$this->load->database()

加载后,可以直接$this->db->function调用自带的方法了。

常规查询,query($sql)

1
$this->db->query("select * from news where id = '".$id."'")

加入单引号保护后,若变量直接传入仍然不安全。这时可用escape()方法进行转义,escape方法会自动引入单引号。

1
$this->db->query("select * from news where id = ".$this->db->escape($id))

参数绑定

参数绑定会自动转义绑定的参数,生成安全的查询语句

1
2
$sql = "SELECT * FROM some_table WHERE id = ? AND status = ? AND author = ?";
$this->db->query($sql, array(3, 'live', 'Rick')); //传入索引数组

2. 查询构造器

CodeIgniter 提供了查询构造器类,查询构造器允许你使用较少的代码来在数据库中 获取、新增或更新数据。有时只需要一两行代码就能完成数据库操作。构造器所有方法的定义位于/system/database/DB_query_builder.php。
比较常用的如下:

1
2
3
4
5
$this->db->get($table, $limit1, $limit2) // select * from $table limit $limit1, $limit2
$this->db->get_where('mytable', array('id' => $id), $limit, $offset); // select * from mytable where id = $id limit $limit, $offset
$this->db->insert('mytable', $data); //$data为数组
$this->db->update('mytable', $data) //搭配下面的where语句设置条件
$this->db->delete('mytable', array('id' => $id)); //第二个参数也可用where语句代替

部分sql语句编写,需要搭配

1
2
3
4
5
6
$this->db->select('title, content, date');  //选择查询的字段
$this->db->where(array('name' => $name, 'title' => $title, 'status' => $status);); // 查询条件设置
$this->db->like('title', 'match'); // where `title` like '%match%'
$this->db->order_by('title', 'DESC');
$this->db->limit(10, 20);
.....

3. 经典的php语句

php的mysql扩展函数。

参考:

CodeIgniter 用户指南