Flask Preventing Form Injection - python

How can python / flask block foreign form injections?
Consider the following mwe:
app.py
from flask import Flask, request, render template
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def helloworld():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
print(request.form['info'])
## do something with the info, like write to a database
return 'nothing'
if __name__ == '__main__':
app.run(debug=True)
templates/index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type='text/javascript' src="{{ url_for('static', filename='js/fire.js') }}"></script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
static/js/fire.js
$(document).click(function() {
// post data to flask
$.post('/', {'info': 'test'});
return false;
};
My questions are:
Is injection possible from a foreign website? Follow-up: how could this be done? (e.g., perhaps via a form that posts to my website url?)
If injection is possible, what can I do in the app.py script to block the injection?
Edit
Here is a very basic script that can be used to test injections against the above flask application. The accepted answer blocks this script:
<!DOCTYPE html>
<html>
<body>
<h2>Malicious Form Injection</h2>
<form action='http://127.0.0.1:5000/' method='post'>
Input 1:<br>
<input name="info" value="mal1"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

app.py
from flask import Flask, request, render template
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
CSRFProtect(app)
app.config['SECRET_KEY'] = 'somethignrandom'
#app.route('/', methods=['GET','POST'])
def helloworld():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST': # anything post will autocheck csrf
print(request.form['info'])
## do something with the info, like write to a database
return 'nothing'
if __name__ == '__main__':
app.run(debug=True)
There is no need to pass the secret key to the html template, as CSRFProtect will automatically pass the secret key.
templates/index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<meta name='csrf-token' content="{{ csrf_token() }}">
<script type='text/javascript' src="{{ url_for('static', filename='js/fire.js') }}"></script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
script.js
$(document).click(function() {
// post data to flask
$.post('/', {'info': 'test', '_csrf_token':$('meta[name="csrf-token"]').attr('content')});
return false;
};

Related

405 Method Not Allowed: The method is not allowed for the requested URL

I have been developing a system but I recently have not been able to debug why I get this error
Method Not Allowed
The method is not allowed for the requested URL.
I have been developing a system
I assume the problem has to do with the post function not being allowed and being interrupted by something please assist me thx.
code:
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/')
def student():
return render_template('index.html')
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
result = request.form['name']
print(result)
return "thank you for filling out this form"
if __name__ == '__main__':
app.run(debug = True)
file_object = open('transferfile.txt', 'a+')
name = "Gabriel"
age = "12"
gender = "male"
file_object.write(name)
file_object.write(" ")
data = file_object.read(100)
file_object.write(age)
file_object.write(" ")
file_object.write(gender)
file_object.close()
html
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>venuefast</title>
</head>
<body>
<form class="logo" action="." method="post">fastvenue<br>
<hr>
<input type ="text" name="name" placeholder="name">
<br>
<button type="submit" value="submit">Submit</button>
</form>
</body>
</html>
Since the student function is rendering the form in index.html, it only makes sense that the student function accepts POST requests:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/',methods = ['POST', 'GET'])
def student():
if request.method == 'POST':
name = request.form['name']
return f"thank you for filling out this form {name}!"
return render_template('index.html')
#app.route('/result')
def result():
return 'this function does nothing yet'
if __name__ == '__main__':
app.run(debug = True)
an alternative, if you are planning to use student for something else, you can make result function renders index.html instead and also make it accept POST requests:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/')
def student():
return 'this function does nothing yet'
#app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
name = request.form['name']
return f"thank you for filling out this form {name}!"
return render_template('index.html')
if __name__ == '__main__':
app.run(debug = True)
Try This in the HTML
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>venuefast</title>
</head>
<body>
<form class="logo" action="/result" method="POST">
<p>fastvenue</p>
<br>
<hr>
<input type ="text" name="name" placeholder="name">
<br>
<button type="submit" value="submit">Submit</button>
</form>
</body>
</html>

How to Display Image in Flask after a button is pressed

I am new to flask and web development. I want to display an image on a local web server after I press a button on the webpage. I am using Flask.Ive been trying to figure this out for a while and havent been able too so any help would be incredible.
FLASK CODE:
#app.route('/graph_select')
def graph_select():
return render_template('live_stream.html')
#app.route('/read_ph', methods=["GET"])
def ph_plot():
if request.method == "GET":
all_plots.ph_plot()
return render_template('live_stream.html')
#app.route("/read_temp", methods=["GET"])
def temp_plot():
if request.method == "GET":
all_plots.temperature_plot()
return render_template('live_stream.html')
#app.route('/read_distance', methods=["GET"])
def distance_plot():
if request.method == "GET":
all_plots.distance_plot()
return render_template('live_stream.html')
HTML CODE:
<h1>Data Monitoring Station</h1>
<form method="GET"
<button type="button">Temperature Graph</button>
<button type="button">PH Graph</button>
<button type="button">Distance Graph</button>
</form>
<h3><img src="{{ url_for('static', filename='ph_plot.png') }}" width="30%">$
<h3><img src="{{ url_for('static', filename='temperature_plot.png') }}" width="30%">$
<h3><img src="{{ url_for('static', filename='distance_plot.png') }}" width="30%">$
</body>
</html>
TLDR;
I wrote a minimal example on displaying images on button click using Flask and Ajax.
In essence, I just returned the URL of the image to the HTML page and set the src attribute of <img> tag with the returned URL.
app.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def hello():
return render_template('a.html')
#app.route("/getimage")
def get_img():
return "a.jpg"
if __name__ == '__main__':
app.run()
a.html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<button type='button' id ='retrieve'>Submit</button>
<img src="" id="myimg" />
</body>
<script>
$(document).ready(function() {
$('#retrieve').click(function(){
$.ajax({
url: "{{ url_for ('get_img') }}",
type: "GET",
success: function(response) {
$("#myimg").attr('src', '/static/' + response);
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
</html>
You can modify this code as you wish.
Note: The a.html file should be in templates folder and the a.jpg file should be in the static folder.
Hope this helps. Good luck.

How to pass variables between HTML pages using Flask

I'm new to using Flask and I've just been trying to pass a variable between two web pages. The first is a simple form to accept a number with the second page just displaying what is entered.
HTML for the form page:
<!doctype html>
<html>
<body>
<form action ="{{ url_for('return_form', glon="glon") }}" method="post">
Galactic Longitude: <input type="text" name="glon">
<button type="submit">Submit</button>
</form>
</body>
</html>
HTML for the display page:
<!doctype html>
<body>
<p> {{ glon }} </p>
</body>
</html>
The Flask script currently looks like this:
from flask import Flask
from flask import render_template, url_for, request, redirect
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/form/', methods = ['GET', 'POST'])
def form():
if request.method == 'POST':
glon = request.form['glon']
#glat = request.form['glat']
return redirect(url_for('return_form', glon=glon))
return render_template('form.html')
#app.route('/return_form/<glon>', methods = ['GET', 'POST'])
def return_form(glon):
return render_template('return_form.html', glon=glon)
if __name__ == '__main__':
app.run()
At the moment, the second page just displays "glon" instead of the number passed to the form.
I simply want the variable to display on the second page, and eventually use it in the return_form function.
So i didn't got your approach.Below is what i did,I changed the code a bit. Hope this solves your problem.
main.py
from flask import Flask
from flask import render_template, url_for, request, redirect
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/form', methods = ['GET', 'POST'])
def form():
if request.method == 'POST':
glon = request.form['glon']
return render_template('display.html', glon=glon)
# #app.route('/return_form/<glon>', methods = ['GET', 'POST'])
# def return_form(glon):
# return render_template('return_form.html', glon=glon)
if __name__ == '__main__':
app.run()
index.html
<html>
<body>
<form action ="{{ url_for('form') }}" method="post">
Galactic Longitude: <input type="text" name="glon">
<button type="submit">Submit</button>
</form>
</body>
</html>
display.html
<!doctype html>
<body>
<p> {{ glon }} </p>
</body>
</html>

Method Not Allowed in Flask for IntegerField form

I'm trying to set up integer field validation on a form in Flask, but I keep getting 'Method Not Allowed'. I can't see what is wrong with my routes?
My main file is:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import IntegerField
# from perfect_numbers import classify
app = Flask(__name__)
app.config['SECRET_KEY'] = 'MySecretKey'
# num = 12
# Classify = classify(num)
class PerfectForm(FlaskForm):
number = IntegerField(4)
#app.route('/', methods=['POST'])
def form():
form = PerfectForm()
return render_template('index.html', form = form)
if __name__ == '__main__':
app.run(debug=True)
Then I have a standard layout.html file:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>PERFECT App</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
And my index.html is:
{% extends 'layout.html' %}
{% block body %}
<h1>PERFECT NUMBERS</h1>
<p>This is a basic Flask App to illustrate Aliquot Sums and Perfect Numbers</p>
<p>Input a number to check if it is abundant, perfect, or deficient</p>
<form action="{{ url_for('/') }}" method="POST">
{{ form.csrf_token }}
{{ form.number }}
</form>
<!-- {{ num }} is {{ classify }} -->
{% endblock %}
First, change the app.route() signature to
#app.route('/', methods=['POST', 'GET'])
You have to fill the form and submit for your app to receive a POST request. When you first load the page on your browser, you technically send a GET request to flask, and it returns the page.
To handle your POST request separately, do something like this :
#app.route('/', methods=['POST', 'GET'])
def form():
if request.method == 'POST':
# Do something with request (access form elements with request.get(key))
return 'Somehing here'
form = PerfectForm()
return render_template('index.html', form = form)

werkzeug.routing.BuildError with Flask Python

**difference to the suggested repeat, my error stemmed from the following line being missing in the original code session['message']=request.form['message'] wherease in the suggested duplicate was missing the render_template component`
I am trying to create user sessions with Flask, I don't care about authentication. I just want a page where they enter their name, and then they are redirected to the main page. I tried to follow the example in this link here but I get a werkzeug.routing.BuildError. To summarise my python app is:
from flask import Flask, render_template
from flask import request, session, url_for,abort,redirect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'F34TF$($e34D';
#app.route('/')
def home():
return render_template('index.html')
#app.route('/signup', methods=['POST'])
def signup():
session['username'] = request.form['username']
session['message']=request.form['message']
return redirect(url_for('message'))
#app.route("/message")
def message():
return render_template("message.html")
if __name__ == '__main__':
app.run(debug=True)
and index.html is:
{% extends "layout.html" %}
{% block content %}
<h1>Say something</h1>
<form method="post" action="{{ url_for('signup') }}">
<p><label>Username:</label> <input type="text" name="username" required></p>
<p><button type="submit">Send</button></p>
</form>
{% endblock %}
layout.html is:
<!doctype html>
<html lang="en">
<head>
<title>Say somthing</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
You are getting that error because you don't have a route called message and yet you are redirecting to it.
#app.route('/signup', methods=['POST'])
def signup():
session['username'] = request.form['username']
# Create a message route first
return redirect(url_for('message'))
Here's a sample route called message
#app.route("/message")
def message():
return render_template("message.html")

Categories

Resources