Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscriber can change email address without confirmation #108

Closed
kieronb opened this issue Jul 2, 2014 · 12 comments
Closed

Subscriber can change email address without confirmation #108

kieronb opened this issue Jul 2, 2014 · 12 comments

Comments

@kieronb
Copy link

kieronb commented Jul 2, 2014

When NEWSLETTER_CONFIRM_EMAIL is True (default), a subscriber must confirm subscription by clicking on an activation link in an email.

A user can change their email address without confirmation by receiving an update URL via email, accessing the form and changing the email address. I think that either:
a) this field should not be allowed to be changed
or
b) this should trigger another confirmation email to be sent to the new address

Otherwise, a user can subscribe others to the newsletter without authorization.

EDIT:
This is also possible during the initial subscription process.

  1. Submit email address
  2. Receive email, follow activation link
  3. Enter different email address
  4. Submit
@dokterbob
Copy link
Collaborator

Very good point. This should be taken seriously.

Recently, I discovered It's Dangerous, which would allow us to sign the URL's and would allow us to do away with storing keys in the database. Does that seem like a sensible approach to you?

@dokterbob dokterbob added the bug label Jul 10, 2014
@kieronb
Copy link
Author

kieronb commented Jul 14, 2014

I'm happy to answer your question, but I should warn you that my use case may be a little different than most users, as my first priority is compliance with some fairly strict anti-spam legislation that has just been introduced. The sensible approach for me is the one which best ensures that no one can end up as a confirmed subscriber without having requested it themselves.

These are the pros of django-newsletter as I see them:

  • user confirmation is required
  • no user-specific subscribe and unsubscribe URLs are present in the newsletters. if a newsletter is forwarded by recipient, there is no exposure to the subscribe/unsubscribe mechanism for the original recipient
  • each step is auditable.
    -initial subscription request
    -confirmation email sent
    -URL accessed with user-specific activation code
    -unsubscribe requested
    etc

If "It's Dangerous" offers benefits without impacting the points above, then it sounds sensible to me. In my case, though, I'd sooner lose the ability for a recipient to change their email address at all, and instead make them unsubscribe address 1 and subscribe address 2, than to compromise in other areas. However, this would be a degraded user experience, and may not sit well with most of your user base.

With that said, I'm not sure that it has to be one or the other. I think re-triggering the confirmation process when a user requests to change their email address would be sufficient. When accessing the "activate" URL, I don't think the email address field is required, as the activation code would be unique to each user, and the email address could be gleaned from this database record.

@dokterbob
Copy link
Collaborator

Thanks for the feedback. As I see it, any possible security issues should have priority. Removing the update mechanism will still allow people to potentially unsubscribe other users, hence I think I'd like to go with the signed URL option.

If you are able to work on this it'd be great, I'd love to merge it in. I myself am rather time contrained at the moment (but I think I can make some time to review any patch and put out a new release).

@dokterbob dokterbob modified the milestones: Future, 0.6 Aug 6, 2015
@dokterbob
Copy link
Collaborator

I think we should really have this fixed in the upcoming 0.6 release.

@dokterbob
Copy link
Collaborator

Ref: https://docs.djangoproject.com/en/1.4/topics/signing/

Proposed implementation: stateless (i.e. not storing activation code), preventing replays by using existing email address in salt, similar to Django's builtin password reset token.

Proper security requires a single authentication secret in the URL for (un)subscribe and one for the old email and the new for updates.

Notes:

@robert-kisteleki
Copy link

What's the reason for presenting a form for this? The way I see it, the logic could be as simple as to check the token presented (checking if the email address matches that is really optional!) and if found, su/unsub as needed. This is simple and secure, as long as the token is unpredictable (signing, randomness or hmac).

One can "change" the address by subscribing with a new address and unsubscribing with the old.

I'm willing to send a PR to this extent, if that helps ;-)

@dokterbob
Copy link
Collaborator

I'm not sure if the form is necessary per-se but let me think about it for a bit. However, I do really like to have a POST for the confirmation. This could be an automatic POST generated by JS.

At the time I modelled the interface after other mailing list packages (that I deemed were well-designed). And still, if you look at MailChimp today they do in fact have some kind of form for unsubscribing, which is in fact automatically posted.

I'm not sure if they list the email address and I'm not sure whether this is necessary. I'll look at it again tomorrow, with less of a hangover, to see if there are any reasons against your suggested approach.

@dokterbob
Copy link
Collaborator

I've changed the milestone to 0.7 - to be released ASAP after 0.6 but if I get some code before releasing 0.6 some time next week I'd still love to ship it with 0.6.

@robert-kisteleki
Copy link

Cool. Note that this makes the update function obsolete, which I guess makes the code cleaner too.

I personally don't see a good reason to forcing a POST, a GET is fine as well as long as it's idempotent (which it would be). Being RESTful is nice but one shouldn't overdo it, IMO. Also, it would not work with JS turned off.

@dokterbob
Copy link
Collaborator

I thought about it for a second. I guess it makes sense. Less features and equivalent functionality sounds like a big win to me.

In the process, we could also do away with the distinction between ‘User’ subscribers and normal subscribers with regards to unsubscribing and/or updating (currently users have to login first to be able to unsubscribe - yielding yet another information leak).

Then again, I think we should support some kind of flow where a user unsubscribes with one address and subscribes with another. This allows to have an ‘update email’ link for better user experience AND makes it much easier to maintain the list of subscribers current. Plus it would provide better insight in subscriptions.

I guess, within this context, the optimal flow would be to allow direct subscription / unsubscription using a signed link. Moreover, we should be able to include an update link on the bottom of emails that lead users straight to a subscribe form which would generate a slightly different update link. As the previous address has already been confirmed through the reception of the initial activation link this should work.

To clarify, the flows would be as follows:

Subscribe non-User, email not already subscribed to

  1. Fill in email form, submit
  2. NO database changes
  3. Signed subscription link emailed
  4. Subscribe link click
  5. Subscription added
  6. Confirmation view

Subscribe as User (email already subscribed irrelevant here)

No changes here: form listing newsletters and subscribe status - no confirmation necessary

Subscribe non-user email already subscribed to

User-facing part of normal subscribe flow, though no database changes should take place.

Unsubscribe non-User

  1. User clicks signed subscribe link
  2. User unsubscribed in DB
  3. Confirmation view

Unsubscribe User

Same as non-User flow.

Update non-User

  1. User clicks update link
  2. Update form
  3. NO database changes
  4. Signed update link emailed
  5. Link clicked
  6. Subscription updated in database
  7. Confirmation view

The user experience and a large part of the code, except for the update form and an ‘existing email’ field in the link or something similar, should overlap with the ordinary subscribe view.

Update User

  1. User click update link
  2. Redirect to profile URL (including requiring login)
  3. Everything is handled by whatever is handling the profile from there on

I think we have all user interactions covered now. I hope you would still like to work on this one and I hope you see my point in maintaining the update flow. If its any help perhaps we could split the ticket up so we can collaborate, though due to the large overlap in features it might be easier to have a single person implement this.

@robert-kisteleki
Copy link

TBH I don't know much about the update procedure (which as I said should go, IMO) or the logged-in-user part. I was volunteering for something simpler :)

@dokterbob
Copy link
Collaborator

There was some old WIP on this in https://github.com/dokterbob/django-newsletter/tree/confirmation_fix. It's not finished but I pushed it so that whoever feels like it might finish the job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants