经验总结
WEB开发中常见漏洞防御方法
2019-11-11 11:07

SQL注入漏洞

SQL注入漏洞产生原因及危害

在sql查询中很多程序员会将变量拼接入sql语句后再进行查询,这样如果黑客在参数中插入其他sql语句就可能导致我们网站的密码被被黑客查询出来或者被拖取大量数据,如果在开发中使用了字符串拼接进SQL语句就必须进行严格的过滤,任何用户输入的内容都不可信任,以下列举几种防御方法。

数字型查询注入防护

查询例子如下

$id = $_GET['id'];

$sql="SELECT * FROM table WHERE id='$id'";

$conn->query($sql);

如果是这样的数字型注入我们可以强制将传入参数转换为整数,以剔除黑客拼接的SQL语句。修改如下

$id = intval($_GET['id']);

$sql="SELECT * FROM table WHERE id='$id'";

$conn->query($sql);

这是这个网页正常查询的返回的结果。

图片1.jpg

这是一个典型的数字型注入,我们输入注入语句可见注入成功

图片2.jpg

我们强制转换类型到代码中:

图片3.jpg

我们再执行注入可以看到恢复正常查询,注入失败。

图片4.jpg

非数字型注入防护-通用防护

如果查询参数不是数字,那么我们该如何防护呢,那么这里可以使用通用型防护,对数字型和非数字型同样适用,我们知道web中获取参数的方式主要有三种分别是get、post、cookie。那么我们防护的主要方面也是这三个方面,我们可以对网站的所有流量进行黑名单过滤。当然这个也可以拦截xss漏洞。具体流程如下:

图片5.png

具体实现代码:

<?php
class WAF{
  public $filter;
  public function __construct() {
   $this->filter = "
\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]+?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]+?\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)|<.*(iframe|frame|style|embed|object|frameset|meta|xml|a|img)|hacker";
}
  public function CheckInject($Value){
    if(is_array($Value)){
    $Value=implode($Value);
    }
    if (preg_match("/".$this->filter."/is",$Value)==1){
    die("非法操作!");
  }
  }
}
$checkhack = new WAF();
foreach($_GET as $key=>$value){
  $checkhack->CheckInject($value);
}
foreach($_POST as $key=>$value){
  $checkhack->CheckInject($value);
}
foreach($_COOKIE as $key=>$value){
  $checkhack->CheckInject($value);


?>


测试

同样我们在原先的网站上将我们的waf.php文件包含进去,在执行注入操作,可见我们已经将非法操作拦截。

图片6.jpg

图片7.png


使用预处理对注入进行防护

//预处理语句,?为绑定的参数

$mysql = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");

//绑定参数第一个参数为参数列处理其余参数的数据类型。如下$firstname, $lastname, $email三个变量都为字符串类型所以,第一个参数为sss

$mysql->bind_param("sss", $firstname, $lastname, $email);

 /*参数1有以下四种类型:

i - integer(整型)

d - double(双精度浮点型)

 s - string(字符串)

b - BLOB(布尔值)*/

//下面设置参数并执行

$firstname = "John";

$lastname = "Doe";

$email = "john@example.com";

$stmt->execute();

预处理的优点

预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行)。

绑定参数减少了服务器带宽,你只需要发送查询的参数,而不是整个语句。

预处理语句针对SQL注入是非常有用的,因为参数值发送后使用不同的协议,保证了数据的合法性。


XSS漏洞的防护

xss漏洞产生的原因及危害

xss漏洞和sql注入一样也是注入型漏洞,主要是黑客在网页中注入恶意的js代码,可以导致我们的cookie被盗取,黑客通过cookie欺骗就能轻松登陆我们的后台,黑客也可以利用js进行挂马、黑帽seo、攻击客户计算机等操作危害十分严重。那么如何防御呢,我将讲解两种主要防御方法。

xss分类

xss主要分为反射型,储存型、和DOM型

转义 htmlspecialchars()

我们知道在数据库查询出来的数据可以打印到网页上,但是数据可能是用户在注册或者输入其他表单输入的,那么这里用户可能输入的是js或者html代码,这里就可能导致,用户输入的代码在浏览器中被解析并执行,那么我们这就可以通过 htmlspecialchars()将其转义为不可解析的字符串,从而避免此类攻击。

这是一个模拟存在xss漏洞的网页。我们进行模拟攻击和修复。
<?php
    $id = $_GET['id'];
    echo $id;
    ?>

我们传入一个xss攻击代码,可见直接获取了当前网页的cookie内容

图片7.png

那我们在输出时候给$id加上htmlspecialchars()呢
<?php
    $id = $_GET['id'];
    echo htmlspecialchars($id);
    ?>

我们可以明显看到浏览器不再解析我们传入的js代码,而是将它当做普通字符串输出。

图片8.png

通用型防护

将我们sql注入的通用型防护waf.php包含到该网页同样可以实现过滤。

图片9.png

CSRF漏洞的防御

CSRF漏洞产生的原因和危害

CSRF漏洞主要是我们的网站没有对表单验证,这个表单是不是我们网站自己本身提交的,如果有一个改密码的表单被人构造并放在了其他人的网站上,我们在打开这个黑客精心构造的域外表单时候就导致了我们本身的密码被修改,黑客也可以通过CSRF漏洞进行蠕虫式传播,新浪微博就曾遭遇过此类攻击,黑客精心构造表单,当你打开这个表单的链接时候就会自动发送一条微博,其他人打开同样进行这样的操作。

TOKEN防护

我们如何验证这个表单是不是我们自己网站本身提交的呢,那么我们可以在每个表单下生成一个隐藏的input表单存放一个TOKEN,在进行表单提交时会验证这TOKEN是否在SESSION上,如果在就执行这个表单的操作,如果TOKEN不在或者根本没提交TOKEN那么说明表单是伪造的,我们直接截断操作。具体流程如下:

防护代码编写:
<?php
class WAF{
  public function CheckCsrf($Token){//检查TOKEN
      if($Token!=$_SESSION['CsrfToken']){
          $this->UnsetToken();
          die('NO-TOKEN!');

      }else if(empty($Token)){
          die('NO-TOKEN!');
      }
  }
  public function Csrf_Token(){//生成TOKEN表单
    echo "<input type=\"hidden\" name=\"" . "TOKEN". "\"value=\"" .$this->GetTager(). "\"> ";
  }

  public function UnsetToken(){//删除TOKEN
    unset($_SESSION['CsrfToken']);
  }

  public function GenerateToken(){//生成TOKEN值
    $hash=md5(uniqid(rand(),true));//unique生成ID并md5加密
    $n=rand(1,23);
    $token=substr($hash, $n,9);
    return $token;
  }
  public function GenerateStoken(){//将TOKEN写入SESSION
    if(empty($_SESSION['CsrfToken'])){
      $Token=$this->GenerateToken();
        $_SESSION['CsrfToken']=$Token;
    }
   
  }
  public function GetTager(){//获取TOKEN
    $this->GenerateStoken();
    return $_SESSION['CsrfToken'];
  }

}
?>

测试

我们分别写两个文件分别是index.php用于提交表单,xss.php用于验证表单

index.php
<?php
include('waf.php');
session_start();
$tokenwaf = new WAF();
?>
<form action="xss.php" method="POST">
  <input type="text" name="box">
  <input type="submit" name="submit">
  <?php echo $tokenwaf->Csrf_Token()?>//生成TOKEN表单
</form>

xss.php
<?php
include('waf.php');
session_start();
$tokenwaf = new WAF();
$tokenwaf->CheckCsrf($_POST['TOKEN']);//验证TOKEN
echo "check success";
    ?>

可以看到我们代码非常简单,只要我们通过动态的TOKEN验证,那就会输出check success,否则输出NO-TOKEN!
首先我们直接提交表单是没有问题的直接返回成功

图片12.png

但是我们F12将TOKEN值删除再提交呢?

图片13.png

可以看到会直接截断

图片14.png

相关实验推荐:web防御中的代码安全 

 

上一篇:PHP-Session利用总结
下一篇:PhpStudy BackDoor2019 深度分析
版权所有 合天智汇信息技术有限公司 2013-2021 湘ICP备14001562号-6
Copyright © 2013-2020 Heetian Corporation, All rights reserved
4006-123-731