CSRF防御及模拟CSRF攻击
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种攻击方式,攻击者可以诱使用户在已登录的应用中执行非本意的操作。为了防御这种攻击,许多Web应用会使用CSRF Token来验证请求的合法性。
0.csrf 攻击原理
2. 后端服务app.js 使用nodemon插件启动服务需全局安装nodemon app.js
const Koa = require('koa'); const Router = require('koa-router'); const bodyParser = require('koa-bodyparser'); // 用于解析请求体 // const cookies = require('koa-cookies'); const app = new Koa(); const router = new Router(); // 使用中间件解析请求体 app.use(bodyParser()); var listLog = [] let username = '' router.get('/login', (ctx, next) => { // 获取 url let url = ctx.url; // 从上下文中获取get请求参数 // 获取GET请求参数 const queryParams = ctx.query; console.log(`GET请求参数: ${JSON.stringify(queryParams)}`) console.log(queryParams.username) if (queryParams.username == 'admin') { username = 'admin' ctx.cookies.set('myCookie', queryParams.username, { maxAge: 1000 * 60 * 60, // 1小时过期 httpOnly: true, // 仅在http请求中可用,不允许js访问 overwrite: true, // 覆盖已有的cookie SameSite: "strict" //更严格的安全模式,cookie永远不会附带于跨站点的请求上,即使是在顶级导航的情况下也不会发送cookie }); } // next() }); router.get('/getMsg', (ctx, next) => { ctx.body = { data: listLog }; }); router.post('/setMsg', async (ctx) => { console.log(ctx.request) const queryParams = ctx.request.body.msg; // 获取请求体 // 处理body中的数据... listLog.push({ msg: queryParams, username: username || '匿名用户' }) ctx.body = { data: listLog }; }) router.get('/setMsg', (ctx, next) => { const queryParams = ctx.query.msg; listLog.push({ msg: queryParams, username: username || '匿名用户' }) ctx.body = { data: listLog }; }); router.get('/clearmsg', (ctx, next) => { listLog = [] ctx.body = { data: listLog }; }); app.use(router.routes()); // 匹配路由并调用相应的处理函数 app.use(router.allowedMethods()); app.listen(9000); console.log('Server is running on port 9000');
3. 前端服务
登录清空评论
添加评论
export default { name: "HelloWorld", data() { return { msg: "", from: { username: "admin", password: "123", }, tableData: [], }; }, mounted() { this.getmsg(); }, methods: { login() { this.$axios .get("/app/login", { params: { ...this.from } }) .then((res) => { console.log(res.data.data); }); }, getmsg() { this.$axios.get("/app/getMsg", {}).then((res) => { this.tableData = res.data.data; console.log(res.data.data); }); }, setmsg() { /* this.$axios .get("/app/setMsg", { params: { msg: this.msg } }) .then((res) => { this.msg = ""; console.log(res.data.data); this.getmsg(); }); */ this.$axios.post("/app/setMsg", { msg: this.msg }).then((res) => { this.msg = ""; console.log(res.data.data); this.getmsg(); }); }, clearmsg() { this.$axios.get("/app/clearmsg", {}).then(() => { this.getmsg(); }); }, }, }; h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; }
4. csrf跨站攻击脚本
csrf demo hello,这里什么也没有。 document.write(` 来自CSRF攻击! ` ); var iframe = document.createElement('iframe'); iframe.name = 'csrf'; iframe.style.display = 'none'; document.body.appendChild(iframe); setTimeout(function () { document.querySelector('[name=commentForm]').submit(); }, 1000);
5.攻击详情部署
1:首先不登录的情况添加评论1,刷新前端页面。
2:点击登录按钮添加评论123,刷新前端页面。
3:打开csrf跨站攻击脚本页面,刷新前端页面。
6.防御csrf攻击方式
1.CSRF Token
CSRF Token(跨站请求伪造令牌)并不是指登录成功后返回的用于身份验证的token,尽管它们可能看起来相似并且都涉及到了“token”这个词,但它们有着不同的目的和机制。
登录返回的Token(Session Token 或 Access Token)
当你登录到一个网站或应用时,服务器可能会生成一个token,通常是session token或者access token,然后返回给客户端。这个token会存储在客户端(比如浏览器的cookie中),并在后续的每个请求中附带,以便服务器可以验证请求的来源。这个token的作用是证明用户已经通过了身份验证,是用户与服务器之间会话状态的一部分。
CSRF Token
CSRF Token则是为了防止跨站请求伪造攻击而设计的。在CSRF攻击中,攻击者试图诱使已登录的用户在不知情的情况下执行恶意操作,例如转账或改变账户设置。CSRF Token是一种额外的安全措施,用来确认发起请求的页面是可信任的源。
CSRF Token的机制是这样的:
- 用户登录后,服务器会生成一个随机的CSRF Token,并将其存储在服务器端,同时也会将这个Token以某种形式(如隐藏的表单字段、HTTP header或cookie)发送给客户端。
- 当客户端发起敏感请求时,必须包含这个CSRF Token。
- 服务器接收到请求后,会验证请求中的CSRF Token是否与服务器上存储的Token相匹配。如果不匹配,则拒绝请求。
因为CSRF Token是在用户登录后由服务器独立生成的,且每个会话或每个请求都可能是不同的,所以即使攻击者能够控制用户点击链接或按钮,他们也无法预测或复制正确的CSRF Token,因此无法成功伪造请求。
总之,登录返回的token主要用于身份验证和授权,而CSRF Token则专门用于保护应用程序免受跨站请求伪造攻击。两者虽然都是token,但在功能和使用场景上是不同的。
2.登录验证码或者是token