从 React Amplify APP 访问 AWS Secrets

Access AWS Secrets from React Amplify APP

这可能是个愚蠢的问题,但是以这种方式从我的 React 前端应用程序(托管在 AWS Amplify)访问 AWS Secrets 是否安全?

这些秘密显然不是 public 所以我不想使用 Amplify Env Variables 选项。

如果这不是将 API 机密和密钥加载到前端应用程序的适当方式,那么什么是?

var AWS = require('aws-sdk'),
    region = "us-east-2",
    secretName = "MNTSWP",
    secret,
    decodedBinarySecret;

// Create a Secrets Manager client
var client = new AWS.SecretsManager({
    region: region
});



client.getSecretValue({SecretId: secretName}, function(err, data) {
    if (err) {
        if (err.code === 'DecryptionFailureException')

            throw err;
        else if (err.code === 'InternalServiceErrorException')

            throw err;
        else if (err.code === 'InvalidParameterException')

            throw err;
        else if (err.code === 'InvalidRequestException')

            throw err;
        else if (err.code === 'ResourceNotFoundException')

            throw err;
    }
    else {

        if ('SecretString' in data) {
            secret = data.SecretString;
        } else {
            let buff = new Buffer(data.SecretBinary, 'base64');
            decodedBinarySecret = buff.toString('ascii');
        }
    }
    
    // Your code goes here. 
});

为了使其正常工作,您必须在有权访问机密的客户端上拥有一些凭据。如果它们确实是秘密的,那么您应该这样做。您通过应用程序请求的任何内容都不再是秘密。如果您尝试提供对后端资源的安全访问,您应该使用 Cognito 之类的东西并传递 JWT。

因为您的前端在 Web 浏览器中运行,因为代码可以很容易地被中等技术用户检查,所以您不能在那里安全地保存凭证(例如您的 AWS 凭证)。如果这样做,不仅会暴露您的秘密,还会暴露您的 AWS 凭证,攻击者可以利用这些凭证造成很大的破坏(并且有工具可以扫描 AWS 密钥)。

老实说,在前端应用程序中并没有真正可靠的方法来保护凭据,因此您可以:

  • 使用安全保存凭据的后端 API
    • 但是你只是在推动问题吗?现在您需要验证用户是否应该有权访问后端 API?
  • 让用户提供凭据
    • 这是最常见的方法 -- 用户提供用户名和密码,您用它来控制访问
    • 这可能仍然需要后端 API 或可以解析凭据的东西(例如 AWS API 网关 + 授权方)
  • 制定复杂的规则来保护后端资源,即使某些级别的密钥已暴露(例如,请参阅 Firebase 安全规则)。

您可能需要先将您的凭据信息保存到 Secret Manager 中,然后按如下方式获取:

var AWS = require('aws-sdk'),
  region = "ap-southeast-1",
  secretName = `my-secret`, rds_username, rds_password;

var awsSecretClient = new AWS.SecretsManager({
  region: region
});

let result = await awsSecretClient.getSecretValue({ SecretId: secretName }).promise();
rds_username = Buffer.from(JSON.parse(result.SecretString).rds_username, 'base64').toString();
rds_password = Buffer.from(JSON.parse(result.SecretString).rds_password, 'base64').toString();