限制特定应用程序客户端的 API 访问

Foo*_*ook 5 amazon-cognito aws-api-gateway

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

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

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

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

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

ASR*_*ASR 1

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

  1. cognito identity pool使用您cognito user 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
    
    Run Code Online (Sandbox Code Playgroud)
  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       
        }
      });
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将 API 网关身份验证从 更改Cognito user pool authorizerAWS_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);
            }
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)

    使用此access key,密钥and令牌来访问您的 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);                    
            }
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这组密钥的权限基于您在步骤 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
Run Code Online (Sandbox Code Playgroud)

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

希望这可以帮助。