HIGH cross site request forgeryflaskbearer tokens

Cross Site Request Forgery in Flask with Bearer Tokens

Cross Site Request Forgery in Flask with Bearer Tokens

Cross Site Request Forgery (CSRF) in Flask applications that rely on Bearer Tokens challenges common assumptions about token-based authentication. Bearer Tokens are typically transmitted in HTTP headers, which are not automatically included in browser-initiated requests triggered by third-party sites. However, this does not make CSRF impossible when using Bearer Tokens in Flask. The risk depends on how tokens are stored and whether requests can be forged from the client side. If an application stores a Bearer Token in local storage or session storage and uses JavaScript to attach it to API requests, malicious third-party sites can potentially initiate requests using embedded images, forms, or scripts, leveraging the browser’s automatic inclusion of credentials for the target domain. This is especially relevant when token handling is implemented manually without additional protections. Even with Bearer Tokens, endpoints that accept unsafe methods like POST, PUT, or DELETE without verifying the request origin remain vulnerable when token storage is accessible to malicious scripts. The presence of CORS misconfigurations can further expose these endpoints to unauthorized origins, allowing attackers to craft requests that appear legitimate to the server. For example, an attacker might trick a user’s browser into making a request to /api/transfer with a valid Bearer Token, leading to unauthorized actions. Flask APIs that do not implement anti-CSRF tokens, custom headers, or strict CORS policies expose these attack paths. The use of Bearer Tokens alone does not prevent CSRF; developers must understand how browsers handle credentials and design defenses accordingly. Without proper mitigations, applications risk unauthorized state changes, data manipulation, or privilege escalation through forged requests initiated from malicious sites.

Bearer Tokens-Specific Remediation in Flask

Securing Flask APIs that use Bearer Tokens requires a combination of secure token handling, strict CORS policies, and explicit anti-CSRF measures for browser-based clients. The following practices and code examples demonstrate how to reduce CSRF risk while maintaining token-based authentication.

Secure Token Storage and CORS Configuration

Ensure Bearer Tokens are not stored in locations accessible to JavaScript, such as local storage. Instead, use HttpOnly cookies for token storage when possible, or ensure strict SameSite and Secure flags are applied. Configure CORS to allow only trusted origins and avoid wildcard entries. Below is an example using the flask-cors extension to restrict origins:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
CORS(app, resources={r"/api/*": {"origins": ["https://trusted-frontend.com"]}})

@app.route('/api/transfer', methods=['POST'])
def transfer():
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return {'error': 'Unauthorized'}, 401
    token = auth_header.split(' ')[1]
    # Validate token and process request
    return {'status': 'success'}, 200

Anti-CSRF Protection with Custom Headers

Require a custom header (e.g., X-Requested-With or a custom value) for state-changing requests. Because cross-origin requests initiated by forms or scripts cannot set custom headers without CORS preflight approval, this mitigates CSRF for browsers. Below is an example middleware in Flask:

from flask import request, jsonify

@app.before_request
def verify_csrf_for_state_changing():
    if request.method in ['POST', 'PUT', 'DELETE', 'PATCH']:
        if not request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return jsonify({'error': 'CSRF protection triggered'}), 403

Stateless Token Validation Example

Validate Bearer Tokens on every request using a public key or introspection endpoint. Ensure tokens have appropriate scopes and are bound to the request context. Here is a minimal route demonstrating token validation:

import jwt
from flask import request, jsonify

PUBLIC_KEY = open('public_key.pem').read()

@app.route('/api/secure-data')
def secure_data():
    auth = request.headers.get('Authorization')
    if not auth:
        return {'error': 'Missing token'}, 401
    try:
        token = auth.split(' ')[1]
        payload = jwt.decode(token, PUBLIC_KEY, algorithms=['RS256'], audience='api.example.com')
        # Proceed with request handling using payload['sub']
        return {'data': 'secure', 'user': payload['sub']}, 200
    except jwt.ExpiredSignatureError:
        return {'error': 'Token expired'}, 401
    except jwt.InvalidTokenError:
        return {'error': 'Invalid token'}, 401

Defense in Depth

Combine these techniques with short token lifetimes, strict scope validation, and monitoring for anomalous request patterns. For non-browser clients or high-security operations, consider adding CSRF tokens alongside Bearer Tokens. Regularly review CORS configurations and token usage to ensure alignment with current security practices.

Frequently Asked Questions

Can CSRF occur when using Bearer Tokens in mobile or native apps?
CSRF is primarily a browser-based threat. Native or mobile apps that do not rely on shared browser session storage are not vulnerable in the same way, but they should still use secure token storage and network-level protections.
Does middleBrick detect CSRF vulnerabilities during API scans?
Yes, middleBrick includes CSRF-related checks among its 12 security checks. It evaluates authentication mechanisms, CORS settings, and state-changing request handling to identify potential CSRF risks and provides remediation guidance.