freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CRSF、JSONP劫持、CORS配置不当中的cookie跨域问题
2024-03-15 20:09:18

前言

最近在挖SRC时遇到了JOSNP和CORS,但是进行JSONP劫持和CORS跨域请求的尝试却失败了,后来经过研究发现根本原因是cookie跨域的限制造成了,遂有了这篇文章。

关于cookie跨域的分析

影响cookie跨域的samesite和secure

2016年开始,Chrome 51版本对Cookie新增了一个 SameSite属性,为了防止CSRF攻击,陆续的各大厂商的浏览器也都适配了该属性,该属性限制了在不同情况下cookie的跨域。而Secure则是规定了cookie是否可以在http下传输,如果Secure为true,则仅在使用https时才会携带cookie。

  • 下图为不同SameSite设置的效果,当然也可以不设置SameSite,大多数浏览器在不设置SameSite时默认为Lax

img

指的一提的是,一般情况下如果设置SameSite为None,也要同时设置Secure,否则一些浏览器可能会拒绝仅有SameSite=None的设置。

img

在不同浏览器上的实验

上面的描述只是标准,具体的效果还要依赖于浏览器的实现,这里进行一波实验来验证一下上述和标准和各个浏览器的实现。

先使用小皮面板创建两个站点,test1.com和test2.com,test1.com注意设置为https访问。

img

img

在test1.com上部署一个设置cooke的前端页面test1.com/cookieSetting.html和一个后端处理脚本test1.com/getCookie.php,还有一个测试cookie是否携带的页面test1.com/json.php,如果携带cookie就会返回账户密码,否则返回error。

  • test1.com/cookieSetting.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Cookie 设置与清除</title>
</head>
<body>

<h2>Cookie 设置与清除表单</h2>

<form action="./getCookie.php" method="post" id="cookieForm">

   <label for="samesite">SameSite:</label>
   <select id="samesite" name="samesite">
       <option value="Strict">Strict</option>
       <option value="Lax">Lax</option>
       <option value="None">None</option>
       <option value=" ">不设置</option>
   </select>
   </br>
   <label for="httponly">HttpOnly:</label>
   <input type="checkbox" id="httponly" name="httponly">

   <label for="secure">Secure:</label>
   <input type="checkbox" id="secure" name="secure">
   </br>
   <select id="setcookie" name="setcookie">
       <option value="set">设置cookie</option>
       <option value="">清除cookie</option>
   </select>
   </br>
   <button type="submit">确认</button>
</form>


</body>
</html>
  • test1.com/getCookie.php

<?php
$simesite=$_POST["samesite"];
$httponly=$_POST["httponly"];
$secure=$_POST["secure"];
$set=$_POST["setcookie"];

// 检查是否存在名为 "secret" 的Cookie
if ($set==="") {
    // 如果存在,则清除Cookie
    setcookie('secret', '', time() - 3600); // 将过期时间设置为过去的时间
    echo 'Cookie已清除';
} else {
    // 如果不存在,则设置Cookie为 "secret=666666"
    // 启用HTTPS时设置Secure标志
    $secureFlag = true;
    // 设置Cookie
    setcookie('secret', '666666', [
        'expires' => time() + 3600, // 0表示会话结束时过期
        'path' => '/',   // 可在整个域名下访问
        'domain' => '',  // 通过任何子域名都可以访问
        'secure' => $secure,  // 根据是否使用HTTPS动态设置Secure标志
        'httponly' => $httponly,  // 仅通过HTTP协议访问,防止JavaScript访问
        'samesite' => $simesite,  // 允许在跨站请求中发送Cookie
    ]);
    echo 'Cookie已设置';
}
?>
  • test1.com/json.php

<?php

if(isset($_COOKIE['secret']) && $_COOKIE['secret'] == '666666') {
   header("Content-Type: text/json");
   echo "hack({\"username\":\"admin\",\"password\":\"123456\"})";
} else {
    echo 'error';
}

?>

在test2.com则部署一个跨域测试的html页面crossSite.html,来测试各种跨域的cookie携带情况

  • test2.com/crossSite.html

<a href="https://test1.com/json.php?a">link to test1.com/json.com</a>
</br>
<button onclick="window.open('https://test1.com/json.php?windowOpen')">window.open("https://test1.com/json.php")</button>
</br>
<button onclick="window.location.href = 'https://test1.com/json.php?windowLocation'">window.location.href = 'https://test1.com/json.php'</button>
<form action="https://test1.com/json.php" method="get">
<input name="get" type="text hidden" value="get"/>
<button type="submit">form get</button>
</form>
<form action="https://test1.com/json.php" method="post">
<input name="post" type="text hidden" value="post"/>
<button type="submit">form post</button>
</form>
<iframe  src="https://test1.com/json.php?iframe"></iframe>
<script  src="https://test1.com/json.php?script"></script>
<link rel="stylesheet" href="https://test1.com/json.php?stylesheet">
<script>
fetch('https://test1.com/json.php?fetch', {
 method: 'GET',  // 或 'POST',根据实际需求选择
 credentials: 'include'  // 允许携带 Cookie
})
 .then(response => response.json())
 .then(data => console.log(data))
 .catch(error => console.error('Error:', error));
</script>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://test1.com/json.php?ajax', true);
xhr.withCredentials = true;  // 允许携带 Cookie

xhr.onreadystatechange = function() {
 if (xhr.readyState === XMLHttpRequest.DONE) {
   if (xhr.status === 200) {
     var data = JSON.parse(xhr.responseText);
     console.log(data);
   } else {
     console.error('Error:', xhr.status);
   }
 }
};

xhr.send();
</script>
<link rel="prefetch" href="https://test1.com/json.php?prefetch">

测试步骤很简单,先通过test1.com/cookieSetting.html设置不同属性的cookie,然后通过test2.com/crossSite.html进行跨域访问,检查其cookie携带情况即可,这里大量图片就省略了,我直接给出我的测试结果。

浏览器samesite=stricksamesite=laxsamesite=none secure=falsesamesite=none secure=true不设置samesite也不设置secure
firefox浏览器 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0全部不携带cookie与标准有一处不同,<form method=post>携带cookie设置成功,全部携带cookie与samesite=none secure=false相同此时secure=false,而samesite=none。全部携带cookie。
edge浏览器 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0全部不携带cookie与之前的总结完全相同,在对<form method=post>的处理上,与firefox不同edge拒绝这样设置cookie全部携带cookie此时secure和samesite都没有显示值。经过测试,本文第一张图中的跨站定级跳转全部携带cookie,其他不携带,post值得注意
chrome浏览器 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36与edge一致与edge一致与edge一致与edge一致与edge一致

关于CSRF、JSONP和CORS的cookie跨域

经过上面的分析,在什么时候可以进行跨域其实已经很明了了

  • CSRF使用get和input进行跨域,当使用get进行跨域时,除了SameSite=strick的情况,都可以携带cookie;当使用post进行跨域时,按照标准,只有SameSite=None和Secure被设置时才能携带cookie。但是由于很多浏览器的实现不标准或者对于不设置SameSite的处理较为模糊,有时不设置SameSite或设置SameSite=None而不设置Secure时允许input跨域携带cookie,这要视浏览器的实现而定。

  • JSONP劫持依赖<script src>访问敏感信息,如果希望<script src>携带cookie,只有SameSite=None的时候才可以

  • CORS配置不当,对于CORS的设置就不多说了,在Access-Control-Allow-Credentials为true的前提下,由于CORS的跨域依赖的是ajax和fetch,要在这种情况下携带cookie进行跨域,同样也只有SameSite=None的时候才可以

# 漏洞 # web安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录