【问题标题】:Restrict API access to specific app clients限制对特定应用客户端的 API 访问
【发布时间】:2018-08-13 21:58:13
【问题描述】:

我已经构建了一个 iOS 和一个 Android 应用程序。这些应用程序使用 Cognito 用户池来允许公开身份验证和未经身份验证的 API 网关访问。

我正在尝试阻止第三方应用访问此 API。我只想要我已授权具有 API 访问权限的应用程序。是否可以将 APIG 的访问权限仅限于我的应用程序?

Cognito 在用户池的设置中提供了 App Client ID 和 App Client Secret 的概念。这是将 Cognito 登录限制为白名单客户端/应用程序的首选机制吗? docs 几乎没有说明此配置的目的或在野外保持这些密钥安全的最佳实践。

是否有其他方法可以实现我正在尝试的目标?这个目标甚至有可能实现吗?我相信应用可以针对这些密钥进行逆向工程,或者可以通过网络嗅探器发现它们。

我在 API 安全方面有点新手,因此非常感谢您的见解。

【问题讨论】:

  • 我目前的工作在登录后生成一个JWT令牌。所以所有数据都是动态的。当然,如果你获得了用户/通行证,你就进去了。然后我使用 API Gateway Autorizers,它对每个请求进行 lambda 调用(也有缓存)。如果这验证了(在我的情况下)JTW,则允许方法通过。不确定这是否真的可以帮助你。
  • 您是否为此使用 Cognito?我认为限制需要发生在 Cognito 级别。只有某些应用程序必须被允许接收登录令牌,然后控制 APIG 访问。我希望我的解释是正确的。
  • 我只玩过几次 Cognito。如果我发现了什么,我会告诉你的。
  • 如果我对您的理解正确,您在 API 网关上对您的 API 进行了经过身份验证的访问和未经身份验证的访问,并且您只想限制对您的应用的未经身份验证的访问。这样做的一种方法是将API keys 用于 API 网关,尽管它的目的不是用于身份验证。这些API keys 本质上是静态的,您必须实现自己的系统来轮换这些密钥。首选方法是使用 identity federationuser pools 来访问您的 API 网关。如果这是您要查找的内容,我可以添加更多详细信息。
  • 谢谢@ASR,请让我澄清一下。我想限制对我的“官方”应用程序的 API 访问,以便只有这个应用程序(iOS 和 Android 版本)可以连接。这将涵盖经过身份验证或未经身份验证的角色。我认为这需要在 Cognito 层处理,以某种方式只允许某些 API 密钥或应用程序客户端通过。我目前正在使用用户池进行身份验证。目标是防止任何未经批准的应用程序连接到 API。如果您能提供任何额外的实施细节,我们将不胜感激。

标签: aws-api-gateway amazon-cognito aws-cognito


【解决方案1】:

看看Cognito IdentityCognito Federated Identity Pools 提供经过身份验证和未经身份验证的访问。这会很长,所以请多多包涵。 (我的代码示例在 yaml 或 JS 中使用 cloudformation)。我假设你已经创建了你的user pool & app client。您将需要这些来创建identity pool。我还将假设您的用户池allowed oauth flows 设置为implicit grant 并且allowed oauth scopeopenid。这是获取用于创建federated identityid_token 所必需的。

  1. 使用您的cognito user pool 作为经过身份验证的提供者创建cognito identity pool。相同的示例 CFN yaml

    AccIdenAdminPool:
      Type: "AWS::Cognito::IdentityPool"
          Properties:
            IdentityPoolName: <identity pool name as input>
            AllowUnauthenticatedIdentities: true
            CognitoIdentityProviders: 
              - ClientId: <your app client id>
                ProviderName: "cognito-idp.us-east-1.amazonaws.com/<your user pool id>"
                ServerSideTokenCheck: true
    
  2. 现在将您经过身份验证和未经身份验证的角色附加到您刚刚创建的identity pool。示例 JS 代码 -

    module.exports.attachRole = (event, context, callback) => {
    
      console.log(JSON.stringify(event));           // successful response
    
      let params = {
        IdentityPoolId: event.identityPoolId, /* required */
        Roles: {
            /* required */
            'authenticated': <auth role arn>,
            'unauthenticated': <unauth role arn>
        },
      };
    
      cognitoidentity.setIdentityPoolRoles(params, function (err, data) {
        if (err) {
            console.log(err, err.stack);
        }
        else {
            console.log("success");      // successful response       
        }
      });
    }
    
  3. 将 API 网关身份验证从 Cognito user pool authorizer 更改为 AWS_IAM。这是必须的。如果由于某种原因您无法执行此操作,则需要找到其他方法来关闭对您的 API 的未经身份验证的访问。

  4. 对于经过身份验证的访问,使用id_token(成功登录后收到)、身份池ID和用户池ID来获取CognitoIdentityCredentials。示例代码 -

    function getAccessToken(idToken, idenPoolId, userPool) {
        let region = idenPoolId.split(":")[0];
        let provider = "cognito-idp." + region + ".amazonaws.com/" + userPool;
        let login = {};
    
        login[provider] = idToken;
    
        console.log(provider + ' || ' + idenPoolId);
    
        // Add the User's Id Token to the Cognito credentials login map.
        let credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: idenPoolId,
            Logins: login
        });
    
        //call refresh method in order to authenticate user and get new temp credentials
        credentials.get((error) => {
            if (error) {
                console.error(error);               
            } else {
                console.log('Successfully logged!');
                console.log('AKI:'+ credentials.accessKeyId);
                console.log('AKS:'+ credentials.secretAccessKey);
                console.log('token:' + credentials.sessionToken);
            }
        });
    }
    

    使用此 access key,secret keyandtoken` 来访问您的 API。它将根据您在第 2 步中配置的经过身份验证的角色获得权限。

  5. 对于未经身份验证的访问,显然会跳过登录步骤,但您仍然可以生成临时密钥以访问您的 API。示例代码非常相似,只有一个关键区别。 Logins 参数不是必需的。

    function getUnauthToken(idenPoolId) {
    
        console.log(idenPoolId);
    
        // Add the User's Id Token to the Cognito credentials login map.
        let credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: idenPoolId,
        });
    
        credentials.get((error) => {
            if (error) {
                console.error(error);
    
            } else {
                console.log('Unauth AKI:'+ credentials.accessKeyId);
                console.log('Unauth AKS:'+ credentials.secretAccessKey);
                console.log('Unauth token:' + credentials.sessionToken);                    
            }
        });
    }
    

    这组密钥的权限基于您在步骤 2 中配置的未经身份验证的角色。

Roles - 这就是我的 API 网关创建角色和策略的方式。 CFN yaml 中的示例

AuthenticatedRole:
  Type: "AWS::IAM::Role"
  Properties:
    RoleName: "AuthenticatedRole"
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        -
          Effect: "Allow"
          Action:
            - "sts:AssumeRoleWithWebIdentity"
          Principal:
            Federated: 
              - "cognito-identity.amazonaws.com"
          Condition:
            StringEquals: 
              cognito-identity.amazonaws.com:aud: <your identity pool id>
            ForAnyValue:StringLike:
              cognito-identity.amazonaws.com:amr: authenticated
    Path: "/"
AuthRolePolicy:
  Type: "AWS::IAM::Policy"
  Properties:
    PolicyName: AuthRolePolicy
    PolicyDocument: 
      Version: "2012-10-17"
      Statement: 
        - 
          Effect: "Allow"
          Action: "execute-api:Invoke"
          Resource:
            - "arn:aws:execute-api:<region>:<account id>:<api id>/*/*/acc/*"]]
    Roles: 
      - 
        Ref: AuthenticatedRole
UnauthRole:
  Type: "AWS::IAM::Role"
  Properties:
    RoleName: UnauthRole
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        -
          Effect: "Allow"
          Action:
            - "sts:AssumeRoleWithWebIdentity"
          Principal:
            Federated: 
              - "cognito-identity.amazonaws.com"
            Condition:
            StringEquals: 
              cognito-identity.amazonaws.com:aud: <your identity pool id>
    Path: "/"
UnauthRolePolicy:
  Type: "AWS::IAM::Policy"
  Properties:
    PolicyName: UnauthRolePolicy
    PolicyDocument: 
      Version: "2012-10-17"
      Statement: 
        - 
          Effect: "Allow"
          Action: "execute-api:Invoke"
          Resource:
          - "arn:aws:execute-api:<region>:<account id>:<api id>/*/GET"/acc/dept/12/*"]]
  Roles: 
    - 
      Ref: UnauthRole

因此,基于上述角色,我对经过身份验证和未经身份验证的用户具有不同的访问权限。唯一需要注意的是,您的 identity pool id 必须是一个秘密(即在浏览器中公开不是一件好事)。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2018-08-31
    • 2021-01-28
    • 2017-10-10
    • 2019-07-15
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多