前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSRF 攻击案例

CSRF 攻击案例

作者头像
Jimmy_is_jimmy
发布2023-10-16 20:06:04
2020
发布2023-10-16 20:06:04
举报
文章被收录于专栏:call_me_Rcall_me_R

CSRF 是什么

CSRFHacker 利用用户登录的身份凭证(即伪造),通过在用户不知知情的情况下(即跨过)发送恶意请求和执行未经授权的操作。

CSRFCross-Site Request Forgery,跨站请求伪造。

我们可以试想这么一个例子:

你将私房钱放在了保险箱里面,保险箱只能通过你的拇指指纹才可以打开。某天,你的妻子端来一杯下了安眠药的水给你喝,趁你熟睡的时候,然后通过你的指纹打开了保险箱,取走了为数不多的小金库...

CSRF 攻击.png
CSRF 攻击.png

CSRF 攻击案例

下面,我们来简单演示下 CSRF 攻击,先做点前期准备。

案例的演示环境: macOS Monterey - Apple M1 node version - v14.18.1 Visual Studio Code 及其 Live Server 插件

首先,我们添加个 hostname, 方便测试,当然你可以直接使用 ip 地址测试。

通过 sudo vim /etc/hosts 添加 127.0.0.1 a.example.com 的映射:

hosts添加映射.png
hosts添加映射.png

我们 demo 的场景是 get 接口转账。在登陆的情况下进行转账攻击。

代码语言:javascript
复制
const Koa = require('koa');
const Router = require('koa-router');
const views = require('koa-views');
const path = require('path');
const bodyParser = require('koa-bodyparser');
const session = require('koa-session');

const app = new Koa();
const router = new Router();

app.use(
  views(path.join(__dirname, 'views'), {
    extension: 'ejs'
  })
);

app.use(bodyParser());

// session
app.keys = ['secret'];
app.use(session(app));

router.get('/', async (ctx) => {
  if(ctx.session.user) {
    await ctx.render('index');
  } else {
    ctx.redirect('/login');
  }
  
});

router.get('/login', async (ctx) => {
  await ctx.render('login');
})

router.post('/api/login', async (ctx) => {
  const { username, password } = ctx.request.body;
  if(username === 'jimmy' && password === '123456') {
    ctx.session.user = { username, password };
    ctx.body = {
      message: 'ok'
    }
  } else {
    ctx.body = {
      message: 'error'
    }
  }
})
// use get method to transfer fund
router.get('/api/fund/transfer', async (ctx) => {
  const { account, fund } = ctx.query;
  if(ctx.session.user) {
    ctx.body = {
      message: `Success! Transfer ${fund} to the account ${account}.`
    }
  } else {
    ctx.body = {
      message: 'please login.'
    }
  }
  
})

app.use(router.routes());
app.listen(3000, () => {
  console.log("listening on http://localhost:3000");
})

上面接口 /api/fund/transfer 是使用 get 接口进行转账,当然,我们对登陆的用户才进行操作。当用户没有登陆的时候,会抛出异常。

代码语言:javascript
复制
<!-- index.ejs -->
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSRF - Jimmy - Index</title>
</head>
<body>
  <h3 style="text-align: center;">CSRF</h3>
  <p>Welcome to be here.</p>
  <input placeholder="account number" type="number" id="account" />
  <input placeholder="fund" type="number" id="fund" />
  <button id="transfer">Transfer</button>
  <p id="hint"></p>
  <script>
    let accountDom = document.getElementById('account');
    let fundDom = document.getElementById('fund');
    let transferDom = document.getElementById('transfer');
    let hintDom = document.getElementById('hint');
    transferDom.addEventListener('click', function() {
      const params = {
        account: accountDom.value,
        fund: fundDom.value
      }
      const queryString = Object.keys(params)
        .map(key => encodeURIComponent(key) + "=" + encodeURIComponent(params[key]))
        .join("&"); 
      
      fetch(`/api/fund/transfer?${queryString}`, {
        method: 'GET'
      })
        .then(response => response.json())
        .then(data => {
          hintDom.innerText = data.message;
        })
    })
    // attack -> http://localhost:3000/api/fund/transfer?account=123&fund=100
  </script>
</body>
</html>
csrf_attack_demo.gif
csrf_attack_demo.gif

但是,当用户登陆这个系统之后:

代码语言:javascript
复制
<!-- login.ejs -->
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSRF - Jimmy - Login</title>
</head>
<body>
  <!-- <h3 style="text-align: center;">CSRF</h3> -->
  <div>
    <input type="text" placeholder="username" id="username" />
    <input type="password" placeholder="password" id="password" />
    <button id="submit">Submit</button>
  </div>
  <script>
    let submitBtn = document.getElementById('submit');
    let usernameDom = document.getElementById('username');
    let passwordDom = document.getElementById('password');
    submitBtn.addEventListener('click', function() {
      fetch('/api/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          'username': usernameDom.value,
          'password': passwordDom.value
        })
      }).then((response) => response.json())
        .then((data) => {
          if(data.message === 'ok') {
            window.location.href = '/'
          }
        })
    })
  </script>
</body>
</html>
csrf_attack_login.gif
csrf_attack_login.gif

上图,登陆成功并转账成功。那么我们伪造一个链接,比如:

代码语言:javascript
复制
<a href="http://a.example.com:3000/api/fund/transfer?account=456&fund=10000">领取百万大奖</a>

将其发送到你的邮箱上,然后刚好你登陆了系统,你点击了该链接,那么恭喜你,你中奖了:

transfer_fund.png
transfer_fund.png

不知不觉就向账号 456 转账了 10000 元。

transfer_money.gif
transfer_money.gif

【该图片来源网络,侵删】

CSRF 预防

  • 凭证失真:代码设置凭证的有效期;或者人为操作,在不使用系统时候记得退出系统
  • 关键步骤二次验证:涉及敏感操作,比如金额转账操作,设置密码输入确认等
  • 不允许记住密码:电脑一般不是自己独有,登陆系统的时候,账号密码应该禁止浏览器记住
  • etc.

参考

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CSRF 攻击案例
  • CSRF 预防
  • 参考
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档