跨站请求伪造和csrf_token使用

Posted zh-xiaoyuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跨站请求伪造和csrf_token使用相关的知识,希望对你有一定的参考价值。

之前我们在写项目时会把下面项目setting.py中的 这一句注释掉:

 django.middleware.csrf.CsrfViewMiddleware,

如果不注释这一句我们在输入正确用户名和密码的情况下进行如下POST请求时会出错:

技术图片

  浏览器会禁止我们提交,这里就涉及到CSRF

什么是CSRF ?
        跨站请求伪造,
     
        
    问题:
        1. 钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的?)
            钓鱼网站的页面是由 钓鱼网站的服务端给你返回的
            
            正经网站的网页是由 正经网站的服务端给你返回的     
            

当注释掉那一句:

技术图片

  遇到钓鱼网站时会出现下面的情况:

技术图片

   其中正经的网站的html

<h1>正经的网站</h1>
<form action="/transfer/" method="post"><p>
        转出:
        <input type="text" name="from">
    </p>

    <p>
        转入:
        <input type="text" name="to">
    </p>
    <p>
        金额:
        <input type="text" name="money">
    </p>
    <p>
        <input type="submit" value="转账">
    </p>
</form>

钓鱼的网站的html

<h1>钓鱼的网站</h1>
<form action="http://127.0.0.1:8002/transfer/" method="post">
    <p>
        转出:
        <input type="text" name="from">
    </p>

    <p>
        转入:
        <input type="text" name="">
        <input type="text" name="to" style="display: none" value="哪吒">
    </p>
    <p>
        金额:
        <input type="text" name="money">
    </p>
    <p>
        <input type="submit" value="转账">
    </p>
</form>

解决办法:

当正经的网站给你返回一个页面的时候,偷偷的在你form表单中塞一个特殊的字符串,后端会记下这个字符串,当你发POST请求时候,后端会

从你提交的数据里面拿到那个特殊的字符串然后和存的字符串比对一下,如果能比对上就表示你这个请求是来自我这个正经网站的请求,但钓鱼

网站就没有这个特殊的字符串,正经的网站就不会处理这个POST请求。

Django中内置了一个专门处理csrf问题的中间件
     django.middleware.csrf.CsrfViewMiddleware
            
         这个中间件做的事情:
                1. 在render返回页面的时候,在页面中塞了一个隐藏的input标签
                
        用法:
                 我们在页面上 form表单 里面 写上 {% csrf_token %}
                    
                 <input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE">
                
                2. 当你提交POST数据的时候,它帮你做校验,如果校验不通过就拒绝这次请求

正经的网站代码修改如下:

<h1>正经的网站</h1>
<form action="/transfer/" method="post">
      {% csrf_token %}
    <p>
        转出:
        <input type="text" name="from">
    </p>

    <p>
        转入:
        <input type="text" name="to">
    </p>
    <p>
        金额:
        <input type="text" name="money">
    </p>
    <p>
        <input type="submit" value="转账">
    </p>
</form>

然后取消那一句注释:

技术图片

  再次进入正经的网站就会出现:

技术图片

  而且每次刷新的时候value值都不一样

在两个网站上再次进行POST请求时:

技术图片

以上所用相关代码:

技术图片
from django.shortcuts import render, redirect, HttpResponse

# Create your views here.


# def login(request):
#     if request.method == "POST":
#         # 取出数据
#         user = request.POST.get("username")
#         pwd = request.POST.get("pwd")
# 
#         if user == "alex" and pwd =="dsb":
#             return redirect("http://www.luffycity.com")
# 
#     return render(request, "login.html")


# 转账
def transfer(request):
    if request.method == "POST":
        from_ = request.POST.get("from")
        to_ = request.POST.get("to")
        money = request.POST.get("money")

        print("{} 给 {} 转了 {}钱".format(from_, to_, money))
        return HttpResponse("转账成功!")

    return render(request, "transfer.html")
views.py
技术图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>



<h1>正经的网站</h1>
<form action="/transfer/" method="post">
      {% csrf_token %}
    <p>
        转出:
        <input type="text" name="from">
    </p>

    <p>
        转入:
        <input type="text" name="to">
    </p>
    <p>
        金额:
        <input type="text" name="money">
    </p>
    <p>
        <input type="submit" value="转账">
    </p>
</form>
</body>
</html>
正经网站transfer.html
技术图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>钓鱼的网站</h1>
<form action="http://127.0.0.1:8002/transfer/" method="post">
    <p>
        转出:
        <input type="text" name="from">
    </p>

    <p>
        转入:
        <input type="text" name="">
        <input type="text" name="to" style="display: none" value="哪吒">
    </p>
    <p>
        金额:
        <input type="text" name="money">
    </p>
    <p>
        <input type="submit" value="转账">
    </p>
</form>
</body>
</html>
钓鱼网站transfer.html

 

CSRF的攻击与防御

以上是关于跨站请求伪造和csrf_token使用的主要内容,如果未能解决你的问题,请参考以下文章

第十篇:跨站请求伪造csrf

csrf_token(跨站伪造)

Django-csrf跨站请求伪造

Ajax csrf跨站请求伪造

Django框架 之 基于Ajax中csrf跨站请求伪造

ajax解决csrf的跨站请求伪造