JWT token signature - http

I am looking for a solution on how to improve security for JWT without using encrytpion and in the same time allow user a multisessions.
The standard algorithm of creating a signature is:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
What if we combine some unique client identifier (IP/ MAC address/ browser Fingerprint) (smth that could be exported from the request itself without passing in request body) with our secret?
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret + UNIQUEIDENTIFIER)
Such a solution will prevents the hacker to access our data even if the whole JWT will be stolen.
Unfortunately the usage of IP is not the best for UNIQUEIDENTIFIER, because the client can use dynamic IP.
Any ideas which parameter of http request can be used as UNIQUEIDENTIFIER?

Related

Encryption key retrieve on http call to the API?

Can you tell me if the following flow is good practice for retrieving encryption key?
So I have an Angular app which has custom encryption service created by me and a npm library, which now uses simple string value for key.
I also store access token inside a cookie and the value is encrypted.
Is it good practice, while executing a standard CRUD operation method against my API, first in this method to execute a separate http get request to get the encryption key from the API (from a separate endpoint), then de-crypt the cookie and THEN send it in the http request?
For example, look at this pseudo-code:
getAllProductsAsAdmin(): Observable<any>{
let encryptionKey = callApiAndGetKeyMethod(this.encryptionKeyApiUrl);
let decryptedCookie = decryptCookie(this.existingCookie, encryptionKey);
this.headers = this.headers.set('Authorization', decryptedCookie);
return this.httpClient.get<IGetProductAdminModel[]>(this.getAllProductsAsAdminUrl, {headers: this.headers})
.pipe(
tap(data => console.log('All:',JSON.stringify(data))),
catchError(this.handleError)
);

How to verify a HS256 signed JWT Token created with Keycloak authentication provider on jwt.io

I am trying to verify a HS256 JWT Token generated with locally ran KeyCloak Authentication Provider on https://jwt.io.
The KeyCloack instance is running on my local machine inside a docker container. I have applied almost the same steps as described in this answer (which on contrary applies the RS algorithm instead, and works as described): https://stackoverflow.com/a/55002225/1534753
My validation procedure is very simple:
1.) Request the token (with Postman) from my local docker KeyCloak instance with:
POST requesting http://localhost:8080/auth/realms/dev/protocol/openid-connect/token
2.) Copy the token contents inside the jwt.io's "Encoded" section
3.) I verify that the header and payload are as expected and correct
4.) I copy the client secret from my KeyCloak instance admin dashboard, you can see the reference on the image below:
5.) I paste the secret into the "VERIFY SIGNATURE" section on jwt.io and the "Encoded" token section changes, hence resulting with an invalid signature and a invalid (i.e. different) token.
My core question is what am I missing here? Why does the token change when I apply the expected secret!? Am I applying the right secret, the one from the client? If I understand JWT infrastructre and standard correctly then It should stay the same if the secret (with the expected algorithm applied) is valid. My reasoning is that something with JWT creation on KeyCloak is specific. I have not touched the HS256 algorithm provider on KeyCloak, everything is used as default with the docker installation guide on using KeyCloak. The settings related to the token and algorithm are setup to use HS256, and the algorithm is specified as expected in the JWT's header section correctly which can be verified after the encoded token is pasted into the jwt.io's page.
I need this to work as I am trying to apply the same JWT validation process inside a .NET Core web API application. I have encountered this whole issue in there, i.e. inside the System.IdentityModel.Tokens.JWT and the JwtSecurityTokenHandle.ValidateSignature method which results with an invalid signature and finally resulting in an exception.
On side note, I am accessing the token with Postman and its Authorize feature the configuration can be seen on the image below:
One more side note is I have a user "John" which belongs to my "Demo" realm. I use him to request an access token from KeyCloak.
To get the secret used for signing/verifying HS256 tokens, try using the following SQL:
SELECT value FROM component_config CC INNER JOIN component C ON(CC.component_id = C.id) WHERE C.realm_id = '<realm-id-here>' and provider_id = 'hmac-generated' AND CC.name = 'secret';
If you use the resulting secret to verify the tokens, the signature should match. I’m not sure if this secret is available through the UI, probably not.
Source: https://keycloak.discourse.group/t/invalid-signature-with-hs256-token/3228/3
you can try using Keycloak Gatekeeper.
If you want to verify that token in that way you need to change the Client Authenticator to "Signed JWT with client secret", otherwise you can use this "Gatekeeper" option. Here you can read more about it.

BizTalk 2016: How to use HTTP Send adapter with API token

I need to make calls to a rest API service via BizTalk Send adapter. The API simply uses a token in the header for authentication/authorization. I have tested this in a C# console app using httpclient and it works fine:
string apiUrl = "https://api.site.com/endpoint/<method>?";
string dateFormat = "dateFormat = 2017-05-01T00:00:00";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("token", "<token>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
string finalurl = apiUrl + dateFormat;
HttpResponseMessage resp = await client.GetAsync(finalurl);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
var rootresult = JsonConvert.DeserializeObject<jobList>(result);
return rootresult;
}
else
{
return null;
}
}
however I want to use BizTalk to make the call and handle the response.
I have tried using the wcf-http adapter, selecting 'Transport' for security (it is an https site so security is required(?)) with no credential type specified and placed the header with the token in the 'messages' tab of the adapter configuration. This fails though with the exception: System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
I have tried googling for this specific scenario and cannot find a solution. I did find this article with suggestions for OAUth handling but I'm surprised that even with BizTalk 2016 I still have to create a custom assembly for something so simple.
Does anyone know how this might be done in the wcf-http send adapter?
Yes, you have to write a custom Endpoint Behaviour and add it to the send port. In fact with the WCF-WebHttp adapter even Basic Auth doesn't work so I'm currently writing an Endpoint Behaviour to address this.
One of the issues with OAuth, is that there isn't one standard that everyone follows, so far I've had to write 2 different OAuth behaviours as they have implemented things differently. One using a secret and time stamp hashed to has to get a token, and the other using Basic Auth to get a token. Also one of them you could get multiple tokens using the same creds, whereas the other would expire the old token straight away.
Another thing I've had to write a custom behaviour for is which version of TLS the end points expects as by default BizTalk 2013 R2 tries TLS 1.0, and then will fail if the web site does not allow it.
You can feedback to Microsoft that you wish to have this feature by voting on Add support for OAuth 2.0 / OpenID Connect authentication
Maybe someone will open source their solution. See Announcement: BizTalk Server embrace open source!
Figured it out. I should have used the 'Certificate' for client credential type.
I just had to:
Add token in the Outbound HTTP Headers box in the Messages tab and select 'Transport' security and 'Certificate' for Transport client credential type.
Downloaded the certificate from the API's website via the browser (manually) and installed it on the local servers certificate store.
I then selected that certificate and thumbprint in the corresponding fields in the adapter via the 'browse' buttons (had to scroll through the available certificates and select the API/website certificate I was trying to connect to).
I discovered this on accident when I had Fiddler running and set the adapter proxy setting to the local Fiddler address (http://localhost:8888). I realized that since Fiddler negotiates the TLS connection/certificate (I enabled tls1.2 in fiddler) to the remote server, messages were able to get through but not directly between the adapter and the remote API server (when Fiddler WASN'T running).

How to verify a shopify webhook request in asp.net

Can someone explain how do I compute a HMAC
===============
To verify that the request came from Shopify, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Shopify-Hmac-SHA256 header. If they match, you can be sure that the Webhook was sent from Shopify and the data has not been compromised.
Each Webhook request includes a X-Shopify-Hmac-SHA256 header which is generated using the app's shared secret, along with the data sent in the request.
I have the secret key... how can I combine the secret key + the data in the request to generate a HMAC
The easiest way is to use the ShopifySharp Library. You can use the Nuget package and install it in your project.
This is an example taken from the ShopifySharp website for validating webhooks:
NameValueCollection requestHeaders = Request.Headers;
Stream inputStream = Request.InputStream;
if(AuthorizationService.IsAuthenticWebhook(requestHeaders, inputStream, shopifySecretKey))
{
//Webhook is authentic.
}
else
{
//Webhook is not authentic and should not be acted on.
}
If you don't want to use ShopifySharp, you can see how they implemented it in the source code.

How to allow secure login across multiple domains

I have a web based application that allows a user to point their DNS at my IP and my app will serve up their content based on the domain name I see in the HTTP host header. I should point out this is done by the application, not by the actual HTTP server(apache), it is a rebranded app sort of thing. The problem I have is that I would like the users to be able to login through a form on the served page and somehow stay within the domain of the user. This is easy, unless you want security. I would have to have a SSL cert installed for every domain to pull this off. Right now I can do it by submitting the form to a domain with an SSL cert installed, but due to browser security I can't exactly set the required cookies on the original domain.
Does anyone know a way I can securely log in users through the app that does not involve installing a lot of ssl certs. I can think of some convoluted ways using redirects or other mechanisms, but it is not that clean. I don't mind a submit to the secure url and a redirect, it's just setting the cookie can't be done.
I've done this before using the following method...
Create auth key on server 1.
create_auth_key
expires = time + expire_time
data = username + '|' + password + expires
secret = 'my secret key'
hash = md5( data + secret )
key = base64( data ) + hash
On server two you pass the newly created authkey
valid_auth_key(key)
hash = key[-hash_size:]
b64data = key[:-hash_size]
data = base64decode( b64data )
data_hash = md5( data + secret )
if data_hash != hash:
return false # invalid hash
data_parts = data.split('|')
user = data_parts[0]
password = data_parts[1]
expires = data_parts[2]
if now > expires:
return false # url expired
return true
It's kind of quick and dirty but only relies on simple data passed via URL. The down side is that a specific url is all that's required to login and someone could share that url for a period of time. You also have to make sure your expiration time is not greater than the time difference between servers.
A common trick is to pass data in the URL. Facebook Connect does this. You can redirect from one domain to the other with a session token in the URL and then verify the token (perhaps convert to a cookie) when the request comes in on the other domain. Edit: the MSDN article that Facebook links to has much more detail.

Resources