Clickjacking in Flask with Cockroachdb
Clickjacking in Flask with Cockroachdb — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side attack where an attacker tricks a user into interacting with invisible or disguised UI elements. In a Flask application using Cockroachdb as the backend database, the vulnerability arises not from Cockroachdb itself, but from missing HTTP response headers and insecure UI composition that allow malicious sites to embed or overlay content on your pages. When Flask serves HTML pages that render data from Cockroachdb without anti-clickjacking protections, an attacker can embed those pages in an iframe and capture user actions.
Consider a Flask route that queries Cockroachdb for user-specific settings and renders them in a dashboard page:
import psycopg2
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route('/dashboard')
def dashboard():
conn = psycopg2.connect(
host='localhost',
port 26257,
user='app_user',
password='secure_password',
database='app_db'
)
cur = conn.cursor()
cur.execute('SELECT username, email FROM users WHERE id = %s', (current_user_id,))
user_data = cur.fetchone()
cur.close()
conn.close()
return render_template_string('''
<h1>{{ user_data[0] }}'s Dashboard</h1>
<p>Email: {{ user_data[1] }}</p>
<button>Update Settings</button>
''', user_data=user_data)
If this page is served without the X-Frame-Options or Content-Security-Policy headers, an attacker can craft a page that loads /dashboard inside a hidden iframe and overlay interactive elements on top, tricking the user into performing unintended actions such as changing settings or confirming transactions stored in Cockroachdb.
Additionally, if Flask templates dynamically inject data from Cockroachdb into JavaScript or HTML without proper escaping, attackers may combine stored cross-site scripting (XSS) with clickjacking to further manipulate the UI. For example, unsanitized user input used in inline event handlers could enable script execution when combined with frame-based attacks.
The risk is compounded when Cockroachdb stores sensitive operations data that Flask renders in admin panels or configuration screens. An attacker who can trick an authenticated user into clicking a crafted link may silently execute privileged actions, leveraging the trust relationship between the user and the Flask application.
Cockroachdb-Specific Remediation in Flask — concrete code fixes
Remediation focuses on HTTP headers, template safety, and secure data handling in Flask routes that interact with Cockroachdb. Below are concrete code examples demonstrating secure practices.
1. Add anti-clickjacking headers in Flask
Use middleware or route decorators to set security headers. For global protection, register a before_request handler:
from flask import Flask
app = Flask(__name__)
@app.before_request
def set_security_headers():
# Prevent embedding in any frame
response.headers['X-Frame-Options'] = 'DENY'
# Modern alternative: restrict to same-origin only
response.headers['Content-Security-Policy'] = "frame-ancestors 'self'"
2. Secure Cockroachdb connection and parameterized queries
Always use parameterized queries to prevent SQL injection, which could otherwise lead to data exposure that makes clickjacking more impactful:
import psycopg2
from flask import Flask, g
app = Flask(__name__)
def get_db():
if 'db' not in g:
g.db = psycopg2.connect(
host='localhost',
port=26257,
user='app_user',
password='secure_password',
database='app_db'
)
return g.db
@app.route('/user/')
def user_profile(user_id):
db = get_db()
cur = db.cursor()
cur.execute('SELECT username, email FROM users WHERE id = %s', (user_id,))
user = cur.fetchone()
cur.close()
return f'User: {user[0]}, Email: {user[1]}'
3. Escape output in templates
Use Flask's built-in escaping in Jinja2 to prevent injection when rendering Cockroachdb data:
from flask import render_template
@app.route('/profile')
def profile():
user_data = ('Alice', '[email protected]')
return render_template('profile.html', username=user_data[0], email=user_data[1])
In profile.html, ensure variables are not marked safe unless necessary:
<!-- profile.html -->
<h1>{{ username | e }}</h1>
<p>Email: {{ email | e }}</p>
4. Validate and limit frame ancestors for APIs
If your Cockroachdb-backed API serves JSON to web clients, ensure frontend pages include CSP headers to restrict framing:
@app.after_request
def apply_csp(response):
response.headers['Content-Security-Policy'] = "default-src 'self'; frame-ancestors 'none'"
return response
These measures reduce the attack surface when Flask serves data from Cockroachdb, mitigating clickjacking risks by controlling how pages can be embedded and ensuring data integrity.