Không thể xác minh hàm băm bí mật cho khách hàng trong Amazon Cognito Userpools


131

Tôi bị kẹt trong quá trình "Nhóm người dùng nhận dạng Amazon Cognito".

Tôi đã thử tất cả các mã có thể để xác thực người dùng trong nhóm người dùng cognito. Nhưng tôi luôn gặp lỗi khi nói "Lỗi: Không thể xác minh hàm băm bí mật cho máy khách 4b ******* fd".

Đây là mã:

AWS.config.region = 'us-east-1'; // Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b64bb629-ec73-4569-91eb-0d950f854f4f'
});

AWSCognito.config.region = 'us-east-1';
AWSCognito.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:b6b629-er73-9969-91eb-0dfffff445d'
});

AWSCognito.config.update({accessKeyId: 'AKIAJNYLRONAKTKBXGMWA', secretAccessKey: 'PITHVAS5/UBADLU/dHITesd7ilsBCm'})

var poolData = { 
    UserPoolId : 'us-east-1_l2arPB10',
    ClientId : '4bmsrr65ah3oas5d4sd54st11k'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

var userData = {
     Username : 'ronakpatel@gmail.com',
     Pool : userPool
};

var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);

cognitoUser.confirmRegistration('123456', true,function(err, result) {
if (err) {
    alert(err);
    return;
}
console.log('call result: ' + result);
});

9
Câu trả lời được chấp nhận là KHÔNG hợp lệ nữa. Hướng dẫn cách tạo băm bí mật có tại đây docs.aws.amazon.com/cognito/latest/developerguide/ Lời
jasiustasiu

Có, và xem câu trả lời @Simon Buchan bên dưới để triển khai JavaScript. Nó hoạt động hoàn hảo.
guzmonne

Câu trả lời:


179

Có vẻ như hiện tại AWS Cognito không xử lý bí mật khách hàng một cách hoàn hảo. Nó sẽ hoạt động trong tương lai gần nhưng hiện tại nó vẫn là phiên bản beta.

Đối với tôi, nó hoạt động tốt đối với một ứng dụng không có bí mật của khách hàng nhưng không thành công cho một ứng dụng có bí mật của khách hàng.

Vì vậy, trong nhóm người dùng của bạn hãy cố gắng tạo một ứng dụng mới mà không tạo ra một bí mật khách hàng. Sau đó sử dụng ứng dụng đó để đăng ký người dùng mới hoặc để xác nhận đăng ký.


14
FYI: Điều này vừa xảy ra với tôi, vừa nãy. Nó vẫn hoạt động theo cách này, tháng 1 năm 2017. Khi tôi tạo một ứng dụng không có client_secret, tôi đã có thể sử dụng SDK SDK. Khi tôi tạo một ứng dụng với client_secret, tôi đã nhận được thông tin tương tự như trong câu hỏi ban đầu.
Cheeso

5
Kể từ ngày 21 tháng 4 năm 2017, nó vẫn không hoạt động khi sử dụng AWS CLI khi khóa bí mật được bật cho Ứng dụng khách. aws cognito-idp admin-initate-auth \ --region ap-winter-1 \ --user-pool-id MY_POOL_ID \ --client-id MY_CLIENT_ID \ --auth-Flow ADMIN_NO_SRP_AUTH \ --auth -ameter @ gmail.com, PASSWORD = som3PassW0rd
Stanley Yong

26
Kể từ tháng 1 năm 2018, điều này vẫn chưa được hỗ trợ. Tài liệu về repo Github github.com/aws/amazon-cognito-identity-js đề cập đến nó:"When creating the App, the generate client secret box must be unchecked because the JavaScript SDK doesn't support apps that have a client secret."
kakoma

5
19 tháng 5 năm 2018, cùng một lỗi chúng ta cần tạo ứng dụng mà không có bí mật của khách hàng.
Dileep

4
Ngày 12 tháng 9 năm 2018 - Vấn đề tương tự. Ngay cả khi không sử dụng ứng dụng khách tạo bí mật, tôi vẫn nhận được 400 dù người dùng có được xác thực hay không. Ứng dụng chức năng như mong đợi mặc dù điều này, tuy nhiên.
foxtrotuniform6969


37

Điều này có thể trễ vài năm nhưng chỉ cần bỏ chọn tùy chọn "Tạo bí mật khách hàng" và nó sẽ hoạt động cho các máy khách web của bạn.

tạo tùy chọn ứng dụng khách


8
Lưu ý rằng bạn không thể chỉnh sửa nó sau khi máy khách được tạo, vì vậy hãy tạo một cái mới nếu cần.
URL87

Nếu bạn tạo ứng dụng khách mới và bạn có nhóm nhận dạng (trên "Danh tính liên kết") sử dụng nhà cung cấp xác thực Cognito, hãy nhớ cập nhật trường id ứng dụng khách với id của ứng dụng khách ứng dụng mới.
AMS777

21

Vì mọi người khác đã đăng ngôn ngữ của họ, nên đây là nút (và nó hoạt động trong trình duyệt với browserify-crypto, được sử dụng tự động nếu bạn sử dụng webpack hoặc browserify):

const crypto = require('crypto');

...

crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')

4
đây là giải pháp Node.js đơn giản và tốt nhất được xây dựng trong giải pháp, cảm ơn @simon
Kỹ sư

19

Tôi gặp vấn đề tương tự trong SDK .net.

Đây là cách tôi giải quyết, trong trường hợp có ai khác cần nó:

public static class CognitoHashCalculator
{
    public static string GetSecretHash(string username, string appClientId, string appSecretKey)
    {
        var dataString = username + appClientId;

        var data = Encoding.UTF8.GetBytes(dataString);
        var key = Encoding.UTF8.GetBytes(appSecretKey);

        return Convert.ToBase64String(HmacSHA256(data, key));
    }

    public static byte[] HmacSHA256(byte[] data, byte[] key)
    {
        using (var shaAlgorithm = new System.Security.Cryptography.HMACSHA256(key))
        {
            var result = shaAlgorithm.ComputeHash(data);
            return result;
        }
    }
}

Đăng ký sau đó trông như thế này:

public class CognitoSignUpController
{
    private readonly IAmazonCognitoIdentityProvider _amazonCognitoIdentityProvider;

    public CognitoSignUpController(IAmazonCognitoIdentityProvider amazonCognitoIdentityProvider)
    {
        _amazonCognitoIdentityProvider = amazonCognitoIdentityProvider;
    }

    public async Task<bool> SignUpAsync(string userName, string password, string email)
    {
        try
        {
            var request = CreateSignUpRequest(userName, password, email);
            var authResp = await _amazonCognitoIdentityProvider.SignUpAsync(request);

            return true;
        }
        catch
        {
            return false;
        }
    }

    private static SignUpRequest CreateSignUpRequest(string userName, string password, string email)
    {
        var clientId = ConfigurationManager.AppSettings["ClientId"];
        var clientSecretId = ConfigurationManager.AppSettings["ClientSecretId"];

        var request = new SignUpRequest
        {
            ClientId = clientId,
            SecretHash = CognitoHashCalculator.GetSecretHash(userName, clientId, clientSecretId),
            Username = userName,
            Password = password,
        };

        request.UserAttributes.Add("email", email);
        return request;
    }
}

Xác nhận rằng điều này vẫn cần thiết và vẫn hoạt động trong v3 AWS .NET SDK (bản xem trước).
pieSquared

13

Đối với bất kỳ ai quan tâm đến việc sử dụng AWS Lambda để đăng ký người dùng bằng AWS JS SDK, đây là các bước tôi đã làm:

Tạo một hàm lambda khác trong python để tạo khóa:

import hashlib
import hmac
import base64

secretKey = "key"
clientId = "clientid"
digest = hmac.new(secretKey,
                  msg=username + clientId,
                  digestmod=hashlib.sha256
                 ).digest()
signature = base64.b64encode(digest).decode()

Gọi hàm thông qua hàm nodeJS trong AWS. Chữ ký đóng vai trò là hàm băm bí mật cho Cognito

Lưu ý: Câu trả lời dựa nhiều vào câu trả lời của George Campbell trong liên kết sau: Tính toán hàm băm SHA bằng chuỗi + khóa bí mật trong python


12

Giải pháp cho golang. Có vẻ như điều này nên được thêm vào SDK.

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
)

func SecretHash(username, clientID, clientSecret string) string {
    mac := hmac.New(sha256.New, []byte(clientSecret))
    mac.Write([]byte(username + ClientID))
    return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

8

Giải pháp cho NodeJS với SecretHash

Có vẻ ngớ ngẩn khi AWS đã xóa khóa bí mật khỏi SDK vì nó sẽ không bị lộ trong NodeJS.

Tôi đã làm cho nó hoạt động trong NodeJS bằng cách chặn tìm nạp và thêm vào khóa băm bằng câu trả lời của @Simon Buchan .

cognito.js

import { CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'amazon-cognito-identity-js'
import crypto from 'crypto'
import * as fetchIntercept from './fetch-intercept'

const COGNITO_SECRET_HASH_API = [
  'AWSCognitoIdentityProviderService.ConfirmForgotPassword',
  'AWSCognitoIdentityProviderService.ConfirmSignUp',
  'AWSCognitoIdentityProviderService.ForgotPassword',
  'AWSCognitoIdentityProviderService.ResendConfirmationCode',
  'AWSCognitoIdentityProviderService.SignUp',
]

const CLIENT_ID = 'xxx'
const CLIENT_SECRET = 'xxx'
const USER_POOL_ID = 'xxx'

const hashSecret = (clientSecret, username, clientId) => crypto.createHmac('SHA256', clientSecret)
  .update(username + clientId)
  .digest('base64')

fetchIntercept.register({
  request(url, config) {
    const { headers } = config
    if (headers && COGNITO_SECRET_HASH_API.includes(headers['X-Amz-Target'])) {
      const body = JSON.parse(config.body)
      const { ClientId: clientId, Username: username } = body
      // eslint-disable-next-line no-param-reassign
      config.body = JSON.stringify({
        ...body,
        SecretHash: hashSecret(CLIENT_SECRET, username, clientId),
      })
    }
    return [url, config]
  },
})

const userPool = new CognitoUserPool({
  UserPoolId: USER_POOL_ID,
  ClientId: CLIENT_ID,
})

const register = ({ email, password, mobileNumber }) => {
  const dataEmail = { Name: 'email', Value: email }
  const dataPhoneNumber = { Name: 'phone_number', Value: mobileNumber }

  const attributeList = [
    new CognitoUserAttribute(dataEmail),
    new CognitoUserAttribute(dataPhoneNumber),
  ]

  return userPool.signUp(email, password, attributeList, null, (err, result) => {
    if (err) {
      console.log((err.message || JSON.stringify(err)))
      return
    }
    const cognitoUser = result.user
    console.log(`user name is ${cognitoUser.getUsername()}`)
  })
}

export {
  register,
}

fetch-inceptor.js ( Được chia và chỉnh sửa cho NodeJS từ Fork của https://github.com/werk85/fetch-intercept/blob/develop/src/index.js )

let interceptors = []

if (!global.fetch) {
  try {
    // eslint-disable-next-line global-require
    global.fetch = require('node-fetch')
  } catch (err) {
    throw Error('No fetch available. Unable to register fetch-intercept')
  }
}
global.fetch = (function (fetch) {
  return (...args) => interceptor(fetch, ...args)
}(global.fetch))

const interceptor = (fetch, ...args) => {
  const reversedInterceptors = interceptors.reduce((array, _interceptor) => [_interceptor].concat(array), [])
  let promise = Promise.resolve(args)

  // Register request interceptors
  reversedInterceptors.forEach(({ request, requestError }) => {
    if (request || requestError) {
      promise = promise.then(_args => request(..._args), requestError)
    }
  })

  // Register fetch call
  promise = promise.then(_args => fetch(..._args))

  // Register response interceptors
  reversedInterceptors.forEach(({ response, responseError }) => {
    if (response || responseError) {
      promise = promise.then(response, responseError)
    }
  })

  return promise
}

const register = (_interceptor) => {
  interceptors.push(_interceptor)
  return () => {
    const index = interceptors.indexOf(_interceptor)
    if (index >= 0) {
      interceptors.splice(index, 1)
    }
  }
}

const clear = () => {
  interceptors = []
}

export {
  register,
  clear,
}

Tôi đã có thể đăng ký theo thủ tục của bạn, nhưng tôi không thể đăng nhập bằng cách sử dụng Proc này. Có bất kỳ sửa đổi cần phải được thực hiện để đăng nhập? Nó sẽ rất hữu ích nếu bạn có thể thêm nó ở đây. Cảm ơn trước.
Vinay Wadagavi

7

Trong Java, bạn có thể sử dụng mã này:

private String getSecretHash(String email, String appClientId, String appSecretKey) throws Exception {
    byte[] data = (email + appClientId).getBytes("UTF-8");
    byte[] key = appSecretKey.getBytes("UTF-8");

    return Base64.encodeAsString(HmacSHA256(data, key));
}

static byte[] HmacSHA256(byte[] data, byte[] key) throws Exception {
    String algorithm = "HmacSHA256";
    Mac mac = Mac.getInstance(algorithm);
    mac.init(new SecretKeySpec(key, algorithm));
    return mac.doFinal(data);
}

Nơi nào bạn sử dụng hàm băm bí mật này trong SDK ngoài việc đưa nó ra màn hình?
Aaron

1
Bất cứ ai cũng có thể chỉ ra bất kỳ tài liệu AWS trực tuyến nào, nơi xác thực chống lại bí mật của khách hàng được giải thích? Các mã hóa chữ ký base64 / sha256 là các giải pháp hấp dẫn - nhưng vô giá trị trừ khi chúng tuân thủ rõ ràng với các tài liệu AWS đánh vần cách xác thực đối với bí mật của máy khách.
Kode Charlie

7

Amazon đề cập đến cách tính toán các giá trị SecretHash cho Amazon Cognito trong tài liệu của họ với mã ứng dụng Java. Ở đây mã này hoạt động với boto 3 Python SDK .

chi tiết ứng dụng khách

Bạn có thể tìm thấy App clientstrong menu bên trái của bạn dưới General settings. Nhận những cái đó App client idApp client secretđể tạo ra SECRET_HASH. Để bạn hiểu rõ hơn, tôi đã nhận xét tất cả các kết quả đầu ra của mỗi dòng.

import hashlib
import hmac
import base64

app_client_secret = 'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
app_client_id = '396u9ekukfo77nhcfbmqnrec8p'
username = 'wasdkiller'

# convert str to bytes
key = bytes(app_client_secret, 'latin-1')  # b'u8f323eb3itbr3731014d25spqtv5r6pu01olpp5tm8ebicb8qa'
msg = bytes(username + app_client_id, 'latin-1')  # b'wasdkiller396u9ekukfo77nhcfbmqnrec8p'

new_digest = hmac.new(key, msg, hashlib.sha256).digest()  # b'P$#\xd6\xc1\xc0U\xce\xc1$\x17\xa1=\x18L\xc5\x1b\xa4\xc8\xea,\x92\xf5\xb9\xcdM\xe4\x084\xf5\x03~'
SECRET_HASH = base64.b64encode(new_digest).decode()  # UCQj1sHAVc7BJBehPRhMxRukyOoskvW5zU3kCDT1A34=

Trong tài liệu boto 3 , chúng ta có thể thấy rất nhiều thời gian hỏi về SECRET_HASH. Vì vậy, các dòng mã trên giúp bạn tạo ra điều nàySECRET_HASH .

Nếu bạn không muốn sử dụng, SECRET_HASHchỉ cần bỏ chọn Generate client secretkhi tạo ứng dụng.

tạo ứng dụng mới


1
Đối với tôi, điều này chỉ hoạt động nếu tôi chuyển tập tin = byte (app_client_id + tên người dùng, 'latin-1') sang tập tin = byte (tên người dùng + app_client_id, 'latin-1'). Để rõ ràng, tôi đã chuyển thứ tự của clientId và tên người dùng sao cho tên người dùng xuất hiện đầu tiên.
Josh Wolff

1
Cảm ơn rất nhiều @JoshWolff, tôi đã trao đổi nhầm app_client_idusername. Nhưng tôi hiển thị đầu ra chính xác dưới dạng một nhận xét hiển thị theo dấu username+ app_client_id. Một lần nữa và cảm ơn rất nhiều.
Kushan Gunasekera

1
Không có vấn đề gì cả! @Kushan Gunasekera
Josh Wolff

6

đây là mã php mẫu mà tôi sử dụng để tạo hàm băm bí mật

<?php
    $userId = "aaa";
    $clientId = "bbb";
    $clientSecret = "ccc";
    $s = hash_hmac('sha256', $userId.$clientId, $clientSecret, true);
    echo base64_encode($s);
?>

trong trường hợp này kết quả là:

DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=

5

đối với JAVA và .NET, bạn cần truyền bí mật có trong các tham số auth với tên SECRET_HASH.

AdminInitiateAuthRequest request = new AdminInitiateAuthRequest
{
  ClientId = this.authorizationSettings.AppClientId,
  AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
  AuthParameters = new Dictionary<string, string>
  {
    {"USERNAME", username},
    {"PASSWORD", password},
    {
      "SECRET_HASH", EncryptionHelper.GetSecretHash(username, AppClientId, AppClientSecret)
    }
  },
  UserPoolId = this.authorizationSettings.UserPoolId
};

Và nó nên hoạt động.


3

C ++ với Khung Qt

QByteArray MyObject::secretHash(
     const QByteArray& email,
     const QByteArray& appClientId, 
     const QByteArray& appSecretKey)
{
            QMessageAuthenticationCode code(QCryptographicHash::Sha256);
            code.setKey(appSecretKey);
            code.addData(email);
            code.addData(appClientId);
            return code.result().toBase64();
};

1

Có thể có một phiên bản nhỏ gọn hơn, nhưng phiên bản này hoạt động cho Ruby, cụ thể là trong Ruby on Rails mà không phải yêu cầu bất cứ điều gì:

key = ENV['COGNITO_SECRET_HASH']
data = username + ENV['COGNITO_CLIENT_ID']
digest = OpenSSL::Digest.new('sha256')

hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, key, data))

0

Xác thực Cognito

Lỗi: Ứng dụng khách không được định cấu hình cho bí mật nhưng đã nhận được hàm băm bí mật

Cung cấp secretKey như nil làm việc cho tôi. Thông tin được cung cấp bao gồm: -

  • CognitoIdentityUserPoolRegion (vùng)
  • CognitoIdentityUserPoolId (userPoolId)
  • CognitoIdentityUserPoolAppClientId (ClientId)
  • AWSCognitoUserPoolsSignInProviderKey (AccessKeyId)

    // setup service configuration
    let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil)
    
    // create pool configuration
    let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId,
                                                                    clientSecret: nil,
                                                                    poolId: CognitoIdentityUserPoolId)
    
    // initialize user pool client
    AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)
    

Tất cả những điều trên làm việc với mẫu mã được liên kết dưới đây.

Mã mẫu AWS: https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Swift

Hãy cho tôi biết nếu điều đó không làm việc cho bạn.


đây là một liên kết chết
Jpnh

0

Đây là lệnh 1 của tôi và nó hoạt động (Xác nhận :))

EMAIL="EMAIL@HERE.com" \
CLIENT_ID="[CLIENT_ID]" \
CLIENT_SECRET="[CLIENT_ID]" \
&& SECRET_HASH=$(echo -n "${EMAIL}${CLIENT_ID}" | openssl dgst -sha256 -hmac "${CLIENT_SECRET}" | xxd -r -p | openssl base64) \
&& aws cognito-idp ...  --secret-hash "${SECRET_HASH}"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.