xss攻击
情景引入:
在一篇博客的评论中,有人提交了这样的评论:
<script>
alert('sb');
<script>
评论会被保存在数据库中,当其他用户访问这个页面时,会自动跳出弹窗sb。这就是xss攻击(跨站脚本攻击)。
如果没有防范,这种方式可以获取客户端cookie,然后以你的身份进行其他恶意操作。
示例
- 用comment.html表示用户提交评论的页面
- cmt_list.html表示展示评论内容的页面
- views.py中,用一个列表msg模拟评论的数据
- 每当收到comment.html表单中的内容时,就将内容添加到msg中
- 然后在cmt_list.html页面中展示出来
代码如下:
# comment.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>comment</title>
</head>
<body>
<form action="/comment/" method="post">
{% csrf_token %}
<input type="text" name="comment"><input type="submit">
</form>
</body>
</html>
# cmt_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>评论列表</title>
</head>
<body>
<h1>评论:</h1>
{% for comment in msg %}
<li>{{ comment }}</li>
{% endfor %}
</body>
</html>
# views.py
from django.shortcuts import render
msg = []
def comment(request):
if request.method == 'POST':
v = request.POST.get('comment')
msg.append(v)
return render(request, 'comment.html')
def cmt_list(request):
return render(request, 'cmt_list.html', {'msg': msg})
此时,如果在评论中输入攻击性代码:
<script>alert('You are SB');</script>
页面会如实显示:
这是因为Django中默认已经做了防止xss攻击的处理。
如果将cmt_list.html中加上’|safe’,就表示数据是安全的,将会以弹窗形式展现出来。
<body>
<h1>评论:</h1>
{% for comment in msg %}
<li>{{ comment|safe }}</li>
{% endfor %}
</body>
结果如下:
除了在模板中用管道符+safe标记外,还可以在后台,使用Django的mark_safe()函数来将标签标记为安全的,代码如下:
def test(request):
temp = '<a href="https://www.baidu.com">百度</a>'
from django.utils.safestring import mark_safe
safe_temp = mark_safe(temp)
render(request, 'test.html', {'temp': safe_temp})
CSRF
情景引入
1、一家初创的金融公司,网页上转账功能采用的是get请求。
攻击者使用美女图片,图片代码如下为<a href="http://www.jinrong.com/?to=6225760000008888&money=20000">美女点我</a>
。
如果小白用户登录成功该金融网站,同时点击了美女,那么2w元就被转账走了。
2、如果该金融公司采用POST形式传递参数。攻击者采用两个display:none的input框,将自己卡号和金额作为值,引诱小白用户点击。
<form action="http://www.jinrong.com/" method="post">
<input type="text" value="6225760000008888" name="to" style="display: none">
<input type="text" value="20000" name="money" style="display: none">
<a onclick="fun">美女点我</a>
</form>
3、该金融公司在正常转账的表单中,增加一个随机字符串。这个随机字符串是在登录成功后服务端发送给客户端的。
如果攻击者提交的POST请求没有这个随机字符串,或者随机字符串与开始的随机字符串不匹配,就不能骗到钱。
Django中默认做了csrf的处理,在settings中:
此时,为了避免出现403 forbidden的报错,就需要在Form表单处添加{% csrf_token %}
。
<form action="/csrf.html">
{% csrf_token %}
<input type="text" id="user" name="user">
<input type="submit" value="提交">
</form>
CSRF,有时又叫XSRF,跨站请求伪造。正常的POST请求之前一般都是GET请求,在这个GET请求时客户端获取到随机字符串,在POST提交时将这个字符串一起提交。
Ajax方式提交CSRF
方式1:
利用jquery获取到csrf和user的值,将其放入data中提交:
<form action="/csrf.html">
{% csrf_token %}
<input type="text" id="user" name="user">
<input type="submit" value="提交">
<a href="" onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-3.4.1.js"></script>
<script>
function submitForm() {
var csrf = $('input[name="csrfmiddlewaretoken"]').val();
var user = $('#user').val();
$.ajax({
url: '/csrf.html',
type: 'POST',
data: {"user": user, "csrfmiddlewaretoken": csrf},
success: function (arg) {
console.log(arg);
}
})
}
</script>
方式2:
新加入插件jquery.cookie.js,从cookie中获取到csrftoken。
将token放入请求头中,固定名称X-CSRFToken headers: {'X-CSRFToken': token},
<form action="/csrf.html">
{% csrf_token %}
<input type="text" id="user" name="user">
<input type="submit" value="提交">
<a href="" onclick="submitForm();">Ajax提交</a>
</form>
<script src="/static/jquery-3.4.1.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
function submitForm() {
var token = $.cookie('csrftoken');
var user = $('#user').val();
$.ajax({
url: '/csrf.html',
type: 'POST',
headers: {'X-CSRFToken': token},
data: {"user": user},
success: function (arg) {
console.log(arg);
}
})
}
</script>