简体   繁体   English

如何保护AWS API网关URL免受未经授权的访问?

[英]How to protect AWS API gateway URL from unauthorized access?

I want to host my static website in AWS S3. 我想在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; 当用户单击提交按钮时,它会将请求发送到AWS API网关,API网关会触发lambda函数; the lambda function sends the mail to Admin. lambda函数将邮件发送给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. 在这种情况下,任何人都可以滥用(通过在URL中传递查询字符串发送更多请求)我知道它的API网关URL。

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 ?. 所以我的问题是如何知道提交请求只是从我的网站请求, 有没有办法使用而不是Captcha

Validate reCAPTCHA using API Gateway and Lambda 使用API​​ Gateway和Lambda验证reCAPTCHA

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. 对于S3静态站点上无服务器SPA站点上的Contact Forms,我使用AngularJS和“angular-recaptcha”服务( https://github.com/VividCortex/angular-recaptcha ),尽管您可以使用任何方式获取和POST重新获得价值。

On the Backend you can use API Gateway which calls a Lambda function to validate the recaptcha value and do something. 在后端,您可以使用API​​网关调用Lambda函数来验证重新接收值并执行某些操作。 Using NodeJS and Recaptcha2 ( https://www.npmjs.com/package/recaptcha2 ) to validate the token. 使用NodeJS和Recaptcha2( https://www.npmjs.com/package/recaptcha2 )验证令牌。

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 使用把手和SES的示例模板化电子邮件

As a bonus, here is some code I reuse for sending emails using html/text templates: 作为奖励,这里是我重复使用html /文本模板发送电子邮件的一些代码:

  • Handlebars to inject values to the template SES to send the email. 把柄注入模板SES以发送电子邮件的把手。
  • Make sure that you have set up SES with your domain name, and permissioned the Lambda to "ses:SendEmail" and "ses:SendEmailRaw". 确保您已使用您的域名设置SES,并允许Lambda使用“ses:SendEmail”和“ses:SendEmailRaw”。
  • Add the environment variables when deploying the function, this makes the code reusable and keeps the secrets out of the source code. 在部署函数时添加环境变量,这使得代码可以重用并将秘密保留在源代码之外。
  • I highly recommend using the Serverless Framework to deploy your serverless applications. 我强烈建议使用无服务器框架来部署无服务器应用程序。 https://serverless.com https://serverless.com

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 编辑:修复语法错误

You can use Referer header on http. 您可以在http上使用Referer标头。 It is set by browser. 它由浏览器设置。

Googles reCAPTCHA looks fairly simple to integrate - Googles reCAPTCHA看起来相当简单 -

https://developers.google.com/recaptcha/intro which breaks into - https://developers.google.com/recaptcha/intro进入 -

  1. Validate user with captcha ( https://developers.google.com/recaptcha/docs/display ) 使用验证码验证用户( https://developers.google.com/recaptcha/docs/display
  2. Validate the response ( https://developers.google.com/recaptcha/docs/verify ) 验证回复( https://developers.google.com/recaptcha/docs/verify

This can easily be achieved with API gateway endpoints and lambda (your secret will be in lambda [Maybe as env variable], site key will go in s3 static site) 这可以通过API网关端点和lambda轻松实现(你的秘密将在lambda [也许作为env变量],站点密钥将进入s3静态站点)

Anyway why not design your own verification mechanism (If you really want to do stuff yourself :))? 无论如何,为什么不设计自己的验证机制(如果你真的想自己做的东西:))? Ask for users phone number before letting them submit (or on submit..). 在让用户提交(或提交...)之前询问用户电话号码。 Then invoke a API gateway endpoint which gets this number and sends an otp via SNS. 然后调用API网关端点获取此编号并通过SNS发送otp。 Once user verifies this otp (another api gateway call) then only send the admin email (do further processing). 一旦用户验证此otp(另一个api网关呼叫),则仅发送管理员电子邮件(进行进一步处理)。 You can store this otp is some rds with validated boolean flag. 你可以存储这个otp是一些带有验证布尔标志的rds。 You don't have to worry about these API gateway endpoints since they are really for authentication only and are scaled automatically with cloud front. 您不必担心这些API网关端点,因为它们仅用于身份验证,并且可以通过云端自动扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM