资讯专栏INFORMATION COLUMN

php安全问题思考

alphahans / 2341人阅读

摘要:用户提交过来的数据都是不可信的,所以,在查库或入库前需要对提交过来的数据进行过滤或字符的转换处理,以防止注入或攻击等问题。

用户提交过来的数据都是不可信的,所以,在查库或入库前需要对提交过来的数据进行过滤或字符的转换处理,以防止SQL注入或xss攻击等问题。

一、防止SQL注入

什么是SQL注入攻击?

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

寻找SQL注入的方法:

1.通过get请求

2.通过post请求

3.其他http请求,如cookie

常见的SQL注入问题:

数据库查询参数的类型转换处理

1. 转义字符处理不当

Talk is cheap,Show me the code.
多说无益,代码亮出来吧!

  // 构造动态SQL语句
  $sql = "select * from tbl where field = "$_GET["input"]"";

  // 执行SQL语句
  $res = mysql_query($sql);

测试:
在下边的网址后边加一个单引号,就会报数据库错误
http://testphp.vulnweb.com/ar...

2. 类型处理不当
// 构造动态SQL语句
$sql = "select * from tbl where field = $_GET["user_id"]";

// 执行SQL语句
 $res = mysql_query($sql);

Mysql内置了一个命令,可以读取文件

Union all select load_file("/etc/passwd")--

select * from tbl where userid = 1 union all select load_file("etc/passwd")--

该命令会获取数据库管理员的密码。

处理方法:
需要将客户端传过来的数据进行类型强制转换,而后再查询

$user_id = (int)$_GET["user_id"];
"select * from tbl where userid = {$user_id}";
3. 查询语句组织不当

user.php?table=user&

4. 错误处理不当

即将站点的错误信息暴漏给用户,这样非常危险。

// 构造动态查询语句

$getid = "select * from tbl where userid > 1";

// 执行SQL语句

$res = mysql_query($getid) or die("
".mysql_error()."
");
5. 多个提交处理不当
// 参数是否是一个字符串

if(is_string($_GET["param"])){}
数据入库时将转换单引号、双引号、反斜杠为实体

在入库的时候如果不过滤 " ""这样的东西,这样会使数据库报错,或者注入等问题。

先将字符串用htmlspecialchars()转换为实体后存储到数据库,然后从数据库读出来时htmlspecialchars_decode()转为HTML标签。

htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。

函数原型:htmlspecialchars(string,quotestyle,character-set)

预定义的字符是:

& (和号)    成为 &
” (双引号)  成为 "
‘ (单引号)  成为 '
< (小于)    成为 <
> (大于)    成为 >

htmlspecialchars_decode() 函数把一些预定义的 HTML 实体转换为字符(和htmlspecialchars相反)。

函数原型:htmlspecialchars_decode(string,quotestyle)

二、防止xss攻击

什么是xss攻击?
和上边的sql注入不同的是,xss攻击是合法的字符串,如经过htmlspecialchars()方法实体化后,可以保存在数据库中,但是,当访问含有该字符串的内容页面时,就会出现问题,如字符串里边还有JavaScript,frame代码,原来的页面就会被篡改。

比如你写个留言本,有人去留言写

除了通过正常途径输入XSS攻击字符外,还可以绕过JavaScript校验,通过修改请求达到XSS攻击的目的,如下图:

了解到XSS攻击的原理和危害后,其实要预防也不难,下面提供一个简单的PHP防止XSS攻击的函数:

除了通过正常途径输入XSS攻击字符外,还可以绕过JavaScript校验,通过修改请求达到XSS攻击的目的。

了解到XSS攻击的原理和危害后,其实要预防也不难,下面提供一个简单的PHP防止XSS攻击的函数:

";
clean_xss($str); //如果你把这个注释掉,你就知道xss攻击的厉害了
echo $str;
?>

避免被XSS:
1.给用户开放的编辑器尽量过滤掉危险的代码
如果是html编辑器,一般的做法是保留大部分代码,过滤部分可能存在危险的代码,如script, iframe等等

三、PHP MySQL 预处理语句

预处理语句对于防止 MySQL 注入是非常有用的。

预处理语句及绑定参数
预处理语句用于执行多个相同的 SQL 语句,并且执行效率更高。
预处理语句的工作原理如下:
预处理:创建 SQL 语句模板并发送到数据库。预留的值使用参数 "?" 标记 。例如:

INSERT 
    INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)

数据库解析,编译,对SQL语句模板执行查询优化,并存储结果不输出。
执行:最后,将应用绑定的值传递给参数("?" 标记),数据库执行语句。应用可以多次执行语句,如果参数的值不一样。
相比于直接执行SQL语句,预处理语句有两个主要优点:

预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行)。
绑定参数减少了服务器带宽,你只需要发送查询的参数,而不是整个语句。
预处理语句针对SQL注入是非常有用的,因为参数值发送后使用不同的协议,保证了数据的合法性。

PDO预处理机制
可以使用多种方式实现预处理:指的是在绑定数据进行执行的时候,可以有多种方式。

预处理语句中为变量
使用数组指定预处理变量

  1、准备预处理语句(发送给服务器,让服务器准备预处理语句)

  PDOStatement PDO::prepare:类似exec将一条SQL语句发送给Mysql服务器  

    //PDO::prepare 能够自动的准备一个预处理语句,用户需要准备的只是预处理所要执行的语句
    //需求:往学生表里循环插入10条记录
    //PDO的预处理能够自动的将对应的以:开始的变量给记录下来,实际发送给服务器的是“?”
    $sql1 = "insert into pro_student values(null,:s_name,:s_num,:s_gender,:s_age,:c_id)";

  2、发送预处理语句

    $stmt = $pdo->prepare($sql1);

  3、给预处理绑定数据

    $arr = array(
      ":s_name" => "房祖名",
      ":s_num" => "itcast0013",
      ":s_gender" => 0,
      ":s_age" => 28,
      ":c_id" => 2
    );

 

  4、执行预处理:将要操作的数据发送给预处理语句,再执行预处理语句

    PDOStatement::execute([$array]):数组用来传递对应的参数

    $stmt->execute($arr); //执行预处理

PDO预处理原理
PDO的预防sql注入的机制也是类似于使用mysql_real_escape_string 进行转义,PDO 有两种转义的机制,第一种是本地转义,这种转义的方式是使用单字节字符集(PHP < 5.3.6)来转义的(单字节与多字节),来对输入进行转义,但是这种转义方式有一些隐患。隐患主要是:在PHP版本小于5.3.6的时候,本地转义只能转换单字节的字符集,大于 5.3.6 的版本会根据 PDO 连接中指定的 charset 来转义。

第二种方式是PDO,首先将 sql 语句模板发送给Mysql Server,随后将绑定的字符变量再发送给Mysql server,这里的转义是在Mysql Server做的,它是根据你在连接PDO的时候,在charset里指定的编码格式来转换的。这样的转义方式更健全,同时还可以在又多次重复查询的业务场景下,通过复用模板,来提高程序的性能。如果要设置Mysql Server 来转义的话,就要首先执行:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

原始链接方法:

setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);    
$dbh->exec("set names utf8");   

$title    = "我们的爱情";
$content  = "你是/谁啊,大几都"老梁"做做&>women没" . " 测试打印号"我是单引号"哈哈";
$user_id  = 174742;
$add_time = date("Y-m-d H:i:s");

$insert_sql = "insert into post_tbl (title, content, user_id, add_time) values (:x_title, :x_content, :x_user_id, :x_add_time)";

$stmt = $dbh->prepare($insert_sql); 
$stmt->execute(array("x_title"=>$title,":x_content"=> $content, ":x_user_id" => $user_id, ":x_add_time" => $add_time));    
echo $dbh->lastinsertid();    

可见这次PHP是将SQL模板和变量是分两次发送给MySQL的,由MySQL完成变量的转义处理,既然变量和SQL模板是分两次发送的,那么就不存在SQL注入的问题了,但需要在DSN中指定charset属性,如:
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8", "root");

示例:

/**
*  插入用户的Token
*/
function photo_save_token($user_id, $token)
{
    // 参数判断
    $user_id = (int)$user_id;
    $token = trim($token);
  
    if(empty($token) || empty($user_id)) return false;

    $sql = "replace into token_db.app_token_tbl
( user_id, token, t_date, last_open_time)
values
( :x_user_id, :x_token, :x_t_date, :x_last_open_time)";
    sqlSetParam($sql,"x_user_id",$user_id);
    sqlSetParam($sql,"x_token",$token);
    sqlSetParam($sql,"x_t_date",date("Y-m-d H:i:s"));
    sqlSetParam($sql,"x_last_open_time", time());
    return mysql_query($sql);
}

总结当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符 ? 发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会。

相关文章:
php-PDO预处理    
PHP MySQL 预处理语句
pdo如何防止 sql注入

小结

①、关于sql注入可以使用htmlspecialchars()或addslashes()方法,如果连接mysql,可以用mysql_real_escape_string(),还有在php.ini中配置magic_quotes_gpc开启自动转义的扩展。

PHP环境打开自动转义,PHP.INI中查看
当magic_quotes_gpc=on 时将自动进行转义(默认是on),可在程序中用get_magic_quotes_gpc()检查他的状态
程序为:

if (get_magic_quotes_gpc()==1){
     $name=stripcslashes($_POST["name"]);       
}else{
     $name=$_POST["name"];
}

②、关于xss攻击可以写一个去处script,frame等代码的方法:

直接用这个函数editor_safe_replace代替htmlspecialchars,既保证安全又能用大部分html代码

function editor_safe_replace($content)
{
   $content = trim($content);

    $tags = array(
        ""]*?>.*?"is",
        ""]*?>.*?"is",
        ""]*?>.*?"is",
        ""]*?>.*?"is",
        ""]*?>.*?"is",
        ""]*?>"is",
        ""]*?>"is",
    );
   
    
    // 1.先过滤掉含有xss攻击的代码
    $content = preg_replace($tags, "", $content);
    
     // strip_tags过滤掉全部HTML标签(script,iframe,head,a 等标签)和上边的正则方法类似
     // $content = strip_tags($content);
    
    // 2.入库时,防止sql注入,转为HTML实体保存在数据库,单双引号都转
     $content = htmlspecialchars($content, ENT_QUOTES);
     
    // 3.替换反斜杠
    $content = preg_replace("//", "\", $content);

    // 4.替换斜杠
    $content = preg_replace("///", "/", $content);
     
     return $content;
}

所以,对于PHP的安全而言,一定要对用户提交的数据进行过滤校验处理,即先防止SQL注入,后再进行XSS过滤,这两个都需要两手一起抓,且两手都要硬,否则,你的网站将会存在很大的安全风险。

相关文章:
PHP 安全三板斧:过滤、验证和转义之转义篇 & Blade模板引擎避免XSS攻击原理探究
8个很有用的PHP安全函数,你知道几个?
HTML 字符实体对照表
PDO使用方法简介
利用SQL注入漏洞登录后台

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21855.html

相关文章

  • 起步-学习php扩展开发的背景

    摘要:开发扩展是用语言实现的,流行的很大一个原因也是因为有大量开发者通过扩展实现大量通用的功能供广大社区开发者使用。扩展化的优势产品安全性和私密性好系统性能高扩展化的劣势开发效率低的优势之一就是开发效率高,需要选择系统合适的模块进行扩展化。 php是解释性语言,不需要编译。对于用php写的产品,如果需要直接源码安装到客户的运行环境中,则存在很大的安全隐患。客户甚至可以把你的产品直接做二次部署...

    joyqi 评论0 收藏0
  • 我在全球最大的同性社交平台那点事

    摘要:从最大的同性社交平台获取数据好了,言归正传,回到题目。乌云密布的爬虫百度网盘这件事,是我不想看到的,这类安全问题的一个共同特点用户自身确实存在问题。 本文作者:夏之冰雪,i春秋签约作家 《我在百度网盘上看到上万条车主个人信息,企业、政府高官信息、各种数据库和无穷无尽的盗版》,一时间,这篇文章就火了,火爆程度另百度猝不及防。 其实呢,这事真不能全怪百度,毕竟用户分享出去了。之所以引起这么...

    AlphaWatch 评论0 收藏0
  • 对一个“老”架构的重新思考

    摘要:常见的就是,它是一个完整的目录。的特点是简单,使用一个中央版本库。当初公司的日均均超过,所以采用的是方案双机热备集群优化架构图上是两主两从。 前言 五年前,我在CNBLOG写的一篇文章,《php+mysql下,对网站架构方面的一些认识(以我维护的站点为例)》,当然,整套架构不是做的,而是配合当初的运维部门,共同完成。那个时候我从入行PHP两年,对所谓的架构也是懵懂。只觉得很深奥,很高大...

    J4ck_Chan 评论0 收藏0
  • 对一个“老”架构的重新思考

    摘要:常见的就是,它是一个完整的目录。的特点是简单,使用一个中央版本库。当初公司的日均均超过,所以采用的是方案双机热备集群优化架构图上是两主两从。 前言 五年前,我在CNBLOG写的一篇文章,《php+mysql下,对网站架构方面的一些认识(以我维护的站点为例)》,当然,整套架构不是做的,而是配合当初的运维部门,共同完成。那个时候我从入行PHP两年,对所谓的架构也是懵懂。只觉得很深奥,很高大...

    LiuRhoRamen 评论0 收藏0
  • 对一个“老”架构的重新思考

    摘要:常见的就是,它是一个完整的目录。的特点是简单,使用一个中央版本库。当初公司的日均均超过,所以采用的是方案双机热备集群优化架构图上是两主两从。 前言 五年前,我在CNBLOG写的一篇文章,《php+mysql下,对网站架构方面的一些认识(以我维护的站点为例)》,当然,整套架构不是做的,而是配合当初的运维部门,共同完成。那个时候我从入行PHP两年,对所谓的架构也是懵懂。只觉得很深奥,很高大...

    Crazy_Coder 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<