Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Account Security for the Fashionable App Developer

Account Security for the Fashionable App Developer

In the same way that we feel safe giving our info to some app and nervous giving our info to other apps, your users have some feeling of safety or concern with the apps you develop. We’ll go over design patterns and Python libraries that will help you protect your user’s accounts.

Given at PyCascades 2019

Philip James

February 24, 2019
Tweet

More Decks by Philip James

Other Decks in Technology

Transcript

  1. #pycascades @asheeshlaroia @phildini
    Account Security for the
    Fashionable App
    Developer
    Asheesh Laroia & Philip James
    PyCascades 2019

    View full-size slide

  2. #pycascades @asheeshlaroia @phildini

    View full-size slide

  3. #pycascades @asheeshlaroia @phildini
    Account Security

    View full-size slide

  4. #pycascades @asheeshlaroia @phildini
    1. Make it costly to take over an
    account
    2. Help users stay informed
    3. Empower users to defend
    themselves

    View full-size slide

  5. #pycascades @asheeshlaroia @phildini

    View full-size slide

  6. #pycascades @asheeshlaroia @phildini
    Make it costly

    View full-size slide

  7. #pycascades @asheeshlaroia @phildini
    hIps:/
    /www.teamsid.com/100-worst-passwords-top-50/
    #9 qwerty
    #8 sunshine
    #7 1234567
    #6 111111
    #5 12345
    #4 12345678
    #3 123456789
    #2 password
    #1 123456

    View full-size slide

  8. #pycascades @asheeshlaroia @phildini
    #@!&$!^rules000000

    View full-size slide

  9. #pycascades @asheeshlaroia @phildini
    “Much of what I did I now
    regret.” -- Bill Burr

    View full-size slide

  10. #pycascades @asheeshlaroia @phildini
    h1ps:/
    /github.com/dropbox/zxcvbn

    View full-size slide

  11. #pycascades @asheeshlaroia @phildini

    View full-size slide

  12. #pycascades @asheeshlaroia @phildini
    Password:

    View full-size slide

  13. #pycascades @asheeshlaroia @phildini
    • pwned-passwords-django (James
    BenneI)
    • django-pwned-passwords
    (jamiecounsell)

    View full-size slide

  14. #pycascades @asheeshlaroia @phildini

    View full-size slide

  15. #pycascades @asheeshlaroia @phildini
    SMS == $$

    View full-size slide

  16. #pycascades @asheeshlaroia @phildini

    View full-size slide

  17. #pycascades @asheeshlaroia @phildini

    View full-size slide

  18. #pycascades @asheeshlaroia @phildini
    “We have had no reported or
    confirmed account takeovers since
    implemendng security keys at
    Google”
    hIps:/
    /krebsonsecurity.com/2018/07/google-security-keys-neutralized-employee-phishing/

    View full-size slide

  19. #pycascades @asheeshlaroia @phildini
    MFA Summary
    • SMS (Twilio, etc.)
    • TOTP (Google Authendcator) (pyotp)
    • U2F (python-u2flib-server)

    View full-size slide

  20. #pycascades @asheeshlaroia @phildini

    View full-size slide

  21. #pycascades @asheeshlaroia @phildini
    Email Login Implementadon
    • hIps:/
    /github.com/skorokithakis/django-tokenauth
    • store sha(token) in your database
    • big-ish index size
    • remember password resets

    View full-size slide

  22. #pycascades @asheeshlaroia @phildini
    Help users stay
    informed

    View full-size slide

  23. #pycascades @asheeshlaroia @phildini

    View full-size slide

  24. #pycascades @asheeshlaroia @phildini

    View full-size slide

  25. #pycascades @asheeshlaroia @phildini
    from django.contrib.auth.signals import user_logged_in
    from django.dispatch import receiver
    from my_app.email import send_login_notification
    @receiver(user_logged_in)
    def check_for_suspicious_login(sender, request, user):
    if user.last_ip != request.ip:
    send_login_notification(user)

    View full-size slide

  26. #pycascades @asheeshlaroia @phildini
    from django.contrib import messages
    @receiver(user_logged_in)
    def check_for_suspicious_login(sender, request, user):
    if user.last_ip != request.ip:
    send_login_notification(user)
    messages.add_message(
    request,
    messages.INFO,
    'Login from new IP address!',
    )

    View full-size slide

  27. #pycascades @asheeshlaroia @phildini
    Password change
    nodficadons

    View full-size slide

  28. #pycascades @asheeshlaroia @phildini
    class MyAppUser(User):
    __password_at_init = None
    ...
    def __init__(self, *args, **kwargs):
    super(MyAppUser, self).__init__(*args, **kwargs)
    self.__password_at_init = self.password

    def save(self, *args, **kwargs):
    if self.password != self.__password_at_init:
    send_password_change_notification()
    super(MyAppUser, self).save(*args, **kwargs)
    self.__password_at_init = self.password

    View full-size slide

  29. #pycascades @asheeshlaroia @phildini

    View full-size slide

  30. #pycascades @asheeshlaroia @phildini
    Nodficadons about
    other breaches

    View full-size slide

  31. #pycascades @asheeshlaroia @phildini

    View full-size slide

  32. #pycascades @asheeshlaroia @phildini

    View full-size slide

  33. #pycascades @asheeshlaroia @phildini
    Empower users to
    defend themselves

    View full-size slide

  34. #pycascades @asheeshlaroia @phildini
    [slide: Screenshot of
    Asheesh’s Facebook
    logout thing d]

    View full-size slide

  35. #pycascades @asheeshlaroia @phildini

    View full-size slide

  36. #pycascades @asheeshlaroia @phildini

    View full-size slide

  37. #pycascades @asheeshlaroia @phildini

    View full-size slide

  38. #pycascades @asheeshlaroia @phildini
    Upgrade
    @login_required
    @requires_post
    def upgrade_plan(request):
    plan = Plan.objects.get(user=request.user)
    plan.upgrade()

    View full-size slide

  39. #pycascades @asheeshlaroia @phildini
    @requires_post
    @login_required
    @require_sudo_mode
    def upgrade_plan(request):
    plan = Plan.objects.get(user=request.user)
    plan.upgrade()

    View full-size slide

  40. #pycascades @asheeshlaroia @phildini
    Password:
    Confirm Password & Upgrade
    By confirming your password, you will enter
    “sudo mode”. We won’t ask for your
    password for some time after.
    /sudo?next=/account&reason=upgrade

    View full-size slide

  41. #pycascades @asheeshlaroia @phildini
    def require_sudo_mode(reason):
    FIVE_MINUTES_AGO = now() - timedelta(seconds=300)
    if request.session.last_authenticated > FIVE_MINUTES_AGO:
    return
    else:
    redirect_to = redirect_to(
    "/sudo",
    {"next": request.referer, "reason": reason},
    )
    hIps:/
    /github.com/jusdnmayer/django-elevate

    View full-size slide

  42. #pycascades @asheeshlaroia @phildini

    View full-size slide

  43. #pycascades @asheeshlaroia @phildini
    Summary
    1. Make it costly to take over an account
    2. Help users stay informed
    3. Empower users to defend themselves
    Asheesh Laroia - @asheeshlaroia

    Philip James - @phildini

    View full-size slide