I want to host my static website in AWS S3. But it contains "contact us" page which is for sending emails. When the user clicks the submit button it sends the request to AWS API gateway, API gateway triggers the lambda function; the lambda function sends the mail to Admin.
But it has some problem . when we host the website at server we can use captcha to prevent the submit request automation and fraudulent activities . in this case the anybody can misuse (sending more request by passing a query string in the URL ) my API gateway URL who know it.
So my question is how to know that the submit request is requested from my website only and is there any way to use instead of Captcha?.
Validate reCAPTCHA using API Gateway and Lambda
For Contact Forms on serverless SPA sites on S3 static sites, I use AngularJS with the "angular-recaptcha" service (https://github.com/VividCortex/angular-recaptcha), though you can use any way of getting and POSTing the recaptcha value.
On the Backend you can use API Gateway which calls a Lambda function to validate the recaptcha value and do something. Using NodeJS and Recaptcha2 (https://www.npmjs.com/package/recaptcha2) to validate the token.
var reCAPTCHA = require('recaptcha2')
module.exports.sendemail = (event, context, callback) => {
// parse the data that was sent from API Gateway
var eventData = JSON.parse(event.body);
// Prepare the recaptcha connection to Google
var recaptcha = new reCAPTCHA({
siteKey: process.env.RECAPTCHA_KEY,
secretKey: process.env.RECAPTCHA_SECRET
})
// Validate the recaptcha value
recaptcha.validate(eventData.recaptcha)
.then(function(){
// validated ok
console.log("ReCaptcha Valid")
... DO STUFF HERE ...
})
.catch(function(errorCodes){
// invalid recaptcha
console.log("ReCaptcha Not Valid")
// translate error codes to human readable text
console.log(recaptcha.translateErrors(errorCodes));
// send a fail message with cors headers back to the UI
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Invalid Recaptcha"})
}
callback(null, response);
});
};
Example Templated Emails using Handlebars and SES
As a bonus, here is some code I reuse for sending emails using html/text templates:
Works a treat for me :)
'use strict';
var AWS = require('aws-sdk');
var ses = new AWS.SES();
var reCAPTCHA = require('recaptcha2')
var fs = require('fs');
var Handlebars = require('handlebars');
module.exports.sendemail = (event, context, callback) => {
// parse the data that was sent from API Gateway
var eventData = JSON.parse(event.body);
// Prepare the recaptcha connection to Google
var recaptcha = new reCAPTCHA({
siteKey: process.env.RECAPTCHA_KEY,
secretKey: process.env.RECAPTCHA_SECRET
})
// Validate the recaptcha value
recaptcha.validate(eventData.recaptcha)
.then(function(){
// validated ok
console.log("reCAPTCHA Valid")
// Read the HTML template from the package root
fs.readFile('./contact/email_template.html', function (err, emailHtmlTemplate) {
if (err) {
console.log("Unable to load HTML Template");
throw err;
}
// Read the TEXT template from the package root
fs.readFile('./contact/email_template.txt', function (err, emailTextTemplate) {
if (err) {
console.log("Unable to load TEXT Template");
throw err;
}
// Gather data to be injected to the templates
var emailData = {
"websiteaddress": process.env.WEBSITEADDRESS,
"websitename": process.env.WEBSITENAME,
"content": null,
"email": process.env.EMAIL_TO,
"event": eventData
};
// Use Handlebars to compile the template and inject values into the title (used in subject and body of email)
var templateTitle = Handlebars.compile(process.env.EMAIL_TITLE);
var titleText = templateTitle(emailData);
console.log(titleText);
// Add title to the values object
emailData.title = titleText;
// Use Handlebars to compile email plaintext body
var templateText = Handlebars.compile(emailTextTemplate.toString());
var bodyText = templateText(emailData);
console.log(bodyText);
// Use Handlebars to compile email html body
var templateHtml = Handlebars.compile(emailHtmlTemplate.toString());
var bodyHtml = templateHtml(emailData);
console.log(bodyHtml);
// Prepare the SES payload
var params = {
Destination: {
ToAddresses: [
process.env.EMAIL_TO
]
},
Message: {
Body: {
Text: {
Data: bodyText,
Charset: 'UTF-8'
},
Html: {
Data: bodyHtml
},
},
Subject: {
Data: titleText,
Charset: 'UTF-8'
}
},
Source: process.env.EMAIL_FROM
}
console.log(JSON.stringify(params,null,4));
// Send SES Email
ses.sendEmail(params, function(err,data){
if(err) {
console.log(err,err.stack); // error
// Handle SES send errors
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Unable to Send Message"})
}
callback(null, response);
}
else {
console.log(data); // success
// SES send was successful
var response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Message Sent"})
}
callback(null, response);
}
});
}); //end of load text template
}); //end of load html template
})
.catch(function(errorCodes){
// invalid recaptcha
console.log("reCAPTCHA Not Valid")
// translate error codes to human readable text
console.log(recaptcha.translateErrors(errorCodes));
// send a fail message with cors headers back to the UI
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Invalid Recaptcha"})
}
callback(null, response);
});
};
Edit: fixed syntax error
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With