2020/1/30 PHP code audit of CSRF vulnerabilities

0x00 CSRF Vulnerability

CSRF (Cross-site request forgery) Cross-site request forgery: Also known as "One Click Attack" or Session Riding, often abbreviated as CSRF or XSRF, is a malicious use of the site. Although it sounds like a cross-site scripting (XSS), but it is very different from XSS, trusted users within the XSS exploit the site, while CSRF is disguised by a trusted user's request to use from trusted sites . Compared with XSS attacks, CSRF attacks are often not very popular (and therefore their resources to guard against is quite rare) and difficult to defend, it is considered more dangerous than XSS.

0x01 hazard vulnerability

To your identity:

Mail
message
property operations such as transfer or purchase of goods
change password
delete posts

0x02 vulnerabilities nature

CSRF (Cross-site request forgery) Cross-site request forgery: the attacker to induce the victim entering third party websites, third-party websites, cross-site request is sent to the attack site. Using the registered credentials victims in the attack site has been acquired, the background to bypass the user authentication, to achieve the purpose impersonate the user to perform an action on the site of attack.

A typical CSRF attack with the following processes:

受害者登录a.com,并保留了登录凭证(Cookie)。

攻击者引诱受害者访问了b.com。

b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。

a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。

a.com以受害者的名义执行了act=xx。

攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

0x03 mining ideas

Background functional modules: management background. Member Centre. Add users.
Referenced core document and there are no verification token referer related code
did not bring token: direct request this page.
Did not bring referer: return the same data

Examples codes 0x04

We first create a database:

Then write a database connection:

<?php
$conn = mysql_connect(server:"localhost",username:"root",password:"root");
mysql_select_db(database_name:"admin",$conn);//选择我们创建的admin数据库
mysql_query(query "SET NAMES GB2312");
?>

Log in to write a front-end:

<html>
<head>
<meta charset="UTF-8">
<title>用户登陆</title>

</head>
<body>
<form action="login.php" method="post">
会员名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>

<input type="submit" name="submit" value="点击登陆">

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

Write login form:

<?php
if(!isset($_POST['submit'])){
    exit('非法访问');
}

$username = $_POST['username'];
$password = $_POST['password'];
include ('conn.php');
$sql = "SELECT * FROM admin WHERE username='$username' and password='$password'";//讲我们的登陆信息插入数据库
$result= mysql_query($sql) or die("执行失败" . mysql_error());
if($conn = mysqli_fetch_array($result)){
    session_start();//开启会话判断是否注册
    $_SESSION['username'] = $row['username'];
    echo $_SESSION['username'] . ".欢迎登陆";
    echo '<a href="register.php">添加用户</a>';
}
?>

Write front-end registration

<html>
<head>
<meta charset="UTF-8">
<title>会员注册</title>

</head>
<body>
<form action="register.php" method="post">
    注册用户 <input type="text" name="username"><br/>
    密码 <input type="password" name="password"><br/>
    <input type="submit" name="用户添加">
</form>

</body>
</html>

Write a registration form

<?php
session_start();//判断是否存在已经登陆的用户名
if(!isset($_SESSION['username'])){
    echo '<script>alert("请你登陆用户")</script>';

}

$username = $_POST['username'];
$password = $_POST['password'];
include('conn.php');//包含引用数据库
$sql = "INSERT INTO admin(username,password) VALUES ($username,$password";//执行我们的数据库语句
$res_insert = mysql_query($sql);
if($res_insert){//如果我们的数据库文件存在
    echo "<script>alert("注册成功")</script>';"

}else{
    echo "<script>alert("注册失败")</script>';"
}

Registered user, we found no protection, there is a CSRF vulnerability.

直接使用bp自带的CSRF POC
ps:csrftest也可以用来测试,注意代理设置。

诱导受害者使用浏览器访问生成的html文件,
点击submit,会发现注册成功。
这样的还不够直观,我们再来想一下,如果某网站修改密码处存在CSRF漏洞。
当受害者点击链接后,再次登陆会发现自己的密码被修改。我们能够得到受害者密码。(poc是我们制作的)

tips:用js自动触发就不用受害者点击Submit提交表单。意思就是,别人点击连接就可以直接触发csrf!

0x05  其他CSRF

 CSRF蠕虫

在CSRF的攻击页面上嵌入蠕虫传播的攻击向量,蠕虫传播要面向不同的用户生成不同的请求。之前的攻击可预测所有的参数,现在必须想办法标识不同用户的数据。
1,服务端脚本获取准备一个php,asp页面,可以检测Referer字段读取url中的用户id等。
2,JSON劫持如果网站提供了这样的数据接口,可以用来获取敏感信息

flash CSRF

网站的根目录下有一个文件crossdomain.xml

<cross-domain-policy>
<allow-access-from domain="*.baidu.com" secure='true'/>
<allow-http-request-headers-from domain="*.baidu.com" headers='*'/>

secure='true' 表示只能通过安全连接请求
表示哪些域的flash请求可以读写本域的资源,同样可以读取token数据发送请求。

0x06 防御方法

1:验证码

这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串。但是这个方法只能用来辅助,不是主要手段,受限于业务,有的网站不能有验证码。

2:服务端进行CSRF防御 

在客户端页面增加伪随机数。

(1).Cookie Hashing(所有表单都包含同一个伪随机值):  
这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>

<?php
    //构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie”, $value, time()+3600);
  ?>

在表单里增加Hash值,以认证这确实是用户发送的请求。

 <?php
  $hash = md5($_COOKIE['cookie']);
?>
<form method=”POST” action=”transfer.php”>
  <input type=”text” name=”toBankId”>
  <input type=”text” name=”money”>
  <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
  <input type=”submit” name=”submit” value=”Submit”>
</form>

然后在服务器端进行Hash值验证

<?php
        if(isset($_POST['check'])) {
             $hash = md5($_COOKIE['cookie']);
             if($_POST['check'] == $hash) {
                  doJob();
             } else {
        //...
             }
        } else {
      //...
        }
      ?>

3:One-Time Tokens(不同的表单包含一个不同的伪随机值

在实现One-Time Tokens时,需要注意一点:就是“并行会话的兼容”。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单都含有非法的伪随机值。必须小心操作以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点

<?php
   function gen_token() {
  //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。
  //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》
        $token = md5(uniqid(rand(), true));
        return $token;
   }
 
2).然后是Session令牌生成函数(gen_stoken()):
 
   <?php
     function gen_stoken() {
    $pToken = "";
    if($_SESSION[STOKEN_NAME]  == $pToken){
      //没有值,赋新值
      $_SESSION[STOKEN_NAME] = gen_token();
    }   
    else{
      //继续使用旧的值
    }
     }
   ?>

2).WEB表单生成隐藏输入域的函数:

 <?php
       function gen_input() {
            gen_stoken();
            echo “<input type=\”hidden\” name=\”" . FTOKEN_NAME . “\”
                 value=\”" . $_SESSION[STOKEN_NAME] . “\”> “;
       }
     ?>

3).WEB表单结构:

<?php
       session_start();
       include(”functions.php”);
  ?>
  <form method=”POST” action=”transfer.php”>
       <input type=”text” name=”toBankId”>
       <input type=”text” name=”money”>
       <? gen_input(); ?>
       <input type=”submit” name=”submit” value=”Submit”>
  </FORM>

4).服务端核对令牌:

客户端验证

进行前端语言js进行二次确认验证。
参考链接
https://www.cnblogs.com/-qing-/p/11015075.html

Guess you like

Origin www.cnblogs.com/wangtanzhi/p/12242868.html