Amazon Cognito 사용자 풀에서 클라이언트에 대한 비밀 해시를 확인할 수 없음
"Amazon Cognito Identity 사용자 풀"프로세스에 갇혀 있습니다.
시크릿 사용자 풀에서 사용자를 인증하기 위해 가능한 모든 코드를 시도했습니다. 하지만 항상 "오류 : 클라이언트 4b ******* fd에 대한 비밀 해시를 확인할 수 없습니다"라는 오류 가 발생 합니다.
다음은 코드입니다.
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);
});
현재 AWS Cognito는 클라이언트 암호를 완벽하게 처리하지 못하는 것 같습니다. 가까운 장래에 작동하지만 현재로서는 아직 베타 버전입니다.
나에게는 클라이언트 암호가없는 앱에서는 잘 작동하지만 클라이언트 암호가있는 앱에서는 실패합니다.
따라서 사용자 풀에서 클라이언트 암호를 생성하지 않고 새 앱을 만들어보십시오. 그런 다음 해당 앱을 사용하여 새 사용자를 등록하거나 등록을 확인하십시오.
문서에 따르면 : http://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-the-javascript-sdk.html
Javascript SDK는 클라이언트 시크릿이있는 앱을 지원하지 않습니다.
이제 지침에는 사용자 풀용 앱을 만들 때 "클라이언트 암호 생성"을 선택 취소해야한다고 명시되어 있습니다.
이것은 몇 년 늦을 수 있지만 "클라이언트 비밀 생성"옵션을 선택 취소하면 웹 클라이언트에서 작동합니다.
다른 모든 사람들이 자신의 언어를 게시했기 때문에 여기 노드가 있습니다 ( browserify-crypto
웹팩 또는 browserify를 사용하는 경우 자동으로 사용되는을 사용 하여 브라우저에서 작동 함 ).
const crypto = require('crypto');
...
crypto.createHmac('SHA256', clientSecret)
.update(username + clientId)
.digest('base64')
AWS Lambda를 사용하여 AWS JS SDK를 사용하여 사용자를 등록하는 데 관심이있는 사람을 위해 다음 단계를 수행했습니다.
파이썬에서 다른 람다 함수를 만들어 키를 생성합니다.
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()
AWS에서 nodeJS 함수를 통해 함수를 호출합니다. 서명은 Cognito의 비밀 해시 역할을했습니다.
참고 : 대답은 다음 링크에있는 George Campbell의 대답을 기반으로합니다. 파이썬에서 문자열 + 비밀 키로 SHA 해시 계산
.net SDK에서 동일한 문제가 발생했습니다.
다른 사람이 필요로하는 경우를 대비하여 해결 방법은 다음과 같습니다.
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;
}
}
}
가입은 다음과 같습니다.
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;
}
}
대한 솔루션 golang
. 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))
}
Java에서는 다음 코드를 사용할 수 있습니다.
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);
}
SecretHash를 사용한 NodeJS 솔루션
AWS가 NodeJS에 노출되지 않기 때문에 SDK에서 비밀 키를 제거한 것은 어리석은 것 같습니다.
가져 오기를 가로 채서 @Simon Buchan 의 답변을 사용하여 해시 된 키를 추가하여 NodeJS에서 작동하도록했습니다 .
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 ( https://github.com/werk85/fetch-intercept/blob/develop/src/index.js의 Fork에서 NodeJS에 대해 포크 및 편집 됨 )
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,
}
이것은 비밀 해시를 생성하는 데 사용하는 샘플 PHP 코드입니다.
<?php
$userId = "aaa";
$clientId = "bbb";
$clientSecret = "ccc";
$s = hash_hmac('sha256', $userId.$clientId, $clientSecret, true);
echo base64_encode($s);
?>
이 경우 결과는 다음과 같습니다.
DdSuILDJ2V84zfOChcn6TfgmlfnHsUYq0J6c01QV43I=
JAVA 및 .NET의 경우 auth 매개 변수에있는 비밀을 전달해야합니다 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
};
그리고 그것은 작동합니다.
아마존은 어떻게 언급 컴퓨팅 SecretHash 값 에 대한 아마존 Cognito을 자바 애플리케이션 코드와의 문서. 여기서이 코드는 boto 3 Python SDK에서 작동합니다 .
App clients
에서 왼쪽 메뉴에서 찾을 수 있습니다 General settings
. 그 가져 오기 App client id
및 App client secret
생성 SECRET_HASH
. 이해를 돕기 위해 각 라인의 모든 출력을 주석 처리했습니다.
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=
에서 BOTO 3 문서, 우리는 많은 시간이에 대해 물어 볼 수 있습니다 SECRET_HASH
. 따라서 위의 코드 줄은 이것을 만드는 데 도움이 SECRET_HASH
됩니다.
사용하지 않으려면 앱을 만들 때 SECRET_HASH
선택을 취소하십시오 Generate client secret
.
Qt 프레임 워크를 사용한 C ++
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();
};
더 간결한 버전이있을 수 있지만 이것은 Ruby에서 작동하며, 특히 Ruby on Rails에서는 아무것도 필요하지 않습니다.
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))
'programing tip' 카테고리의 다른 글
PHP로 POST를 통해 다차원 배열 제출 (0) | 2020.08.27 |
---|---|
Swift double to string (0) | 2020.08.26 |
웹 페이지에서 Apple의 새로운 San Francisco 글꼴을 사용하는 방법 (0) | 2020.08.26 |
평신도 용어로 Java에서 '정적'이란 무엇을 의미합니까? (0) | 2020.08.26 |
XAMPP 아파치 서버 포트를 변경하는 방법은 무엇입니까? (0) | 2020.08.26 |