Fixed CSRF vulnerability, CVE is being issued

This commit is contained in:
supermario
2025-12-03 14:53:18 -05:00
parent 557e242717
commit b9b8335db9
4 changed files with 35 additions and 17 deletions

View File

@@ -92,9 +92,9 @@ function install_py_deps {
python3 -m venv "$VENV_DIR"
"$VENV_DIR/bin/python3" -m pip install --upgrade pip
if [ "$1" == "neuron" ]; then
"$VENV_DIR/bin/python3" -m pip install flask==2.2.5 werkzeug==2.2.2 flask-login==0.6.2 pyserial pymodbus==2.5.3 flask_jwt_extended flask_sqlalchemy python-dotenv
"$VENV_DIR/bin/python3" -m pip install flask==2.2.5 werkzeug==2.2.2 flask-login==0.6.2 pyserial pymodbus==2.5.3 Flask-WTF==1.2.2 flask_jwt_extended flask_sqlalchemy python-dotenv
else
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 flask_jwt_extended flask_sqlalchemy python-dotenv
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 Flask-WTF==1.2.2 flask_jwt_extended flask_sqlalchemy python-dotenv
fi
python3 -m pip install pymodbus==2.5.3
}
@@ -279,7 +279,7 @@ if [ "$1" == "win" ]; then
#Setting up venv
python3 -m venv "$VENV_DIR"
"$VENV_DIR/bin/python3" get-pip3.py
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 flask_jwt_extended flask_sqlalchemy python-dotenv
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 Flask-WTF==1.2.2 flask_jwt_extended flask_sqlalchemy python-dotenv
echo ""
echo "[MATIEC COMPILER]"
@@ -307,7 +307,7 @@ elif [ "$1" == "win_msys2" ]; then
#Setting up venv
python3 -m venv "$VENV_DIR"
"$VENV_DIR/bin/python3" get-pip3.py
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 flask_jwt_extended flask_sqlalchemy python-dotenv
"$VENV_DIR/bin/python3" -m pip install flask==2.3.3 werkzeug==2.3.7 flask-login==0.6.2 pyserial pymodbus==2.5.3 Flask-WTF==1.2.2 flask_jwt_extended flask_sqlalchemy python-dotenv
echo ""
echo "[MATIEC COMPILER]"

View File

@@ -2,3 +2,4 @@ Flask==1.0.2
Flask-Login==0.4.1
pyserial==3.4
pymodbus==2.2.0
Flask-WTF==1.2.2

View File

@@ -129,6 +129,7 @@ login_head = """
login_body = """
<h3 style=\"font-family:'Roboto', sans-serif; font-size:14px; color:#1F1F1F; padding:0px 0px 0px 0px; margin: 0px 0px 40px 0px\"><center>Use your credentials to login</center></h3>
<input type='text' name='username' id='username' placeholder='username'/>
<<<<CSRF_INPUT_HERE>>>>
<input type='password' name='password' id='password' placeholder='password'/>
<br><br><br>
<button>login</button>
@@ -1012,6 +1013,7 @@ add_user_tail = """
<input type='text' id='user_email' name='user_email' placeholder='your@email.com'>
<label for='user_password'><b>Password</b></label>
<input type='password' id='user_password' name='user_password' placeholder='password'>
<<<<CSRF_INPUT_HERE>>>>
<label for='uploadForm'><b>Picture</b></label>
<br>
<br>
@@ -1177,6 +1179,7 @@ settings_tail = """
<br>
<br>
<br>
<<<<CSRF_INPUT_HERE>>>>
<center><input type="submit" value="Save Changes" class="button" style="width: 310px; height: 53px; margin: 0px 20px 0px 20px;"></center>
</form>
</div>
@@ -1420,6 +1423,7 @@ hardware_tail = """</textarea>
</div>
<br>
<br>
<<<<CSRF_INPUT_HERE>>>>
<center><input type="submit" class="button" style="font-weight:bold; width: 310px; height: 53px; margin: 0px 20px 0px 20px;" value="Save changes"><a href="restore_custom_hardware" id="code_restore" class="button" style="display:none; width: 310px; height: 53px; margin: 0px 20px 0px 20px;"><b>Restore Original Code</b></a></center>
<br>
<br>

View File

@@ -26,10 +26,14 @@ from credentials import CertGen
from restapi import app_restapi, restapi_bp, db, register_callback_get, register_callback_post
from dataclasses import dataclass, field
from enum import Enum, auto
from flask_wtf import CSRFProtect
from flask_wtf.csrf import generate_csrf
app = flask.Flask(__name__)
app.secret_key = str(os.urandom(16))
csrf = CSRFProtect(app)
csrf.init_app(app)
login_manager = flask_login.LoginManager()
login_manager.init_app(app)
@@ -601,7 +605,7 @@ def index():
@app.route('/login', methods=['GET', 'POST'])
def login():
if flask.request.method == 'GET':
return pages.login_head + pages.login_body
return (pages.login_head + pages.login_body).replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
username = flask.request.form['username']
password = flask.request.form['password']
@@ -626,9 +630,9 @@ def login():
flask_login.login_user(user)
return flask.redirect(flask.url_for('dashboard'))
else:
return pages.login_head + pages.bad_login_body
return (pages.login_head + pages.bad_login_body).replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
return pages.login_head + pages.bad_login_body
return (pages.login_head + pages.bad_login_body).replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
except Error as e:
print("error connecting to the database" + str(e))
@@ -788,6 +792,7 @@ def programs():
action = "upload-program"
method = "post">
<br>
<<<<CSRF_INPUT_HERE>>>>
<input type="file" name="file" id="file" class="inputfile" accept=".st">
<input type="submit" value="Upload Program" name="submit">
</form>
@@ -802,7 +807,7 @@ def programs():
else:
return_str += 'Error connecting to the database. Make sure that your openplc.db file is not corrupt.'
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/reload-program', methods=['GET', 'POST'])
@@ -902,6 +907,7 @@ def update_program():
action = "update-program-action"
method = "post">
<br>
<<<<CSRF_INPUT_HERE>>>>
<input type="file" name="file" id="file" class="inputfile" accept=".st">
<input type="submit" value="Upload Program" name="submit">
<input type='hidden' name='prog_id' id='prog_id' value='""" + prog_id + """'/>
@@ -914,7 +920,7 @@ def update_program():
</html>"""
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/update-program-action', methods=['GET', 'POST'])
@@ -1024,7 +1030,9 @@ def upload_program():
method = "post"
onsubmit = "return validateForm()">
<label for='prog_name'><b>Name</b></label>
<<<<CSRF_INPUT_HERE>>>>
<input type='text' id='prog_name' name='prog_name' placeholder='My Program v1.0'>
<label for='prog_descr'><b>Description</b></label>
<textarea type='text' rows='10' style='resize:vertical' id='prog_descr' name='prog_descr' placeholder='Insert the program description here'></textarea>"""
@@ -1035,6 +1043,7 @@ def upload_program():
return_str += """
<br>
<br>
<<<<CSRF_INPUT_HERE>>>>
<center><input type="submit" class="button" style="font-weight:bold; width: 310px; height: 53px; margin: 0px 20px 0px 20px;" value="Upload program"></center>
</form>
</div>
@@ -1056,7 +1065,7 @@ def upload_program():
</script>
</html>"""
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/upload-program-action', methods=['GET', 'POST'])
@@ -1237,6 +1246,7 @@ def modbus():
return_str += """
</table>
<br>
<<<<CSRF_INPUT_HERE>>>>
<center><a href="add-modbus-device" class="button" style="width: 310px; height: 53px; margin: 0px 20px 0px 20px;"><b>Add new device</b></a></center>
</div>
</div>
@@ -1250,7 +1260,7 @@ def modbus():
else:
return_str += 'Error connecting to the database. Make sure that your openplc.db file is not corrupt.'
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/add-modbus-device', methods=['GET', 'POST'])
@@ -1291,6 +1301,7 @@ def add_modbus_device():
method = "post"
onsubmit = "return validateForm()">
<label for='dev_name'><b>Device Name</b></label>
<<<<CSRF_INPUT_HERE>>>>
<input type='text' id='dev_name' name='device_name' placeholder='My Device'>
<label for='dev_protocol'><b>Device Type</b></label>
<select id='dev_protocol' name='device_protocol'>
@@ -1323,7 +1334,7 @@ def add_modbus_device():
return_str += pages.add_slave_devices_tail + pages.add_devices_script
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
elif (flask.request.method == 'POST'):
devname = flask.request.form.get('device_name')
@@ -1701,7 +1712,7 @@ def monitoring():
</body>
</html>"""
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/monitor-update', methods=['GET', 'POST'])
def monitor_update():
@@ -1946,7 +1957,7 @@ def hardware():
<p>PSM is a powerful bridge that connects OpenPLC core to Python. You can use PSM to write your own OpenPLC driver in pure Python. See below for a sample driver that switches %IX0.0 every second</p>
<textarea wrap="off" spellcheck="false" name="custom_layer_code" id="custom_layer_code">"""
with open('./core/psm/main.py') as f: return_str += f.read()
return_str += pages.hardware_tail
return_str += pages.hardware_tail.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
else:
hardware_layer = flask.request.form['hardware_layer']
@@ -1957,7 +1968,7 @@ def hardware():
subprocess.call(['./scripts/change_hardware_layer.sh', hardware_layer])
return "<head><meta http-equiv=\"refresh\" content=\"0; URL='compile-program?file=" + current_program + "'\" /></head>"
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
@app.route('/restore_custom_hardware')
@@ -2065,7 +2076,7 @@ def add_user():
<br>
<br>"""
return_str += draw_status() + pages.add_user_tail
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
elif (flask.request.method == 'POST'):
name = flask.request.form['full_name']
@@ -2158,6 +2169,8 @@ def edit_user():
row = cur.fetchone()
cur.close()
conn.close()
csrf_token = generate_csrf()
return_str += "<input type='hidden' value='" + csrf_token + "' name='csrf_token'/>"
return_str += "<input type='hidden' value='" + user_id + "' id='user_id' name='user_id'/>"
return_str += "<label for='full_name'><b>Name</b></label><input type='text' id='full_name' name='full_name' value='" + str(row[1]) + "'>"
return_str += "<label for='user_name'><b>Username</b></label><input type='text' id='user_name' name='user_name' value='" + str(row[2]) + "'>"
@@ -2491,7 +2504,7 @@ def settings():
else:
return_str += "Error opening DB"
return return_str
return return_str.replace('<<<<CSRF_INPUT_HERE>>>>', f"<input type='hidden' value='{generate_csrf()}' name='csrf_token'/>" )
elif (flask.request.method == 'POST'):
modbus_port = flask.request.form.get('modbus_server_port')