CSRF protection (#335)
This commit is contained in:
41
examples/csrf/README.md
Normal file
41
examples/csrf/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# CSRF Example
|
||||
|
||||
This is a small example that demonstrates how the CSRF protection in Microdot
|
||||
works.
|
||||
|
||||
## Running the example
|
||||
|
||||
Start by cloning the repostory or copying the two example files *app.py* and
|
||||
*evil.py* to your computer. The only dependency these examples need to run is `microdot`, so create a virtual environment and run:
|
||||
|
||||
pip install microdot
|
||||
|
||||
You need two terminals. On the first one, run:
|
||||
|
||||
python app.py
|
||||
|
||||
To see the application open *http://localhost:5000* on your web browser. The
|
||||
application allows you to make payments through a web form. Each payment that
|
||||
you make reduces the balance in your account. Type an amount in the form field and press the "Issue Payment" button to see how the balance decreases.
|
||||
|
||||
Leave the application running. On the second terminal run:
|
||||
|
||||
python evil.py
|
||||
|
||||
Open a second browser tab and navigate to *http://localhost:5001*. This
|
||||
application simulates a malicious web site that tries to steal money from your
|
||||
account. It does this by sending a cross-site form submission to the above
|
||||
application.
|
||||
|
||||
The application presents a form that fools you into thinking you can win some
|
||||
money. Clicking the button triggers the cross-site request to the form in the
|
||||
first application, with the payment amount set to $100.
|
||||
|
||||
Because the application has CSRF protection enabled, the cross-site request
|
||||
fails.
|
||||
|
||||
If you want to see how the attack can succeed, open *app.py* in your editor and
|
||||
comment out the line that creates the ``csrf`` object. Restart *app.py* in your
|
||||
first terminal, then go back to the second browser tab and click the
|
||||
"Win $100!" button again. You will now see that the form is submitted
|
||||
successfully and your balance in the first application is decremented by $100.
|
||||
40
examples/csrf/app.py
Normal file
40
examples/csrf/app.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from microdot import Microdot, redirect
|
||||
from microdot.cors import CORS
|
||||
from microdot.csrf import CSRF
|
||||
|
||||
app = Microdot()
|
||||
cors = CORS(app, allowed_origins=['http://localhost:5000'])
|
||||
csrf = CSRF(app, cors)
|
||||
|
||||
balance = 1000
|
||||
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def index(request):
|
||||
global balance
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
balance -= float(request.form['amount'])
|
||||
except ValueError:
|
||||
pass
|
||||
return redirect('/')
|
||||
|
||||
page = f'''<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSRF Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CSRF Example</h1>
|
||||
<p>You have ${balance:.02f}</p>
|
||||
<form method="POST" action="">
|
||||
Pay $<input type="text" name="amount" size="10" />
|
||||
<input type="submit" value="Issue Payment" />
|
||||
</form>
|
||||
</body>
|
||||
</html>'''
|
||||
return page, {'Content-Type': 'text/html'}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
25
examples/csrf/evil.py
Normal file
25
examples/csrf/evil.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from microdot import Microdot
|
||||
|
||||
app = Microdot()
|
||||
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def index(request):
|
||||
page = '''<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSRF Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Evil Site</h1>
|
||||
<form method="POST" action="http://localhost:5000">
|
||||
<input type="hidden" name="amount" value="100" />
|
||||
<input type="submit" value="Win $100!" />
|
||||
</form>
|
||||
</body>
|
||||
</html>'''
|
||||
return page, {'Content-Type': 'text/html'}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(port=5001, debug=True)
|
||||
Reference in New Issue
Block a user