AWS Lambda salt和hash出错

时间:2018-01-05 17:16:11

标签: amazon-web-services lambda pbkdf2 createuser

我一直在使用AWS Lambda in Action - Poccia中的源代码来创建用户池和身份池中的用户。我一直收到错误:

Response:
{
  "errorMessage": "RequestId: f6511085-f22c-11e7-be27-534dfc5d6456 Process exited before completing request"
}

Request ID:
"f6511085-f22c-11e7-be27-534dfc5d6456"

Function Logs:
START RequestId: f6511085-f22c-11e7-be27-534dfc5d6456 Version: $LATEST
2018-01-05T15:27:38.890Z    f6511085-f22c-11e7-be27-534dfc5d6456    TypeError: Pass phrase must be a buffer
    at TypeError (native)
    at pbkdf2 (crypto.js:576:20)
    at Object.exports.pbkdf2 (crypto.js:558:10)
    at computeHash (/var/task/lib/cryptoUtils.js:10:10)
    at InternalFieldObject.ondone (/var/task/lib/cryptoUtils.js:19:4)
END RequestId: f6511085-f22c-11e7-be27-534dfc5d6456
REPORT RequestId: f6511085-f22c-11e7-be27-534dfc5d6456  Duration: 113.62 ms Billed Duration: 200 ms     Memory Size: 128 MB Max Memory Used: 33 MB  
RequestId: f6511085-f22c-11e7-be27-534dfc5d6456 Process exited before completing request

我是AWS Services的新手,我不确定为什么会出现此错误。下面是我试图使用的Lambda函数,以下是它引用的cryptoUtils.js脚本。

console.log('Loading function');
//Loading standard module, such as crypto and the AWS SDK
var AWS = require('aws-sdk');
var crypto = require('crypto');
var cryptoUtils = require('./lib/cryptoUtils.js'); //Loading the cryptoUtils.js module shared code, included in the uploaded ZIP archive
var config = require('./config.json'); //Loading the configuration in the config.json file, included in the uploaded ZIP archive


var dynamodb = new AWS.DynamoDB({
  accessKeyId: 'usingKEYfromIAM',
  secretAccessKey: 'usingKEYfromIAM',
}); //Getting the Amazon DynamoDB service object
var ses = new AWS.SES(); //Getting Amazon SES service object

function storeUser(email, password, salt, fn) { //The storeUser() function stores the new user in the DynamoDB table.
  var len = 128;
  crypto.randomBytes(len, function(err, token) { //Arandom token sent in the validation email and used to validate a user
    if (err) return fn(err);
    token = token.toString('hex');
    dynamodb.putItem({ //Putting an item in the DynamoDB table
      TableName: config.DDB_TABLE, //The table name is taken from the config.json configuration file.
      //Most of the data is string ("S"), but the verifiede attribute is Boollean ("BOOL"), 
      //new users aren't verified (false), and the randomly generated token is stored in the "verifyToken" attribute
      Item: {
        email: {
          S: email
        },
        passwordHash: {
          S: password
        },
        passwordSalt: {
          S: salt
        },
        verified: {
          BOOL: false
        },
        verifyToken: {
          S: token
        }
      },
      ConditionExpression: 'attribute_not_exists (email)' //This condition avoids overwriting existing users (with the same email).
    }, function(err, data) {
      if (err) return fn(err);
      else fn(null, token); //The storeUser() function returns the randomly generated token.
    });
  });
}

function sendVerificationEmail(email, token, fn) { //The send-VerificationEmail() funciton sends the verification email to the new user.
  var subject = 'Verification Email for ' + config.EXTERNAL_NAME;
  //The verification link, to the verify.hrml page, passes the randomly generated token as a query parameter.
  var verificationLink = config.VERIFICATION_PAGE + '?email=' + encodeURIComponent(email) + '&verify=' + token;
  ses.sendEmail({ //Sending the email in HTML format
    Source: config.EMAIL_SOURCE,
    Destination: {
      ToAddresses: [
        email
      ]
    },
    Message: {
      Subject: {
        Data: subject
      },
      Body: {
        Html: {
          Data: '<html><head>' + '<meta http-equiv= "Content-Type" content="test/html; charset=UTF-8" />' +
            '<title>' + subject + '</title>' + '</head><body>' + 'Please <a href="' + verificationLink +
            '">click here to verify your email address</a> or a copy & paste the following link in a browser:' +
            '<br><br>' + '<a href="' + verificationLink + '">' + verificationLink + '</a>' + '</body></html>'
        }
      }
    }
  }, fn);
}

exports.handler = (event, context, callback) => { //The function that's exported and can be invoked using AWS Lambda as createUser
  //Getting the input parameters (email, password) from the event
  var email = event.email;
  var clearPassword = event.password;

  //Using compute-Hash() from cryptoUtils.js to salt the password.
  cryptoUtils.computeHash(clearPassword, function(err, salt, hash) {
    if (err) {
      callback('Error in hash: ' + err);
    } else {
      storeUser(email, hash, salt, function(err, token) { //Storing the user via the storeUser()function
        if (err) {
          if (err.code == 'ConditionalCheckFailedException') { //Checking if the database error is due to the email being already prsent in the database
            //userID already found
            callback(null, {
              created: false
            });
          } else {
            callback('Error in storUser: ' + err);
          }
        } else {
          sendVerificationEmail(email, token, function(err, data) { //Sending the verification email
            if (err) {
              callback('Error in sendVerificationEmail: ' + err);
            } else {
              callback(null, {
                created: true
              });
            }
          });
        }
      });
    }
  });
};

var crypto = require('crypto');

function computeHash(password, salt, fn) {
  var len = 512;
  var iterations = 4096;
  var digest = 'sha512';


  if (3 == arguments.length) {
    crypto.pbkdf2(password, salt, iterations, len, digest, function(err, derivedKey) {
      if (err) return fn(err);
      else fn(null, salt, derivedKey.toString('base64'));
    });
  } else {
    fn = salt;
    crypto.randomBytes(len, function(err, solat) {
      if (err) return fn(err);
      salt = salt.toString('base64');
      computeHash(password, salt, fn);
    });
  }
}

module.exports.computeHash = computeHash;

如果有人有任何建议或需要更多信息来帮助我确定错误发生的原因,我将不胜感激。谢谢。

3 个答案:

答案 0 :(得分:0)

您传递的密码是一个数字?

如果是这样:

  • 将其转换为字符串。

  • 如果您不想这样做,可以传递一个Buffer对象:

  

使用方法Buffer.from(string[, encoding])类传递Buffer对象   https://nodejs.org/api/buffer.html#buffer_class_method_buffer_from_string_encoding

crypto.pbkdf2(Buffer.from(password, 'utf8'), salt, iterations, len, digest, function(err, derivedKey) {
    if (err) return fn(err);
    else fn(null, salt, derivedKey.toString('base64'));
});

希望有所帮助!

答案 1 :(得分:0)

var crypto = require('crypto');

function computeHash(password, salt, fn) {
	// Bytesize. The larger the numbers, the better the security, but the longer it will take to complete
	var len = 512;
	var iterations = 4096;
	var digest = 'sha512';

	if (3 == arguments.length) {
	crypto.pbkdf2(Buffer.from(password, 'utf8'), salt, iterations, len, digest, function(err, derivedKey) {
    if (err) return fn(err);
    else fn(null, salt, derivedKey.toString('base64'));
});
	} else {
		fn = salt;
		crypto.randomBytes(len, function(err, salt) {
			if (err) return fn(err);
			salt = salt.toString('base64');
			computeHash(password, salt, fn);
		});
	}
}

module.exports.computeHash = computeHash;

答案 2 :(得分:0)

  

错误“ TypeError:密码短语必须是缓冲区”

建议尝试对输入字符串进行Buffer转换

在测试Buffer.from(password, 'utf8')

之前

您确认输入值编码为'utf8', 而不是其他一些编码,例如base64或latin1?

List of encodings that Node.js supports