flask imitates csrf attack and protection

flask imitates csrf attack and protection

Schematic diagram of csrf attack:

 

 

Now we have a webA file as follows

login.html

<!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>

transfer.html

<!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 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>

webA.py

from flask import Flask, render_template, make_response
from flask import redirect
from flask import request
from flask import url_for

app = Flask(__name__)


@app.route('/', methods=["POST", "GET"])
def index():
    if request.method == "POST":
        # Get the parameters submitted in the form
        username = request.form.get("username")
        password = request.form.get("password")

        if not all([username, password]):
            print('Parameter error')
        else:
            print(username, password)
            if username == 'laowang' and password == '1234':
                # Maintain the status and set the user name to cookie Indicates successful login
                response = redirect(url_for('transfer'))
                response.set_cookie('username', username)
                return response
            else:
                print('Password error')

    return render_template('login.html')


@app.route('/transfer', methods=["POST", "GET"])
def transfer():
    # from cookie Get user name from
    username = request.cookies.get('username', None)
    # If you don't get it, it means you haven't logged in
    if not username:
        return redirect(url_for('index'))

    if request.method == "POST":
        to_account = request.form.get("to_account")
        money = request.form.get("money")
        print('Pretend to perform the transfer operation and transfer the money of the currently logged in user to the specified account')
        return 'transfer accounts %s Yuan Dao %s success' % (money, to_account)

    # Render conversion page
    response = make_response(render_template('transfer.html'))
    return response

if __name__ == '__main__':
    app.run(debug=True, port=9000)

The webB file is as follows

index.html

<!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="999999">
    <input type="hidden" name="money" value="190000">
    <input type="submit" value="Click to receive coupons">
</form>

</body>
</html>

webB.py

from flask import Flask
from flask import render_template

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


if __name__ == '__main__':
    app.run(debug=True, port=8000)

Now let's start weba Py file enter user name and password

 

 

You can see that the transfer is successful

webA should not turn off Webb that keeps users logged in and then starts malicious attacks py

Click

We can see that we directly asked him to jump to the user's transfer interface and the transfer was successful. What's the secret

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

In fact, website b directly jumps to the transfer interface of website a with the form form action, and then sets the type of the input tag to hidden. When we click the button, he submits the transfer amount and the user to the server (because the default browser will bring his cookie when accessing and inputting the same ip and port as website a)

How to solve this problem? (just change webA)

Step 1:

Use base64 and os to create a random string of 48

def random_csrf_token():
    return bytes.decode(base64.b64encode(os.urandom(48)))

Step 2:

Then, the function will be called and the generated string will be responded, and the generated 48 random number will also be written into the cookie

csrf_token = random_csrf_token()
# Render conversion page
response = make_response(render_template('transfer.html', csrf_token=csrf_token))
response.set_cookie("csrf_token", csrf_token)

Step 3:

Add a hidden tag to the transfer interface to receive the generated 48 bit random number

<input type="hidden" name="csrf_token" value="{{ csrf_token }}">

Step 4:

Finally, check the 48 bit random number obtained from the front-end page and cookie respectively

    if request.method == "POST":
        token1 = request.form.get("csrf_token")
        token2 = request.cookies.get("csrf_token")
        if not token1 == token2:
            return "climb"

Run webB again and you can see that the transfer has been unsuccessful

 

webA finished changing the code

login.html

<!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>

transfer.html

<!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">
    <input type="hidden" name="csrf_token" value="{{ scrf_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>

webA.py

from flask import Flask, render_template, make_response
from flask import redirect
from flask import request
from flask import url_for
import base64
import os

app = Flask(__name__)


def random_csrf_token():
    return bytes.decode(base64.b64encode(os.urandom(48)))


@app.route('/', methods=["POST", "GET"])
def index():
    if request.method == "POST":
        # Get the parameters submitted in the form
        username = request.form.get("username")
        password = request.form.get("password")

        if not all([username, password]):
            print('Parameter error')
        else:
            print(username, password)
            if username == 'laowang' and password == '1234':
                # Maintain the status and set the user name to cookie Indicates successful login
                response = redirect(url_for('transfer'))
                response.set_cookie('username', username)
                return response
            else:
                print('Password error')

    return render_template('login.html')


@app.route('/transfer', methods=["POST", "GET"])
def transfer():
    # from cookie Get user name from
    username = request.cookies.get('username', None)
    # If you don't get it, it means you haven't logged in
    if not username:
        return redirect(url_for('index'))

    if request.method == "POST":
        token1 = request.form.get("csrf_token")
        token2 = request.cookies.get("csrf_token")
        if not token1 == token2:
            return "climb"
        to_account = request.form.get("to_account")
        money = request.form.get("money")
        print('Pretend to perform the transfer operation and transfer the money of the currently logged in user to the specified account')
        return 'transfer accounts %s Yuan Dao %s success' % (money, to_account)
    csrf_token = random_csrf_token()
    # Render conversion page
    response = make_response(render_template('transfer.html', csrf_token=csrf_token))
    response.set_cookie("csrf_token", csrf_token)
    return response


if __name__ == '__main__':
    app.run(debug=True, port=9000)

 

Tags: Flask

Posted by xpherism on Wed, 11 May 2022 07:40:35 +0300