Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cookie和CSRF、xss攻击 #34

Open
huangchucai opened this issue Aug 29, 2017 · 0 comments
Open

cookie和CSRF、xss攻击 #34

huangchucai opened this issue Aug 29, 2017 · 0 comments

Comments

@huangchucai
Copy link
Owner

cookie和CSRF、xss攻击

cookie是什么

首先需要明白的是,

  1. cookie是储存在浏览器中的一段字符串,它本身是没有任何危害的,不包含任何可执行的代码。
  2. 储存cookie是浏览器的功能,浏览器的安装目录下会有一个专门存放不同域名下的cookie的文件夹。
  3. 当网页发起http请求的时候,浏览器首先会检查是否有对应域名的cookie,如果有,就会自动添加到request header中,发送给服务器。
  4. cookie的存放有大小限制,不可以超过4kb, 每一个域名下的cookie数量最多是20个

图解cookie的运行机制

我们以百度登录的cookie为例,当我们没有登录前,给www.baidu.com发送http请求,返回的数据

default

当我们登陆后,再访问百度的域名后

default

基本通讯流程: 登录的时候,百度服务器会response header会返回一个不同用户的一个标识符(cookie) => 登录完成后,访问百度的主页的时候,浏览器会自动在request header带上刚刚存放的cookie去请求百度的服务器 => 百度服务器接收到对应的cookie后,返回不同用户的数据给浏览器。

cookie的格式

获取cookie

JS原生的api提供了获取cookie的方法,document.cookie(注意,这个方法只能获取非 HttpOnly 类型的cookie

图片来源网络

打印出的结果是一个字符串类型,因为cookie本身就是存储在浏览器中的字符串。但这个字符串是有格式的,由键值对 key=value构成,键值对之间由一个分号和一个空格隔开。

cookie的参数

  1. expires 解释cookie在什么时间段内有效
  2. domainpath 限制cookie能被那些网站访问
  3. secure 设置cookie只在确保安全的请求中才会发送(https等安全协议)
  4. httpOnly 设置cookie能否通过js来访问,拥有httpOnly的cookie只能被服务器访问,客户端不能访问,可以用来防止XSS脚本攻击

实例操作cookie

静态服务器的搭建

// 安装依赖
mkdir demo-cookie && cd demo-cookie
npm init -y
npm install --save express 
// 监听本机3000端口
const express = require('express')
const app = express()

app.listen(3000, err => {
  if (err) {
    return console.log(err)
  }
  console.log('---- 打开 http://localhost:3000 吧----')
})

设置cookie

// 我们在根目录上面设置cookie
app.get('/', (req, res) => {
  res.cookie('name','hcc')
  res.send(`<h1>hello world!</h1>`)
})
app.get('/user', (req, res) => {
  res.send('<h1>hello world user!</h1>')
})

可以看到响应头response header中有Set Cookie设置了我们刚刚在服务器中写的对应的cookie,通过浏览器的Application 中的cookie我们可以看到已经存放了我们刚刚写的cookie

cookie
cookie

设置多个cookie值

app.get('/', (req, res) => {
  res.cookie('name','hcc')
  res.cookie('name','yx')
  res.cookie('age',24)
  res.send(`<h1>hello world!</h1>`)
})
app.get('/user', (req, res) => {
  res.send('<h1>hello world user!</h1>')
})

我们可以看到response header中会出现多个set cookie,来对应我们在服务器中设置的cookie值

cookie

通过document.cookie获取我们设置的cookie的值,可以看出,重名的cookie会被后一个值覆盖,不同的cookie以分号结尾,中间有一个空格

document.cookie //
"name=yx; age=24"

expires和maxAge、httpOnly

app.get('/', (req, res) => {
  res.cookie('expires','5秒后消失',{
    expires: new Date(Date.now()+5000)
  })
  res.cookie('max-age','timeout',{
    maxAge: 5000
  })
  res.cookie('httpOnly','set',{
    httpOnly:true
  })
  res.cookie('name','yx')
  res.cookie('age',24)
  res.send(`<h1>hello world!</h1>`)
})
app.get('/user', (req, res) => {
  res.send('<h1>hello world user!</h1>')
})

我们分别给不同的cookie设置了时间限制和httpOnly,让我们看看他们在浏览器中的展示

expires maxage

expiresmaxAge上面已经讲述了,是用来设置cookie的有效时间的,maxAge的使用更加的方便和普遍,因为expires的时间限制是格林威治时间,写起来不方便,maxAge是根据你的当前时间+ 设置的时间(毫秒),更加的方便。

下面分别获取5秒前的cookie和5秒后的cookie

// 5秒前
document.cookie  
"expires=10%E7%A7%92%E5%90%8E%E6%B6%88%E5%A4%B1; max-age=timeout; name=yx; age=24"

// 5秒后
document.cookie  
"name=yx; age=24"

细心的同学已经发现了,我们之前设置了httpOnly=set的cookie值,但是通过document.cookie并没有获取到,我们看看浏览器是否已经存放了,下图展示了,浏览器已经存放了我们设置的httpOnly的cookie,并且后面还有一个勾出现,好像就是通过客户端不可以输出查看。

如果服务器在设置cookie的时候,添加了额外的属性httpOnly的话,就是限制了不能通过浏览器获得,这个对于防止攻击很有用。

额外的,当你5秒后刷新浏览器存放的cookie值,我们刚刚设置的时间限制的cookie都会被清除

删除cookie

只需要将对应的name的cookie的时间限制设置为0,就会被浏览器清除

let removeCookie = (name, path, domain) => {
  document.cookie = `${name}=; path=${path}; domain=${domain}; max-age=0`
}

子作用域

首先有一个大的概念,就像继承家产一样,父亲的会给儿子使用,但是儿子的不会给父亲使用。

图片来源网络

当 Cookie 的 domain 为 news.163.com,那么访问 news.163.com 的时候就会带上 Cookie;
当 Cookie 的 domain 为 163.com,那么访问 news.163.com 和 sports.163.com就会带上 Cookie

实例

下面我们设置了一个根域名和一个根域名下面的子路径的请求

app.get('/', (req, res) => {
  res.cookie('httpOnly','set',{
    httpOnly:true
  })
  res.cookie('name','yx')
  res.cookie('age',24)
  res.send(`<h1>hello world!</h1>`)
})
app.get('/user', (req, res) => {
  res.cookie('child','user')
  res.cookie('user','hcc',{
    path: '/user',
    httpOnly: true
  })
  res.send('<h1>hello world user!</h1>')
})

访问根域名下面的cookie存放

default

访问/user下面的cookie存放

user

很清晰的发现,我们在/user下面设置的cookie并不会存放在根域名/下,但是我们在/设置的cookie,会存放在/user下面。

CSRF攻击

CSRF(cross-site request forgery),中文名:跨站请求伪造,也被称为:one click attack/session riding(很形象), 缩写为 CSRF/XSRF,就是你点击一个什么按钮,会触发一定的程序攻击。

CSRF有什么危害

CSRF可以理解为,在你不知情的情况下,攻击者盗用你的身份,恶意的像服务器发送请求。

  1. 以你的名义发送垃圾邮箱
  2. 购买商品
  3. 虚拟货币转账

CSRF的原理

图片来源网络

从图中我们可以看出,一个CSRF攻击需要2个条件

  1. 登录了一个受信任的网站A,并且本地存放了cookie
  2. 在不关闭A的情况下,访问了危险网站B

你也可以自己做的一下要求来防止CSRF攻击,但是楼主是做不到的

  1. 你不能保证你登陆了一个网站后,不再打开一个tab 页面并访问另外的网站。(习惯)
  2. .你不能保证你关闭浏览器后,你本地的cookie 马上过期,你上次的会话已经结束 (服务器)

实例

实例一

银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfe...

危险网站B,它里面有一段HTML的代码如下:

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块。。。

为什么会这样呢?

原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的以GET的方式请求第三方资源(这里的第三方就是指A网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出GET请求,去获取资源http://www.mybank.com/Transfer.php?toBankId=11&money=1000,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作......

实例二:

为了杜绝上面的问题,银行决定改用POST请求完成转账操作。但是钓鱼网站也意识到银行应该不会那么傻逼,也与时俱进,钓鱼网站B的WEB表单如下:

 <html>
  <head>
    <script type="text/javascript">
      function steal()
      {
              iframe = document.frames["steal"];
                  iframe.document.Submit("transfer");
      }
    </script>
  </head>

  <body onload="steal()">
    <iframe name="steal" display="none">
      <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">
        <input type="hidden" name="toBankId" value="11">
        <input type="hidden" name="money" value="1000">
      </form>
    </iframe>
  </body>
</html>

如果用户仍是继续上面的操作,很不幸,结果将会是再次不见1000块......因为这里危险网站B暗地里发送了POST请求到银行!

我们看出来,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制(cookie)虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

CSRF防御

服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数

  1. 验证 HTTP Referer 字段

  2. 在请求地址中添加 token 并验证


参考链接:

CSRF 攻击的应对之道

浅谈�CSRF 攻击方式

聊一聊 cookie

Cookie 在前端中的实践

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant