Use hmac.compare_digest to prevent timing attacks.

main
Dimitri Huisman 2 years ago committed by Alexander Graf
parent 5c9cdfe1de
commit 7a36f6bbb9
No known key found for this signature in database
GPG Key ID: B8A9DC143E075629

@ -2,6 +2,7 @@ from .. import models, utils
from . import v1 from . import v1
from flask import request from flask import request
import flask import flask
import hmac
from functools import wraps from functools import wraps
from flask_restx import abort from flask_restx import abort
@ -19,10 +20,13 @@ def api_token_authorization(func):
client_ip = flask.request.headers.get('X-Real-IP', flask.request.remote_addr) client_ip = flask.request.headers.get('X-Real-IP', flask.request.remote_addr)
if utils.limiter.should_rate_limit_ip(client_ip): if utils.limiter.should_rate_limit_ip(client_ip):
abort(429, 'Too many attempts from your IP (rate-limit)' ) abort(429, 'Too many attempts from your IP (rate-limit)' )
if request.args.get('api_token') != v1.api_token: if (request.args.get('api_token') == '' or
request.args.get('api_token') == None):
abort(401, 'A valid API token is expected as query string parameter')
if not hmac.compare_digest(request.args.get('api_token'), v1.api_token):
utils.limiter.rate_limit_ip(client_ip) utils.limiter.rate_limit_ip(client_ip)
flask.current_app.logger.warn(f'Invalid API token provided by {client_ip}.') flask.current_app.logger.warn(f'Invalid API token provided by {client_ip}.')
abort(401, 'A valid API token is expected as query string parameter') abort(403, 'A valid API token is expected as query string parameter')
else: else:
flask.current_app.logger.info(f'Valid API token provided by {client_ip}.') flask.current_app.logger.info(f'Valid API token provided by {client_ip}.')
return func(*args, **kwds) return func(*args, **kwds)

@ -7,19 +7,18 @@ db = models.db
alias = api.namespace('alias', description='Alias operations') alias = api.namespace('alias', description='Alias operations')
alias_fields = api.model('Alias', { alias_fields_update = alias.model('AliasUpdate', {
'email': fields.String(description='the alias email address', example='user@example.com', required=True),
'comment': fields.String(description='a comment'),
'destination': fields.List(fields.String(description='alias email address', example='user@example.com', required=True)),
'wildcard': fields.Boolean(description='enable SQL Like wildcard syntax')
})
alias_fields_update = api.model('AliasUpdate', {
'comment': fields.String(description='a comment'), 'comment': fields.String(description='a comment'),
'destination': fields.List(fields.String(description='alias email address', example='user@example.com')), 'destination': fields.List(fields.String(description='alias email address', example='user@example.com')),
'wildcard': fields.Boolean(description='enable SQL Like wildcard syntax') 'wildcard': fields.Boolean(description='enable SQL Like wildcard syntax')
}) })
alias_fields = alias.inherit('Alias',alias_fields_update, {
'email': fields.String(description='the alias email address', example='user@example.com', required=True),
'destination': fields.List(fields.String(description='alias email address', example='user@example.com', required=True)),
})
@alias.route('') @alias.route('')
class Aliases(Resource): class Aliases(Resource):

@ -9,9 +9,8 @@ db = models.db
user = api.namespace('user', description='User operations') user = api.namespace('user', description='User operations')
user_fields_get = api.model('UserGet', { """
'email': fields.String(description='The email address of the user', example='John.Doe@example.com', attribute='_email'), base_model = {
'password': fields.String(description='PBKDF2-HMAC-SHA256 based password of the user. For more info see passlib.hash.pbkdf2_sha256', example='$pbkdf2-sha256$1$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44'),
'comment': fields.String(description='A description for the user. This description is shown on the Users page', example='my comment'), 'comment': fields.String(description='A description for the user. This description is shown on the Users page', example='my comment'),
'quota_bytes': fields.Integer(description='The maximum quota for the users email box in bytes', example='1000000000'), 'quota_bytes': fields.Integer(description='The maximum quota for the users email box in bytes', example='1000000000'),
'global_admin': fields.Boolean(description='Make the user a global administrator'), 'global_admin': fields.Boolean(description='Make the user a global administrator'),
@ -30,6 +29,28 @@ user_fields_get = api.model('UserGet', {
'spam_enabled': fields.Boolean(description='Enable the spam filter'), 'spam_enabled': fields.Boolean(description='Enable the spam filter'),
'spam_mark_as_read': fields.Boolean(description='Enable marking spam mails as read'), 'spam_mark_as_read': fields.Boolean(description='Enable marking spam mails as read'),
'spam_threshold': fields.Integer(description='The user defined spam filter tolerance', example='80'), 'spam_threshold': fields.Integer(description='The user defined spam filter tolerance', example='80'),
}
user_fields_get = api.model('UserGet', {
'email': fields.String(description='The email address of the user', example='John.Doe@example.com', attribute='_email'),
'password': fields.String(description='PBKDF2-HMAC-SHA256 based password of the user. For more info see passlib.hash.pbkdf2_sha256', example='$pbkdf2-sha256$1$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44'),
}.update(base_model))
user_fields_post = api.model('UserCreate', {
'email': fields.String(description='The email address of the user', example='John.Doe@example.com', attribute='_email', required=True),
'raw_password': fields.String(description='The raw (plain text) password of the user. Mailu will hash the password using PBKDF2-HMAC-SHA256', example='secret', required=True),
}.update(base_model))
user_fields_put = api.model('UserUpdate', {
'raw_password': fields.String(description='The raw (plain text) password of the user. Mailu will hash the password using PBKDF2-HMAC-SHA256', example='secret'),
}.update(base_model))
"""
user_fields_get = api.model('UserGet', {
'email': fields.String(description='The email address of the user', example='John.Doe@example.com', attribute='_email'),
'password': fields.String(description='PBKDF2-HMAC-SHA256 based password of the user. For more info see passlib.hash.pbkdf2_sha256', example='$pbkdf2-sha256$1$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44'),
}) })
user_fields_post = api.model('UserCreate', { user_fields_post = api.model('UserCreate', {

Loading…
Cancel
Save