首页 > 编程技术 > php

PHP登录中的防止sql注入方法分析

发布时间:2016-11-25 15:22

防止sql注入这些细节问题一般是出现在大意程序员或者是新手程序员了,他们未对用户提交过来的数据进行一些非常过滤从而导致给大家测试一下就攻破了你的数据库了,下面我来简单的一个用户登录未进行安全配置可能出现的sql注入方法,下面一起来看看吧。

比如以下一段登录的代码:

 代码如下 复制代码

if($l = @mysql_connect('localhost', 'root', '123')) or die('数据库连接失败');

mysql_select_db('test');

mysql_set_charset('utf8');

$sql = 'select * from test where username = "$username" and password = "$password"';

$res = mysql_query($sql);

if(mysql_num_rows($res)){

header('Location:./home.php');

}else{

die('输入有误');

}


注意上面的sql语句,存在很大的安全隐患,如果使用以下万能密码和万能用户名,那么可以轻松进入页面:

 代码如下 复制代码

1. $sql = 'select * from test where username = "***" and password = "***" or 1 = "1"';

很明显,针对这条sql语句的万能密码是: ***" or 1 = "1

 代码如下 复制代码

2. $sql = 'select * from test where username ="***" union select * from users/* and password = "***"';

正斜线* 表示后面的不执行,mysql支持union联合查询, 所以直接查询出所有数据; 所以针对这条sql语句的万能用户名是:***" union select * from users/*

 但是,此注入只针对代码中的sql语句,如果

 代码如下 复制代码
$sql = "select * from test where username = $username and password = $password";

上面的注入至少已经不管用了,不过方法是一样的;

在使用PDO之后,sql注入完全可以被避免,而且在这个快速开发的时代,框架横行,已然不用过多考虑sql注入问题了。

下面整理了两个防止sql注册函数

 代码如下 复制代码

/* 过滤所有GET过来变量 */
foreach ($_GET as $get_key=>$get_var)
{
if (is_numeric($get_var)) {
$get[strtolower($get_key)] = get_int($get_var);
} else {
$get[strtolower($get_key)] = get_str($get_var);
}
}
/* 过滤所有POST过来的变量 */
foreach ($_POST as $post_key=>$post_var)
{
if (is_numeric($post_var)) {
$post[strtolower($post_key)] = get_int($post_var);
} else {
$post[strtolower($post_key)] = get_str($post_var);
}
}
/* 过滤函数 */
//整型过滤函数
function get_int($number)
{
return intval($number);
}
//字符串型过滤函数
function get_str($string)
{
if (!get_magic_quotes_gpc()) {
return addslashes($string);
}
return $string;
}

还有一些博客会这样写

 代码如下 复制代码

<?php  
function post_check($post)
{
if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否为打开
{
$post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤
}
$post = str_replace("_", "\_", $post); // 把 '_'过滤掉
$post = str_replace("%", "\%", $post); // 把' % '过滤掉
$post = nl2br($post); // 回车转换
$post= htmlspecialchars($post); // html标记转换
return $post;
}
?>

跨站攻击就是利用程序上的一些细节或bug问题进行的了,那么我们要如何耿防止跨站攻击呢?下面我们费话不说多了来给大家整理一个防止跨站攻击例子,希望对各位有帮助。

代码是最好的语言。。

 代码如下 复制代码

<?php
#demo for prevent csrf

/**
* enc
*/
function encrypt($token_time) {
return md5(‘!@##$@$$#%43′ . $token_time);
}

$token_time = time();
$token = encrypt($token_time);
$expire_time = 10;

if ($_POST) {
$_token_time = $_POST['token_time'];
$_token = $_POST['token'];

if ((time() – $_token_time) > $expire_time) {
echo “expired token”;
echo “<br />”;
}

echo $_token;
echo “<br />”;
$_token_real = encrypt($_token_time);

echo $_token_real;
//compare $_token and $_token_real
}
?>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=”content-type” content=”text/html; charset=utf-8″ />
<title>test for csrf</title>
<meta http-equiv=”" content=”" />
</head>
<body>
<form method=”post” action=”">
<input type=”text” name=”text” id=”" value=”hello” />
<input type=”hidden” name=”token” id=”" value=”<?php echo $token ?>” />
<input type=”hidden” name=”token_time” id=”" value=”<?php echo $token_time ?>” />

<input type=”submit” name=”submit” id=”" value=”submit” />

</form>
</body>
</html>

 
通过在你的表单中包括验证码,你事实上已经消除了跨站请求伪造攻击的风险。可以在任何需要执行操作的任何表单中使用这个流程

当然,将token 存储到session更好,这儿只是简单示例下

简单分析:

token防攻击也叫作(令牌)了,我们在用户访问页面时就生成了一个随机的token保存session与表单了,用户提交时如果我们获取到的token与session不一样就可以提交重新输入提交数据了

防止sql注入不但是新学的程序员朋友需要深入了解的一个重要知识点之外,还是我们这些写了多年程序的朋友也必须注意的东西,下面给新手介绍php 防止查询的sql攻击的一些例子,希望对各位会有所帮助。

一个入门级别的例子

 代码如下 复制代码

$k = $_REQUEST['k'];

$k = addslashes($k);//转义:单引号,双引号,反斜线,NULL

$k = str_replace('%', '\%', $k);

$k = str_replace('_', '\_', $k);

$sql = "select * from users where name like '%$k%'";

if(!empty($k)){

$res = mysql_query($sql, $con) or die(mysql_error());

if($row = mysql_fetch_assoc($res)){

foreach($row as $k=>$v){

echo $row[$k].':'.$row[$v].'<br />';

}

}

}else{

echo '******';

}

补充

mysql_real_escape_string()

所以得SQL语句如果有类似这样的写法:

"select * from cdr where src =".$userId; 都要改成 $userId=mysql_real_escape_string($userId)

例子

 代码如下 复制代码

<?php
 
$clean = array();
$mysql = array();
 
$clean['last_name'] = "O'Reilly";
$mysql['last_name'] = mysql_real_escape_string($clean['last_name']);
 
$sql = "INSERT
      INTO   user (last_name)
      VALUES ('{$mysql['last_name']}')";
 
?>

所有有打印的语句如echo,print等 在打印前都要使用htmlentities() 进行过滤,这样可以防止Xss,注意中文要写出

 代码如下 复制代码

htmlentities($name,ENT_NOQUOTES,GB2312) 。

php 3des加密解密是一个在数据传输中常用的一个简单的加密方式了,下面我整理了一个php 3des加密解密类程序有需要了解的朋友可进入参考。

3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。

 代码如下 复制代码


<?php
class Crypt3Des {
var $key;
function Crypt3Des($key){
$this->key = $key;
}

function encrypt($input){
$size = mcrypt_get_block_size(MCRYPT_3DES,'ecb');
$input = $this->pkcs5_pad($input, $size);
$key = str_pad($this->key,24,'0');
$td = mcrypt_module_open(MCRYPT_3DES, '', 'ecb', '');
$iv = @mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
@mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
//$data = base64_encode($this->PaddingPKCS7($data));
$data = base64_encode($data);
return $data;
}

function decrypt($encrypted){
$encrypted = base64_decode($encrypted);
$key = str_pad($this->key,24,'0');
$td = mcrypt_module_open(MCRYPT_3DES,'','ecb','');
$iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_RAND);
$ks = mcrypt_enc_get_key_size($td);
@mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$y=$this->pkcs5_unpad($decrypted);
return $y;
}

function pkcs5_pad ($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}

function pkcs5_unpad($text){
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) {
   return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad){
   return false;
}
return substr($text, 0, -1 * $pad);
}

function PaddingPKCS7($data) {
$block_size = mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_CBC);
$padding_char = $block_size - (strlen($data) % $block_size);
$data .= str_repeat(chr($padding_char),$padding_char);
return $data;
}
}

用法:

$crypt = new Crypt3Des('密钥');
$a = '待加密字符串';
$code = $crypt->encrypt($a);//加密
echo $crypt->decrypt($code);//解密

在php应用开发中如果要过滤html标签我们可以直接使用很多函数来实现,但在实际应用中像有一些标签是需要保留的,有一些是要过滤的,下面我就整理了一个完整例子

例子,使用strip_tags()函数过滤所有html

 代码如下 复制代码

$str = '<a href="#">href</a>';
echo htmlspecialchars($str);
echo strip_tags($str);

输出结果为

&lt;a href=&quot;#&quot;&gt;href&lt;/a&gt;

href


上面函数有一个问题就是包括html标签,img标签都过滤掉了,如果我们希望保留图片怎么办

在网上找到一个函数

 代码如下 复制代码

function uh($str)
 {
     $farr = array(
         "/s+/",                                                                   
                        //过滤多余的空白
         "/<(/?)(script|i?frame|style|html|body|title|link|meta|?|%)([^>]*?)>/isu",
   //过滤 <script 等可能引入恶意内容或恶意改变显示布局的代码,如果不需要插入flash等,还可
 以加入<object的过滤
         "/(<[^>]*)on[a-za-z]+s*=([^>]*>)/isu",                                    
 //过滤网页特效的on事件
     
    );
    $tarr = array(
         " ",
         "<123>",           //如果要直接清除不安全的标签,这里可以留空
         "12",
    );
  $str = preg_replace( $farr,$tarr,$str);
    return $str;
 }

这样就可以过滤指定标签了,上面方法还不会我们可参考下面办法

 

 代码如下 复制代码
 <br>$str=preg_replace("/\s+/", " ", $str); //过滤多余回车 <br>$str=preg_replace("/&lt;[ ]+/si","&lt;",$str); //过滤&lt;__("&lt;"号后面带空格) <br><br>$str=preg_replace("/&lt;\!--.*?--&gt;/si","",$str); //注释 <br>$str=preg_replace("/&lt;(\!.*?)&gt;/si","",$str); //过滤DOCTYPE <br>$str=preg_replace("/&lt;(\/?html.*?)&gt;/si","",$str); //过滤html标签 <br>$str=preg_replace("/&lt;(\/?head.*?)&gt;/si","",$str); //过滤head标签 <br>$str=preg_replace("/&lt;(\/?meta.*?)&gt;/si","",$str); //过滤meta标签 <br>$str=preg_replace("/&lt;(\/?body.*?)&gt;/si","",$str); //过滤body标签 <br>$str=preg_replace("/&lt;(\/?link.*?)&gt;/si","",$str); //过滤link标签 <br>$str=preg_replace("/&lt;(\/?form.*?)&gt;/si","",$str); //过滤form标签 <br>$str=preg_replace("/cookie/si","COOKIE",$str); //过滤COOKIE标签 <br><br>$str=preg_replace("/&lt;(applet.*?)&gt;(.*?)&lt;(\/applet.*?)&gt;/si","",$str); //过滤applet标签 <br>$str=preg_replace("/&lt;(\/?applet.*?)&gt;/si","",$str); //过滤applet标签 <br><br>$str=preg_replace("/&lt;(style.*?)&gt;(.*?)&lt;(\/style.*?)&gt;/si","",$str); //过滤style标签 <br>$str=preg_replace("/&lt;(\/?style.*?)&gt;/si","",$str); //过滤style标签 <br><br>$str=preg_replace("/&lt;(title.*?)&gt;(.*?)&lt;(\/title.*?)&gt;/si","",$str); //过滤title标签 <br>$str=preg_replace("/&lt;(\/?title.*?)&gt;/si","",$str); //过滤title标签 <br><br>$str=preg_replace("/&lt;(object.*?)&gt;(.*?)&lt;(\/object.*?)&gt;/si","",$str); //过滤object标签 <br>$str=preg_replace("/&lt;(\/?objec.*?)&gt;/si","",$str); //过滤object标签 <br><br>$str=preg_replace("/&lt;(noframes.*?)&gt;(.*?)&lt;(\/noframes.*?)&gt;/si","",$str); //过滤noframes标签 <br>$str=preg_replace("/&lt;(\/?noframes.*?)&gt;/si","",$str); //过滤noframes标签 <br><br>$str=preg_replace("/&lt;(i?frame.*?)&gt;(.*?)&lt;(\/i?frame.*?)&gt;/si","",$str); //过滤frame标签 <br>$str=preg_replace("/&lt;(\/?i?frame.*?)&gt;/si","",$str); //过滤frame标签 <br><br>$str=preg_replace("/&lt;(script.*?)&gt;(.*?)&lt;(\/script.*?)&gt;/si","",$str); //过滤script标签 <br>$str=preg_replace("/&lt;(\/?script.*?)&gt;/si","",$str); //过滤script标签 <br>$str=preg_replace("/javascript/si","Javascript",$str); //过滤script标签 <br>$str=preg_replace("/vbscript/si","Vbscript",$str); //过滤script标签 <br>$str=preg_replace("/on([a-z]+)\s*=/si","On\\1=",$str); //过滤script标签 <br>$str=preg_replace("/&amp;#/si","&amp;#",$str); //过滤script标签,如javAsCript:alert( <br>


如果只要过滤过滤html标签,js代码,css样式标签

 代码如下 复制代码


<?php
$str = preg_replace( "@<script(.*?)</script>@is", "", $str );
$str = preg_replace( "@<iframe(.*?)</iframe>@is", "", $str );
$str = preg_replace( "@<style(.*?)</style>@is", "", $str );
$str = preg_replace( "@<(.*?)>@is", "", $str );
?>

这样即可了哦。

标签:[!--infotagslink--]

您可能感兴趣的文章: