Django как повысить безопасность сброса пароля?
Я установил возможность сброса пароля для своих пользователей. Но я обнаружил несколько угроз безопасности:
1) ссылка на сброс пароля не истекает: Сейчас моя ссылка на сброс пароля не истекает. Я хочу, чтобы ссылка на сброс пароля могла быть использована только один раз. Пользователь не может использовать ее второй раз для смены пароля
2) Как предотвратить изменение пароля, если пользователь меняет значение HTML : Позвольте объяснить. У меня есть html скрытый ввод, заполненный следующим образом <input type="hidden" name="user_id" value="{{user_id}}">
если пользователь меняет html значение user_id
то я хочу предотвратить смену пароля. вот мой код:
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)
Что касается вашего первого вопроса, вы можете использовать параметр настроек Django PASSWORD_RESET_TIMEOUT_DAYS
, чтобы уменьшить количество дней для таймаута ссылки. Вы можете прочитать больше здесь . Я не совсем уверен, что можно сделать ссылку одноразового использования.
Что касается второго вопроса, вы можете зашифровать его любым удобным для вас способом.
Например, вы можете добавить фильтр шаблона, который будет шифровать ваш идентификатор любым удобным для вас способом. Вы можете запустить шифрование caesar или xor с дополнительной текстовой прокладкой, чтобы затруднить расшифровку.
.
Что-то вроде <input type="hidden" name="user_id" value="{{user_id|caesar}}">
Таким образом, менее вероятно, что изменение идентификатора пользователя будет иметь значение, потому что после расшифровки вы можете вернуть ошибку при отправке, если идентификатор пользователя не существует.