I send a private link to user via email,
= link_to user_profile_url(user_token: #user.token, user_id: #user.uid), method: :post
To avoid let user login again from mobile mail app. I devide to let user login in, if the request has user_token, user_id params.
Because my current method can be brute forcely tried in a short time.
What's the best practice to avoid brute force attacks, thanks
def get_user_by_token(user_id=nil ,token=nil)
if user_id and token
User.where({id: user_id, token: token}).first
else
nil
end
end
You have essentially two complementary options:
make the token complex enough to require a reasonably big computation effort. You can use SecureRandom.hex or even SecureRandom.urlsafe_base64 that includes not only letters and digits but also other chars.
Throttle the action. Keep track of the HTTP requests to that specific action and block the user by IP if the number of requests per minute is higher than, for example 5.
Related
I have a SPA app that contains an form with an upload file field. I have a rest API whose endpoints are protected via flask-extended-jwt JWT. To authenticate the REST endpoints I use #jwt_required. I want to authenticate the upload request as well.
Because of the client side I can't add an Authorization Bearer header so I thought to add the access token as a hidden field when submitting the form.
What is the best way to manually validate the JWT access token after I read it from the form?
class Upload(Resource):
def post(self):
#TODO: check for access token
access_token = None
if 'access_token' in request.form and request.form['access_token']:
access_token = request.form['access_token']
else:
message = json.dumps({'message': 'Invalid or missing token', 'success': False})
return Response(response=message, status=401, mimetype='text/plain')
if access_token:
#TODO: validate_token(access_token)
Thank you
Author of flask-jwt-extended here. That's a great question. There is currently no supported way to do that in the extension, the grabbing the token from the request and decoding it are tightly coupled together. This would be hard to de-couple because there is a lot of conditional things that are going on when the full decode chain runs. For example, checking the CSRF value only if the request is sent in via a cookie, or differentiating between an access and refresh token for the sake of the blacklisting feature.
A generalized function could be created, it's signature would look something like decode_and_verify_jwt(encoded_token, is_access_token=True, check_csrf=False). However, this would complicate the rest of the code in flask_jwt_extended and be a rather confusing function to use for the general case.
I think in this case it would be easier just to add a fourth lookup in the extension, so you could use something like:
app.config['JWT_TOKEN_LOCATION'] = ['headers', 'forms']
app.config['JWT_FORM_KEY'] = 'access_token'
# Use the rest of the application normally
If you want to make a ticket on the github page so I can track this, I would be happy to work on it.
I am playing around with Flask. I like that it is fairly thin and works for most of my requirements.
I would like to know what is your recommended way of retrieving the current logged in user. I would like every HTTP request, which is made, to pass/carry a token in the header, which is first retrieved by the login api
/user/login (params: username, password)
# returns {success: True, token: "<some-unique-string>"
Now is the subsequent APIs I would like to get the user object from the from passed token, like so
#app.route("/user/info", methods = ["GET"])
#apify
def user_get_info():
return {"name": current_user().name}
How could I have current_user read from the header without having to pass the request object every time ?
Any thoughts?
Every token is stored against a user. So you can make a query to get a user against a given token. Something like:
token = Token.query.get(token='token_value')
return jsonify({'name: User.query.get(id=token.user_id).name})
This can be done in one line as well but it totally depends upon your models and relationships.
Hope that helps. If I haven't understood your question correctly, do elaborate a little.
I have a non-profitable website that I need to handle newsletter emails to probably thousand people (lets be realistic and give an upper bound of at most 2000 - 2500 registered users).
I have implemented email this way:
#login_required
def SendEmail(request):
receivers = []
users = Users.objects.all()
receivers.append(user.Email for user in users)
emailTypeSelected = request.POST.get('email_type', -1)
email_factory = EmailFactory()
emailManager = email_factory.create_email(emailTypeSelected)
emailManager.prepare("Some Title")
emailManager.send_email_to(receivers)
return render(request, 'new_user_email.html')
And here is the "abstract" class.
class Email(object):
title = ""
plain_message = ""
html_message = ""
def send_email_to(self, receivers):
send_mail(
self.title,
self.plain_message,
SENDER,
receivers,
html_message=self.html_message
)
I have tested this code and it takes a while to send 1 email to 1 user. My concern is that for thousand emails will put a big overhead to the server.
I was thinking to do the following:
Break the users into group of 100 and send email to those users every 30 minutes.
But I am not sure how this can be implemented. Seems that I will need to implement a sort of threads that will be triggered independently and handle the email for me.
Is there any design pattern that you are aware on how to solve this problem?
Now I know that the best way to do this is to use an external service that handle email newsletter and free up my server from doing this but as a non-profitable website I am trying to minimise the expenses as I already have to pay the server expenses. So at the moment I am trying to find a way to implement that in-house unless big problem arises which will force me to go into third-party services.
Can I restrict actions of my API to specific users if I generate a token like this:
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
expiration = 600
s = Serializer(current_app.config['SECRET_KEY'], expires_in = expiration)
return s.dumps({ 'id': kwargs.get('user_id') })
And the verification
#staticmethod
def verify_auth_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
data = s.loads(token)
except SignatureExpired:
return None # valid token, but expired
except BadSignature:
return None # invalid token
user = User.query.get(data['id'])
return user
I don't understand how this works and achieves security. The way I'm used to securing an API for example, a user wants to do HTTP PUT to /posts/10 I'd usually get the post's author ie user_id then query the database get the token for that user_id, if the request token matches the queried token then it is safe for the PUT. I've read this article and don't fully understand how it achieves security without storing anything in a database. Could someone explain how it works?
By signing and sending the original token upon login the server basically gives the front end an all access ticket to the data the user would have access to, and the front end uses that token (golden ticket) on all future requests for as long as the token is not expired (tokens can be made to have expiration or not). The server in turn knows the token has not been tampered with, because the signature is basically the encrypted hash of the users recognizable data (user_id, username, etc). So, if you change the token information from something like:
{"user_id": 1}
to something like:
{"user_id": 2}
then the signature would be different and the server immediately knows this token is invalid.
This provides an authentication method that exempts the server from having to have a session, because it validates the token every time.
Here is an example of what a token could look like (itsdangerous can use this format of JSON web tokens)
I have two classes of users, those who provide an email address and optional password and (even more) lightweight users who provide only their name. When lightweight users return to my site --even after closing their browser-- their name should be automatically remembered and they should be automatically signed in with their lightweight permissions. Given that name may not be unique, I want to sign the lightweight users in based on their user ID.
(Lightweight users can become full users by adding their email address later.)
I am using Devise, and my user.rb file includes:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def password_required?
false
end
def email_required?
false
end
def remember_me
true
end
In the devise.rb initializer, I have tried setting
config.authentication_keys = [ :user_id ]
but it didn't have an effect other than breaking authentication for those users who have an email address.
With config.authentication_keys = [:email], returning users who have provided an email address are successfully logged into the site when they return even if the browser is restarted/session cookie is destroyed. However, returning users with just a name are forgotten when the browser is restarted. In both cases a remember_user_token cookie is present.
Looking at https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address, I may need to overwrite Devise's find_for_database_authentication method, but I'm not sure what to put in that or if that will be enough; I've tried some variations of that without success.
Finally figured this out; here is the answer in case others have the same issue.
The relevant sign-in process happens in the Rememberable module of Devise.
Devise stores the saved user information between sessions in the remember_user_token cookie. The cookie contains both the user ID and a remember token.
If the email and password are both blank, the remember token will also be blank, causing an internal Devise comparison (secure_compare) to fail. This will result in the session being lost and the remember_user_token cookie to be destroyed.
To fix this, you can set a temporary password for users that don't have one. One approach is the following.
class RegistrationsController < Devise::RegistrationsController
def sign_up_params
new_params = devise_parameter_sanitizer.sanitize(:sign_up)
# If no password is supplied for new user, create one
# This is needed because Devise requires a password for Rememberable to work,
# even if password_required? is set to false in the User model.
if (new_params[:password] == nil)
new_params[:password] = Devise.friendly_token
end
# return the modified (and further sanitized) params list
new_params
end
end
It's up to you, depending on what you're trying to do, whether you want to let the user know about the temporary password they have. Or you could have them reset it if they later add an email address which will also result in them confirming their email address.