jinja2 template and CSRF of Django template

2, Django uses the jinja2 template

2.1 jinja2 introduction

Jinja2: it is the next widely used template engine in Python. It is a template language implemented by python. Its design idea comes from Django's template engine and extends its syntax and a series of powerful functions, especially the built-in template language in Flask framework

Because Django's default template engine is not fully functional and slow, we can also use jinja2 in Django. Jinja2 claims to be 10-20 times faster than Django's default template engine.

Django's mainstream third-party apps basically support Django's default template and jinja2 at the same time, so there won't be many obstacles to using jinja2.

[jinja2 template has no multiline comments]

2.2 installing jinja2 modules

    pip install jinja2

2.3 Django configuration

  1. Create jinja2 in the project file_ env. Py file
from jinja2 import Environment

def environment(**options):
    env = Environment(**options)

    return env

2. In settings Py file

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',#Amendment 1
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS':True,
        'OPTIONS':{
            'environment': 'jinja2_env.environment',# Revision 2
            'context_processors':[
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

2.4 most jinja2 templates are the same as Django's own templates

2.5 jinja2 custom filters

Django documentation: https://docs.djangoproject.com/en/1.11/topics/templates/#module-django.template.backends.django

In jinja2_ env. Custom filter in py file

from jinja2 import Environment

def environment(**options):
    env = Environment(**options)

    # 2. Add a custom filter to the environment
    env.filters['do_listreverse'] = do_listreverse

    return env

# 1. Custom filter
def do_listreverse(li):
    if li == "B":
        return "ha-ha"

3, CSRF

  • CSRF is spelled as Cross Site Request Forgery and translated as cross site request forgery.
  • CSRF means that an attacker embezzles your identity and sends malicious requests in your name.
    • Including: sending emails, sending messages, stealing your account, even buying goods, virtual currency transfer
  • Problems: personal privacy disclosure and property security.

3.1 schematic diagram of CSRF attack

  • The client does not perform security verification with the server when accessing the server

3.2 preventing CSRF attacks

step

  1. When the client requests interface data from the back-end, the back-end will set CSRF in the cookie in the response_ Value of token
  2. Add a hidden field in the Form, and the value is also csrf_token
  3. When the user clicks submit, it will bring these two values to make a request to the background
  4. The backend receives the request to the following events:
    • Remove CSRF from cookie_ token
    • Remove the hidden CSRF from the form data_ Value of token
    • Compare
  5. If the two values are the same after comparison, it means that it is a normal request. If it is not obtained or the comparison is different, it means that it is not a normal request and the next operation is not performed

3.3 code demonstration

WebA without csrf verification

  • Backend code implementation
#Define route
from django.conf.urls  import url
from pay import views
urlpatterns = [
    url(r'^$',views.LoginView.as_view(),name='index'),   #Login routing 
    url(r'^transfer/$',views.TransferView.as_view(),name='transfer'), #Transfer route
]

#Define view
class LoginView(View):

    def post(self,request):

        # Get the parameters submitted in the form
        username = request.POST.get("username")
        password = request.POST.get("password")

        if not all([username, password]):
            print('Parameter error')
        else:
            print(username, password)
            if username == 'laowang' and password == '1234':
                # The status is maintained. Setting the user name into the cookie indicates successful login
                response = redirect(reverse('transfer'))
                response.set_cookie('username', username)
                return response
            else:
                print('Password error')
        return render(request,'login.html')
    def get(self,request):
        return render(request,'login.html')

class TransferView(View):


    def post(self,request):
        # Get user name from cookie
        username = request.COOKIES.get('username', None)
        # If you don't get it, it means you don't log in
        if not username:
            return redirect(reverse('index'))


        to_account = request.POST.get("to_account")
        money = request.POST.get("money")

        print('Pretend to perform transfer operation and transfer the money of the currently logged in user to the specified account')
        return HttpResponse('transfer accounts %s Yuan Dao %s success' % (money, to_account))

    def get(self, request):
        # Render conversion page
        response = render(request, 'transfer.html')

        return response
  • Front end login page code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sign in</title>
</head>
<body>

<h1>I'm a website A,Login page</h1>

<form method="post">
    <label>user name:</label><input type="text" name="username" placeholder="enter one user name"><br/>
    <label>password:</label><input type="password" name="password" placeholder="Please input a password"><br/>
    <input type="submit" value="Sign in">
</form>

</body>
</html>
  • Front end transfer page code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>transfer accounts</title>
</head>
<body>
<h1>I'm a website A,Transfer page</h1>

<form method="post">
    <label>Account:</label><input type="text" name="to_account" placeholder="Please enter the account to transfer"><br/>
    <label>amount of money:</label><input type="number" name="money" placeholder="Please enter the transfer amount"><br/>
    <input type="submit" value="transfer accounts">
</form>

</body>
</html>

Run the test. If you cannot directly enter the transfer page without logging in, the test transfer is successful

Code to attack website B

  • Backend code implementation
#Define route
from django.conf.urls import url
from ads import views

urlpatterns = [
    url(r'^$',views.AdsView.as_view()),
]

#Define view
class AdsView(View):

    def get(self,request):

        return render(request,'index.html')
  • Front end code implementation
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>I'm a website B</h1>

<form method="post" action="http://127.0.0.1:9000/transfer/">
    <input type="hidden" name="to_account" value="hacker">
    <input type="hidden" name="money" value="190000" hidden>
    <input type="submit" value="Click to receive the coupon">
</form>

</body>
</html>

Run the test. When the user logs in to website A, click the button of website B to realize forged access

3.4 implement CSRF in website A_ Token verification process

  • Import generated csrf_token function
 from django.middleware.csrf import get_token
 csrf_token = get_token(request)
  • In rendering the transfer page, do the following:

    1. Generate CSRF_ Value of token
    2. Set CSRF in the response returned to the transfer page_ Token into cookie
    3. CSRF_ The token is saved in the hidden field of the form
     def get(self, request):
            # Generate csrf_token
            from django.middleware.csrf import get_token
            csrf_token = get_token(request)
    
            # Render conversion page, pass in csrf_token into template
            response = render(request, 'transfer.html',context={'csrf_token':csrf_token})
    
            # Set CSRF_ The token is stored in the cookie for submitting verification
            response.set_cookie('csrf_token', csrf_token)
    
            return response
    
  • Add CSRF to the transfer template form_ Token hidden field

<head>
    <meta charset="UTF-8">
    <title>transfer accounts</title>
</head>
<body>
<h1>I'm a website A,Transfer page</h1>

<form method="post">
    <input type="hidden" name="csrftoken" value="{{ csrf_token }}">
    <label>Account:</label><input type="text" name="to_account" placeholder="Please enter opposite account"><br/>
    <label>amount of money:</label><input type="number" name="money" placeholder="Please enter the transfer amount"><br/>
    <input type="submit" value="transfer accounts">
</form>

</body>
</html>

Run the test. After entering the transfer page, view the cookie and html source code

  • Perform CSRF before executing the transfer logic_ Verification of token
 # Remove the CSRF from the form_ token
 form_csrf_token = request.POST.get("csrftoken")
 # Remove the CSRF from the cookie_ token
 cookie_csrf_token = request.COOKIES.get('csrf_token')
 # Compare
 if cookie_csrf_token != form_csrf_token:
     return HttpResponse('token Verification failed. It may be an illegal operation')

After running the test, the user has no problem operating directly on website A, and then goes to website B for operation. It is found that the transfer is unsuccessful because website B cannot obtain the CSRF in the form_ The hidden field of token, and the browser has the same origin strategy. Website B cannot obtain the cookie of website A, so the problem of Cross Site Request Forgery is solved

3.5 solve CSRF attack in Django project

Django turns on CSRF by default

Set CSRF token in template

{% csrf_token %}
perhaps
<input type="hidden" value="{{ csrf_token }}">

Keywords: Python Django

Added by thinkaboutit on Sat, 22 Jan 2022 21:29:27 +0200