aws Signature is not validating in amazon api - api

I have generated the aws signature using the code.
function getSignatureKey(key, dateStamp, regionName, serviceName) {
var kDate= lCase(HMAC(ARGUMENTS.dateStamp,"AWS4" & ARGUMENTS.key,"hmacsha256"));
var kRegion= lCase(HMAC(ARGUMENTS.regionName,binaryDecode(kDate,'hex'),"hmacsha256"));
var kService=lCase(HMAC(ARGUMENTS.serviceName,binaryDecode(kRegion,'hex'),"hmacsha256"));
var kSigning= lCase(HMAC("aws4_request",binaryDecode(kService,'hex'),"hmacsha256"));
return kSigning;
}
<cfset signature = getSignatureKey("fdsaadsf87324hdsfo4324d324", "20170504", "us-west-2", "AWSECommerceService")>
but when i call the api and dump the response it says that
"The request signature we calculated does not match the signature you provided"
I am following this link my How to derive a sign-in key for AWS Signature Version 4 (in ColdFusion)?
my result is matching with their result when i put their values.
But when i put original values of my own account it does not match.

Related

How to authenticate Shopware 6 <base-app-url> correctly

With the Admin SDK it's possible to further enrich the administration in Shopware 6. As in the installation guide for apps stated, an entry point (base-app-url) needs to be provided in the manifest file of an app.
Since every request needs to be authenticated properly, this GET request also needs authentication. However, I am not able to authenticate this one in the same way as I am successfully doing it with the GET request from modules.
The base-app-url request looks the following (in my case with some [custom] entity privileges):
http://localhost:3000/sdk?location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE&shopware-shop-signature=e7b20a46487046a515638f76c6fadab6b1c749ea4a8ac6e7653527e73ba18380
The shop has the following data
Shop {
_id: 'sbzqJiPRrbHAlC2K',
_url: 'http://localhost:8888',
_secret: '3c5a2f031006791f2aca40ffa22e8febbc8a53d8',
_apiKey: 'SWIAB2PVODCWSLZNDMC5ZM1XWA',
_secretKey: 'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg'
}
I am currently authenticating my modules like the following (Node.js):
const SHOPWARE_SHOP_SIGNATURE = 'shopware-shop-signature';
export function authenticateGetRequest(req: Request, shop: Shop): void {
// e7b20a46487046a515638f76c6fadab6b1c749ea4a8ac6e7653527e73ba18380
const signature = getSignatureFromQuery(req);
verifySignature(shop.secret, removeParamsFromQuery(req), signature);
}
function getSignatureFromQuery(req: Request): string {
if (!req.query[SHOPWARE_SHOP_SIGNATURE]) {
throw new Error('Signature is not present in request!');
}
return req.query[SHOPWARE_SHOP_SIGNATURE] as string;
}
function removeParamsFromQuery(req: Request): string {
// Some code
// Returns following string - Does neither work for base-app-url nor for module GET requests:
// 'shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045964'
// If the string follows this pattern, it works only for modules:
// shop-id={id}&shop-url={url}&timestamp={ts}&sw-version={v}&sw-context-language={cl}&sw-user-language={ul}
}
function verifySignature(secret: string, message: string, signature: string): void {
const hmac = crypto.createHmac('sha256', secret).update(message).digest('hex');
if (hmac !== signature) {
throw new Error('Signature could not be verified!');
}
}
However the base-app-url cannot be verified correctly and the "Signature could not be verified!" error is thrown.
What am I doing wrong here?
More info:
Additionally I added a GET request for a module where everything is working:
http://localhost:3000/faq?shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE&shopware-shop-signature=0f0889c9e8086c6c3553dc946a01f2ef27b34cd1c55b0c03901b6d8a6a9b6f53
The resulting string can be verified:
shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE
Try out following code in some php sandbox environment:
<?php
$message = 'shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE';
$secret = '3c5a2f031006791f2aca40ffa22e8febbc8a53d8';
$signature = '0f0889c9e8086c6c3553dc946a01f2ef27b34cd1c55b0c03901b6d8a6a9b6f53';
$hmac = hash_hmac('sha256', $message, $secret);
if (!hash_equals($hmac, $signature)) {
echo 'Signature not valid';
} else {
echo 'Signature valid';
}
SOLUTION:
Express decodes the query strings automatically with req.query depending on your express configuration. Keep in mind to validate the hmac with encoded query params as they are passed from shopware.
In my case the only difference where the decoded privileges and they looked like this:
&privileges={"read":["language","ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"create":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"update":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"delete":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"]}
But they need to look like this:
&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D
Looking at the QuerySigner, this is how the signature is generated on the side of Shopware with the actual arguments:
hash_hmac(
'sha256',
'location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE',
'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg'
);
// 8034a13561b75623420b06fb7be01f20d97556441268939e9a5222ffec12215a
Given on your side you remove the shopware-shop-signature query param AND that the secrets are equal on both sides, you should be able to regenerate the matching signature.
const crypto = require('crypto');
const message = 'location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888&timestamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE';
const hmac = crypto.createHmac('sha256', 'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg').update(message).digest('hex');
// 8034a13561b75623420b06fb7be01f20d97556441268939e9a5222ffec12215a
So in theory your code looks fine. Verify that the query string matches exactly. Things to check:
Maybe your node server decodes the url entities unwantedly?
Does your node serve escape special characters in the query string?
Do the secrets match on both sides?
To consider additionally:
Consider to just point the base-app-url to a static page outside of the scope of your app server instead. As that page will be loaded inside an iframe, you can use client side javascript to read the query parameters and, only if necessary, make requests to your app server using the credentials from inside the iframe. Keep in mind you really only need the authentication if you need to handle personalized data, otherwise you might as well serve static assets without the need for authentication.

How do I form the SSH private key signature in JavaScript?

I am using an in-browser library, SSHy, for SSHing to devices. I'm currently working on adding support for publickey authentication, but I keep getting an error from the server about an invalid signature. I'm able to send the first SSH_MSG_USERAUTH_REQUEST without the signature and get back a SSH_MSG_USERAUTH_PK_OK. But when I send the next message with the signature, I always get a SSH_MSG_USERAUTH_FAILURE.
I'm doing the signing with another library (sshpk-browser) and forming the signature below using SSHy based on the SSH schema.
Can anyone see any potential issues with how I am forming the signature?
const decodedPublicKey = config.privateKey.toPublic().toString('ssh', { hashAlgo: 'sha512' }).split(' ')[1];
const publicKey = atob(decodedPublicKey);
var m = new SSHyClient.Message();
m.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
m.add_string(this.termUsername);
m.add_string('ssh-connection');
m.add_string('publickey');
m.add_boolean(true); // has signature
m.add_string('rsa-sha2-512'); // public key algorithm name
m.add_string(publicKey); // public key
// Create signature
var sigMsg = new SSHyClient.Message();
sigMsg.add_string(SSHyClient.kex.sessionId);
sigMsg.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
sigMsg.add_string(this.termUsername);
sigMsg.add_string('ssh-connection');
sigMsg.add_string('publickey');
sigMsg.add_boolean(true); // has signature
sigMsg.add_string('rsa-sha2-512');
sigMsg.add_string(publicKey);
const sigMsgString = sigMsg.toString();
// Sign signature
const sign = config.privateKey.createSign('sha512');
sign.update(sigMsgString);
const signature = sign.sign();
m.add_string(atob(signatureToString)); // signature
this.parceler.send(m);

how to evaluate java function using __groovy and assign it as part of Http Request

I have a http request with the following structure.
Http Request :-
"Accounts": [
{
"accountType": "SAVINGS",
"RefNumber": "${RefNumber}",
"accountNo": "${AccNumber}"
}
],
"encryptionKey": "${__groovy(new com.util.EncryptUtil().encrypt(), encryptedValue)}"
The value of encryptionKey is calculated using the mentioned groovy function. The encrypt function takes the Accounts object and calculates the encryptedValue based on the value of RefNumber and accountNo. The value of accountNo comes from the first Http Response API. The value of the RefNumber comes from the second Http Response API. How do I accept the dynamic Accounts object json and calculate the encrypted value in jmeter and how do I check if the function result is being assigned to encryptionKey using jmeter?
First of all you can check your function output using The Function Helper Dialog
Example class I use for demo looks like:
package com.util;
public class EncryptUtil {
public String encrypt() {
return "some encrypted value";
}
}
Second, you can check your request payload using View Results Tree listener
And finally you can check generated ${encryptedValue} variable using Debug Sampler

Create registration for Azure Notification Hub in Postman

I created a Service Bus / Notification Hub in my Azure Portal.
Now I'm trying to use the Azure REST API with Postman based on this doc :
https://msdn.microsoft.com/en-us/library/azure/dn223265.aspx
Here is the Postman configuration I have :
It's a POST method of the following url (Create Registration)
https://mysite.servicebus.windows.net/mysite-notif/registrations/?api-version=2015-01
(I replaced with mysite in that url for privacy reasons)
In the Headers, I typed 2 entries :
Content-Type
application/atom+xml;type=entry;charset=utf-8
Authorization
Endpoint=sb://[mysite].servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=[mykey]
(this Connection information I copied from the Azure portal)
In the Body, I chose raw - XML(txt/xml) and pasted :
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<WindowsRegistrationDescription xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect">
<Tags>myTag, myOtherTag</Tags>
<ChannelUri>{ChannelUri}</ChannelUri>
</WindowsRegistrationDescription>
</content>
</entry>
(it's the Native registration for Windows Notification Service example)
When I send this call from within Postman, I get a 401 Error :
<Error>
<Code>401</Code>
<Detail>MalformedToken: The credentials contained in the authorization header are not in the WRAP format..TrackingId:ee0d87ef-6175-46a1-9b35-6c31eed6049d_G2,TimeStamp:8/13/2015 9:58:26 AM</Detail>
</Error>
What am I missing ?
Is it the Authorization tab I left on "No Auth" in Postman ?
Is it the value of the Authorization header that should be encoded like shown here ?
Creating registration ID for Azure Notification Hub via REST api
Thanks.
Here is an example of a pre-request script for postman that generates the needed header:
function getAuthHeader(resourceUri, keyName, key) {
var d = new Date();
var sinceEpoch = Math.round(d.getTime() / 1000);
var expiry = (sinceEpoch + 3600);
var stringToSign = encodeURIComponent(resourceUri) + '\n' + expiry;
var hash = CryptoJS.HmacSHA256(stringToSign, key);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var sasToken = 'SharedAccessSignature sr=' + encodeURIComponent(resourceUri) + '&sig=' + encodeURIComponent(hashInBase64) + '&se=' + expiry + '&skn=' + keyName;
return sasToken;
}
postman.setEnvironmentVariable('azure-authorization', getAuthHeader(request['url'], "mySharedAccessKeyName", "mySharedAccessKey"));
postman.setEnvironmentVariable('current-date',new Date().toUTCString());
To use it do the following:
add this pre-request script to your postman request
replace mySharedAccessKeyName , mySharedAccessKey with your credentials
add a header Authorization: {{azure-authorization}}
add a header x-ms-date: {{current-date}}
Your "Authorization" header is not correct.
As stated in the Azure Notification Hubs REST API documentation, e.g. for creating a registration, the "Authorization" header has to contain the "Token generated as specified in Shared Access Signature Authentication with Service Bus"...
The token format is specified in the documentation for Shared Access Signature Authentication with Service Bus as the following:
SharedAccessSignature sig=<signature-string>&se=<expiry>&skn=<keyName>&sr=<URL-encoded-resourceURI>
URL-encoded-resourceURI: The url you send the POST request to (in your case "https://mysite.servicebus.windows.net/mysite-notif/registrations/?api-version=2015-01")
keyName: In your case the default key name "DefaultFullSharedAccessSignature"
expiry: The expiry is represented as the number of seconds since the epoch 00:00:00 UTC on 1 January 1970.
signature-string: The signature for the SAS token is computed using the HMAC-SHA256 of a string-to-sign with the PrimaryKey property of an authorization rule. The string-to-sign consists of a resource URI and an expiry, formatted as follows:
StringToSign = <resourceURI> + "\n" + expiry;
resourceURI should be the same as URL-encoded-resourceURI (also URL encoded)
Compute the HMAC-SHA256 of StringToSign using the SAS key (what you replaces with [mykey] in your example). Use the URL encoded result for signature-string then.
After spending over an hour trying to understand why the steps above didn't work, I realized if you are using the code from https://code.msdn.microsoft.com/Shared-Access-Signature-0a88adf8 It has two things that are not defined at the top of the code. Key and KeyName.
The Key is the part that alluded me because at first glance on the other post here I thought it was the same. Its not.
In Azure: Go to your Notification Hub, Then Click > Settings> Access Policies then on the Policy that has Manage Permission. Add a policy if you need to. Once you Click on the Access Policy. It shows Connection String, Primary and Secondary. Copy the Primary to your Clipboard and throw it in notepad. It will look something like this..
Endpoint=sb://mysite.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=hc7qZ+pMG6zltjmASDFrskZO+Yv52D55KQUxUTSO0og=
SharedAccessKeyName = KeyName
SharedAccessKey = Key
Yea it looks obvious all spelled out here but you cannot see this information in AZURE portal unless you copy it.
So Just to be totally Clear, in the header you generate the key "sig" by combining + "\n" + expiry which Baris did point out, but then you sign it with the Key not the KeyName..
I may sounds like an idiot spelling this out but this process is not an easy one.
Hope it helps someone else.
Baris Akar's response is mostly correct, except for one omission that, for whatever reason, is also not mentioned in the relevant documentation: the signature parameter (i.e., the signature-string in sig=) must be Base64 encoded!
You have to remove "\"" in Token String like below.
authorizationString = resultA.replaceAll("\"","");
From
"SharedAccessSignature sr=https%3a%2f%2fmshub.servicebus.windows.net%2f&sig=PFZVab43PMsO0q9gz4%2bFsuaQq%5ff05L4M7hKVBN8DEn0%3d&se=1553339810&skn=RootManageSharedAccessKey"
To
SharedAccessSignature sr=https%3a%2f%2fmshub.servicebus.windows.net%2f&sig=PFZVab43PMsO0q9gz4%2bFsuaQq%5ff05L4M7hKVBN8DEn0%3d&se=1553339810&skn=RootManageSharedAccessKey
Good luck.
See the following documentation from Microsoft to generate a SAS Token.
This token you can use in Postman.
Generate SAS Token (NodeJs, Java, etc.)
Like Jérôme, I also used the example at https://code.msdn.microsoft.com/Shared-Access-Signature-0a88adf8 to generate the token and I also found out that the .NET-generated token worked. I compared the .NET-generated token with my ruby-generated token and found that URI.escape did not encode the last character (an '=' sign) of my base64 hash. It also did not encode '+' signs. Adding the string '=+' to the function fixed the problem: URI.escape(hmacb64, '=+')
(I don't know if there are other characters that should be identified here.)
It also took me quite some time to figure out a way to generate the SAS tokens in Go.
I created a gist which shows how to generate those tokens:
https://gist.github.com/dennis-tra/14c63e6359f17cbb504e78d6740ca465
I probably wouldn't have figured it out if had not found this repo:
https://github.com/shanepeckham/GenerateSASTokenGo/blob/master/gosas.go
Working from D-rk's code, which is probably outdated in 2022, here's an updated version that works in Postman 10.5.6 and with the Azure Notification Hub's api-version 2020-06
Postman Pre-Request Script:
function createSharedAccessToken(sb_name, eh_name, saName, saKey) {
if (!sb_name || !eh_name || !saName || !saKey) {
throw "Missing required parameter";
}
var resourceUri = encodeURIComponent("https://" + sb_name + ".servicebus.windows.net/" + eh_name)
// Set expiration in seconds
var expires = (Date.now() / 1000) + 20 * 60;
expires = Math.ceil(expires);
var toSign = CryptoJS.enc.Utf8.parse(resourceUri + '\n' + expires);
var sa_key_utf8 = CryptoJS.enc.Utf8.parse(saKey);
var hmac = CryptoJS.HmacSHA256(toSign, sa_key_utf8);
var hmacBase64 = CryptoJS.enc.Base64.stringify(hmac);
var hmacUriEncoded = encodeURIComponent(hmacBase64);
// Construct autorization string
var token = "SharedAccessSignature sr=" + resourceUri + "&sig=" + hmacUriEncoded + "&se=" + expires + "&skn="+ saName;
return token;
}
var sb_name = "your-notification-hub-namespace";
var eh_name = "your-notification-hub-name";
//See Access Policies -> Connection String
var sa_name = "your-shared-access-key-name"
var sa_key = "your-shared-access-key-name"
var auth_header = createSharedAccessToken(sb_name, eh_name, sa_name,sa_key);
pm.environment.set('azure-authorization',auth_header);
pm.environment.set('current-date',new Date().toUTCString());
Solution provided by Dirk helped me to resolve the issue.
But make sure to use SharedAccessKeyName and SharedAccessKey from a policy which has "Manage" claims access. If you have only Send and/or Listen claims, then the authentication will not work and throws an error - MalformedToken: The credentials contained in the authorization header are not in the WRAP format

S3 upload image file security issue

I'm reading the following tutorial:
https://devcenter.heroku.com/articles/s3-upload-node#uploading-directly-to-s3
The first step is when a user chooses an image
function s3_upload(){
var s3upload = new S3Upload({
file_dom_selector: '#files',
s3_sign_put_url: '/sign_s3',
onProgress: function(percent, message) {
// some code
},
onFinishS3Put: function(public_url) {
// some cde
},
onError: function(status) {
// somecode
}
});
}
Now the s3_sign_put_url refers to a server side function that returns
app.get('/sign_s3', function(req, res){
...
// calculates signature (signature variable)
// sets expiration time (expires variable)
var credentials = {
signed_request: url+"?AWSAccessKeyId="+AWS_ACCESS_KEY+"&Expires="+expires+"&Signature="+signature,
url: url
};
...
}
If I already calculated a signature as function of (AWS_SECRET_KEY) like this:
var signature = crypto.createHmac('sha1', AWS_SECRET_KEY).update(put_request).digest('base64');
signature = encodeURIComponent(signature.trim());
signature = signature.replace('%2B','+');
Question:
Why do I have to pass the AWS_SECRET_KEY value as part of the credentials object returned by s3_sign function? why isn't the signature enough to be returned? isn't this a security issue?
You aren't doing that.
The returned credentials contain the AWS_ACCESS_KEY, not the AWS_SECRET_KEY.
The access key is analogous to a username... it's needed by S3 so that it knows who created the signature. From this, S3 looks up the associated secret key internally, creates a signature for the request, and if it's the same signature as the one you generated and the supplied access key is associated with a user with permission to perform the operation, it succeeds.
The access key and secret key work as a pair, and one can't reasonably be derived from the other; the access key is not considered private, while the secret key is.