#python #python-3.x #django
Вопрос:
Я настроил опцию сброса пароля для своих пользователей. Но я обнаружил несколько угроз безопасности:
1) ссылка для сброса пароля не истекает: Прямо сейчас моя ссылка для сброса пароля не истекает. Я хочу, чтобы ссылку для сброса пароля можно было использовать только один раз. Пользователь не может использовать его во второй раз для смены пароля
2) Как предотвратить смену пароля, если пользователь изменит значение HTML : Позвольте вам объяснить. У меня есть скрытый ввод html, поданный таким <input type="hidden" name="user_id" value="{{user_id}}">
образом, если пользователь изменит значение user_id
html, я хочу предотвратить изменение пароля. вот мой код:
token.py для сброса отправленного пароля ссылка на почту
def send_forget_password_mail(email,token):
subject = 'EXAMPLE.COM Password Reset Link'
message = f'hi your forgot password link http://127.0.0.1:8000/change-password/{token}'
email_from = 'noreply@EXAMPLE.com'
recipient_list =[email]
send_mail(subject,message,email_from,recipient_list)
return True
views.py
Это представление «Забыть пароль», в котором пользователь отправляет почту для получения ссылки на сброс пароля. Здесь я также сохраняю токен в профиле пользователя.
def ForgetPassword(request):
if request.method == "POST":
email = request.POST["email"]
User = get_user_model()
if not User.objects.filter(email=email).first():
messages.success(request, "Invalid mail")
return redirect('members:rest-password')
user_obj = User.objects.get(email=email)
print(user_obj)
token = str(uuid.uuid4())
profile_obj = UserProfile.objects.get(user=user_obj)
profile_obj.forget_password_token = token
profile_obj.save()
send_forget_password_mail(user_obj.email,token)
messages.success(request, "An password reset link sent to your email")
return redirect('members:reset-password')
return render(request, 'members/password_reset_form.html')
Это представление, в котором пользователь меняет свой пароль.
def ChangePassword(request,token):
profile_obj = UserProfile.objects.filter(forget_password_token=token).first()
User = get_user_model()
print(profile_obj)
if request.method == "POST":
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
user_id = request.POST.get('user_id')
if user_id is None:
messages.success(request, "user not found")
return redirect(f'http://127.0.0.1:8000/change-password/{token}')
if password1 != password2:
messages.success(request, "password didn't match")
return redirect(f'http://127.0.0.1:8000/change-password/{token}')
user_obj = User.objects.get(id =user_id)
user_obj.set_password(password1)
user_obj.save()
messages.success(request, "your password sucessfully changed")
return redirect('members:login')
context ={'user_id':profile_obj.user.id}
print(context)
return render(request,'members/password_change.html',context)
Ответ №1:
Для вашего первого вопроса вы можете использовать параметр настроек Django PASSWORD_RESET_TIMEOUT_DAYS
, чтобы уменьшить количество дней для тайм-аута ссылки. Вы можете прочитать больше здесь. Я не совсем уверен, что это возможно сделать ссылкой для одноразового использования.
Что касается второго вопроса, вы можете зашифровать его любым удобным для вас способом.
Например, вы можете добавить шаблон фильтра, который будет шифровать ваш идентификатор любым удобным для вас способом. Вы можете запустить шифрование caesar или шифрование xor с дополнительным заполнением текста, чтобы затруднить расшифровку.
Что-то вроде <input type="hidden" name="user_id" value="{{user_id|caesar}}">
Таким образом, менее вероятно, что изменение идентификатора пользователя будет иметь значение, потому что вы можете вернуть ошибку при отправке, если идентификатор пользователя не существует, после расшифровки.