Are Json Web Tokens secure enough? And how to secure payload? - cryptography

When I go to https://jwt.io I see this encoded token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
If I go to https://codebeautify.org/base64-decode , copy-paste token value and push Decode, I get this:
{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"John Doe","iat":1516239022}
If I switch from HS256 to RS256, I now get this token:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM
And it also can be easily decoded with base64. So, my question is, whether it is expected behaviour or not? And if yes, what is the reason to use different algorithms (HS256, RS256 etc.), if whatever algorithm we use, we can easily read the contents using just base64 decode?

Well Jwt is not meant to secure the content it is used to verify a claim, ie when you sign a request using jwt, when decoding it the user/sytem must have the secret key. So to answer your question yes it is the expected behaviour, the base 64 encoding is only meant for transportation over the URL and not to secure it. The last bit if i may clarify the verification of a claim is simply to mean you are what/who you tell the system you are and that the content of the signature has not been altered even alittle bit, any changes to any part of the encoded signature will result to signature failure; hence the claim would nolonger be authentic or true. To see this just try to encode something like this in your terminal
import jwt
encoded=jwt.encode({'name':'some name'}, 'somesecretkey',algorithm='HS256')
then copy the resulting token and then remove or add asingle letter to the string and try decoding using the same secret key and watch it fail or try the same at codebeautify again

Related

Can you modify the header of a JWT token after it is created (after it is encrypted and signed)?

I know that a JWT token contains a header section that is BASE64 encoded.
Scenario:
Decode the header
Change the value of one of the parameters present in header, like for example kid parameter
Encode the modified header
Replace the initial encoded header with the new encoded header in the JWT token
Questions
Will the token still be valid?
Or when it is initially signed, the header is also considered when creating the signature, thus if after that you modify the header, the token is considered invalid?
For a signed token (JWS), the signature is computed using the payload AND the header.
If you alter the header or the payload then the signature part becomes invalid.
You can give it a try at https://jwt.io/
Please note there was a known attack that consisted into a modification of the signature algorithm to none and the signature itself allowing payload modification without warning for vulnerable libraries.
Refer to this detailed article for more information.
Yes. You can try this site, if want to modify from an existing token: https://token.dev/
Someone can not change the header/payload unless has the secret key. if he/she has the secret key they can change the JWT token.
For instance, if you are using nestjs to register JwtModule you have to read the secret key from the config file to avoid revealing the secret key. as below
JwtModule.register({
secret: 'read this from config file',
signOptions: {
expiresIn: 60 * 1000
}
}),
For more information, you can watch this video

Why do we have to specify server-side encryption in the http header?

This article in the AWS Developer Blog describes how to generate pre-signed urls for S3 files that will be encrypted on the server side: https://aws.amazon.com/blogs/developer/generating-amazon-s3-pre-signed-urls-with-sse-kms-part-2/ . The part that describes how to generate a url makes sense, but then the article goes on to describe how to use the url in a put request, and it says that, in addition to the generated url, one must add to the http request a header specifying the encryption algorithm. Why is this necessary when the encryption algorithm was included in the url's generation?
// Generate a pre-signed PUT URL for use with SSE-KMS
GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
myExistingBucket, myKey, HttpMethod.PUT)
.withSSEAlgorithm(SSEAlgorithm.KMS.getAlgorithm());
...
HttpPut putreq = new HttpPut(URI.create(puturl.toExternalForm()));
putreq.addHeader(new BasicHeader(Headers.SERVER_SIDE_ENCRYPTION,
SSEAlgorithm.KMS.getAlgorithm()));
I ask in part due to curiosity but also because the code that has to execute the put request in my case is running on a different machine from the one that generates the url. I won't go into the details, but it's a real hassle to make sure that the header that one machine generates matches the url that the other machine generates.
I don't know how "clear" the justification is, but my assumption is that the encryption parameters are required to be sent as headers in order to keep them from appearing in logs that log the query string.
Why is this necessary when the encryption algorithm was included in the url's generation
This aspect is easier to answer. A signed request is a way of proving to the system that someone in possession of your access-key-secret authorized this exact, specific request, down to the last byte. Change anything about the request that was included in the signature generation, and you have invalidated the signature, because now the request differs from what was authorized.
When S3 receives your request, it looks up your secret key and does exactly what your local code does... it signs the request it received and checks whether its generated signature matches the one you supplied.
A common misconception is that signed URLs are generated by the service, but they aren't. Signed URLs are generated entirely locally. The algorithm is not computationally-feasible to reverse-engineer, and for any given request, there is exactly 1 possible valid signature.
It looks like the information about encryption doesn't get included in the presigned url. I'm guessing the only reason it's included in the GeneratePresignedUrlRequest is for generating a hash that's checked for authentication. After reading up on the question of when to use url parameters vs custom headers, I have to wonder if there is any clear justification for S3's using custom headers instead of url parameters here. As mentioned in the original question, having to include these headers makes using this API difficult. I wouldn't have this problem if url parameters were used instead. Any comments on the matter would be appreciated.

proof of API response

Let's say I have access to an https weather API.
Let's say I query its health status on thursday 17/08/2017 23h30 and the API replies OK (simple OK http code).
As a client, I need to prove in the future that the service actually responded me this data.
I'm thinking to asking the API to add a crypto signature of the data sent + timestamp, in order to prove they actually responded OK at that specific time.
Is it overkill? Is there a more simple way of doing it?
A digital signature containing current date/time or even adding a time stamp issued by a third party time stamp authority is an appropriate way to ensure that the content was actually issued on a date
In general, implementing a digital signature system on HTTP requests is not so simple and you have to consider many elements:
What content will you sign: headers, payload, attachments?
Is it binary content or text? Because the algorithms and signature formats will be different
In case of text you must canonicalize the content to avoid encoding problems when you verify the signature on the client side. Also you need to define a signature algorithm to compute the content to sign
Do you also need to sign the attachments when they are sent via streams?. How are you going to handle big files?
How are you going to attach the signature to the https response: special header, additional attribute in the payload?
How is the server going to distribute the signing certificate? You should include it in a truststore on the client
But, if you only want to proof that a service response was OK/FAIL, then the server just need to add a digital signature over the payload (or computed on a concatenation of the headers) but if you want to implement something more complex I suggest you take a look at the Json Web Signature (JWS)

What are the pros/cons of using JWE or JWS [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to implement an authentication token system, so I want to know the pros/cons of using JSON Web Encryption (JWE) or JSON Web Signature (JWS), and if it make sense to use both (a JWE inside a JWS).
JSON Web Signature (JWS) claims are signed with a signature that can be verified by the server with a secret signing key. This ensures that the claims have not been tampered with when passed between client and server. The contents of JWS token are Base64 encoded and not encrypted (remember encoding is different from encryption!). Base64 encoded data looks encrypted in that it looks like a garbage text but it’s actually trivial to turn back into readable data. Therefore it is always advised to not store any sensitive information in JWT. It is advisable to use JWT only when you want to exchange information between two parties (or between client and server) and no sensitive data is passed as payload in token.
But what if you want to include any private information in a token? You don’t want your sensitive information to be present in a token that is only Base64 encoded that can be easily decoded by any attacker. Fortunately, there is a way to encrypt and guard the claims data with another, a more secure level of protection known as JSON Web Encryption (JWE). It defines a way to encrypt your claims data (which is basically JSON based data structure) so that only intended receiver can read the information present in a token.
The best way to handle a web token is to:
Sign it, so that it is well known that the token originated from authorized client.
Encrypt it, so that only an authorized server can tell what it says.
We have couple of good libraries available in Java that can encrypt your JSON Web Token:
Jose4J
Nimbus-JOSE-JWT
Both the above libraries are open source (Apache 2.0) implementation of JWT and JOSE (Javascript Object Signing and Encryption) specification suite. They both are quality libraries and you can’t really make a wrong choice. However, JWT.IO has a nice UI to show differences of each available library.
A JWS is used to sign the data, making it integrity-protected, this means that:
Man-in-the-middle attacks can see the data for what it is
Man-in-the-middle attacks cannot modify it, since the signature verification would fail
A JWE is used to encrypt the data as well as make it integrity-protected
Man-in-the-middle attacks cannot see the data for what it is
Man-in-the-middle attacks cannot modify it, since the verification would fail
The aims between JWS and JWE are different.
A JWS is used to sign claims, a JWE is used to transmit sensitive data.
If you want to implement an authentication system, then JWS must be used to verify authenticity of claims.
You can also encrypt your JWS using JWE if some of the claims in your JWS contain sensitive information.
But use only JWE is a none sense in your context.

Is this a secure implementation of a basic HMAC authentication system for my REST API?

I'm building a very basic REST API for my site. The only verb I'm using at the moment is GET which simply outputs a list of posts on my site.
For authentication, I have been reading about HMAC and in particular this article:
http://websec.io/2013/02/14/API-Authentication-Public-Private-Hashes.html
My question centres around what the 'hashed content' should be. As I am not posting any data to the API, I have just been hashing my public key (with a simple salt) using my private key.
Is this a secure method or should I use a different 'content hash'? The data is not sensitive in any way - this was just a learning exercise.
You will want to consider the "replay attacker". When the attacker captures a packet between your API client and the server, what damage can she do when she replays it later?
In your case, if you only use the API key of the user in the HMAC, then the attacker will be able to impersonate that user when she replay the requests. She can call any API request and just set the HMAC to what she captured, as it will validate.
If none of the parameters of the request are included, the attacker will be able to call the request and specify her own parameters. So it's better if the parameters are also included in the HMAC. It doesn't prevent replay of the request with these specific parameters though.
You can include a timestamp parameter to the request and in the HMAC. The server will recompute the HMAC including the timestamp passed in, and it will also verify that the timestamp is recent enough. As the attacker cannot forge new HMAC out of thin air, she will only be able to use ones with matching timestamps that you will reject based on age.