I signed a jwt in nodejs with the below snipet.
var jwtoken = jwt.sign({ email: 'test#test.com', name: 'test' }, 'abcd');
I got the below token after signing
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJuYW1lIjoidGVzdCIsImlhdCI6MTYzNjE4MjYwOX0.07FXjm1lKEIiU_QOMEEOFzhsC0vtKt4PFoW-7YHHzyM
I wanted to verify this with jwt.io when I paste the JWT in jwt.io, I can see the the site says the "Signature Verified" for whatever key I provide(I dont need to provide abcd which is my actual key). I was expecting that the key would be required to determine if a signature is valid. How does the jwt.io determine if a jwt is valid without the original key.
The https://jwt.io debugger works in both directions, you can inspect and verify tokens or create and sign tokens. When you first paste your token on the left side and then paste the secret or key into the field under 'verify signature' in the right column, the signature will be recreated and you should notice that it changed. In this case, the result is always 'signature verified', because the signature was just calculated based on the entered secret.
The correct way to verify a signature is to first paste the key into the secret key field and then paste the token to the left part of the debugger. Always make sure, that any other content in the input fields is overwritten. If your key is actually Base64 encoded (i.e. a binary secret that is stored in Base64 encoded form), you should tell jwt.io by checking the "secret base64 encoded" checkbox.
Then the result, either 'signature' verified' or 'invalid signature', will be correct.
Every secret that you enter after that causes a recalculation of the signature and then it's always verified (with the new secret). Also clicking on the "secret bas64 encoded" checkbox causes recalculation.
But if you do it in the right order, a wrong secret causes an "invalid signature" result:
Related
I'm writing a shell script that will send email which has a link for application. When the user click link on the email, it will open the application. How to hide query parameters in the URL that was sent from shell script?
It doesn't make sense to hide URL / query string in any way; since if the user can open the URL, then the user must be able to read the URL. When you show that you have something to hide, curious users WILL try to find what and why are you hiding things.
sensitive information (confidential)
If what you're doing is sending something sensitive (ex: password), then just don't send it via email. Instead send some one-time-use token that expire after a day (assuming your email recipient will always read your email in a day). Format of such token can be JWT (see https://jwt.io for reference). For example:
instead of:
click here to login: https://yourapp.com/login?username=user&pass=user123
use these:
click here to login: https://yourapp.com/login?username=user&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTY0MzkwMjJ9.WkfqJZ3t0basNIqnRJD8R720BXmULhEONNlpHVxgoqA
Make sure you signed the JWT with a private key that only you know.
This way you're not exposing user's password just to prove that you're that user. The JWT in my example only contains claim that bearer of this token is named "user", and the token only valid from "iat" to "exp" field. (try copy-pasting the JWT above to jwt.io or decode it yourself).
If you're using this approach, you must also tell the users not to share their URL since other may impersonate them if they do.
identity
If what you're doing is sending something to prove who the user is, and it would be bad to be seen by other people because if they see it they can impersonate the recepient user, then you can send some hashed salt of the user's username or id. For example:
instead of:
click here to login: https://yourapp.com/login?username=user
use these:
click here to login: https://yourapp.com/login?username=3f480e2ceaf459b732f07b1b60a7ea16d1cd3244ef390ade01f401ad7b170445e08fb0b3583bb66210efc0fbe747c730f36f962de3cac07e6a165a80cb84def6
The hash in my example is sha512 digest of user some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123 some long long salt here 123
When your application read those hash, it can do a query to it's database like SELECT ... WHERE $urlparam = SHA512( CONCAT( username , '$salt' ) )
Same with above approach, you must also tell the users not to share their URL since other may impersonate them if they do.
long / large data
If what you're doing is sending very long/large data, and/or you do not want the user to change that data (ex: shopping cart data). Then you have to save it into database instead, and only send primary key / id of the record in URL. For example:
instead of:
click here to checkout: https://yourapp.com/checkout?username=user&cart1=myproduct1&cart1qty=20&cart2=myproduct2&cart2qty=50&cart3=myproduct3&cart3qty=99&cart4=myproduct4&cart4qty=1...(still continue)
use these:
click here to checkout: https://yourapp.com/checkout?cartid=1372384
This way, even if the user knows that his/her cartid is 1372384, it doesn't means anything for him/her. Of course this approach should be combined with some means of authenticating the user (otherwise some malicious user can see other's cart by entering random number or by guessing it)
lazy answer
If you just want to hide the URL no matter why, just use some strong encryption algorithm like AES256 to encrypt all query parameter, and then encode it as base64 (or url safe base64). In this case, your application (that read/handle the URL) and your script that generates the URL will have to share a same encryption key.
You will probably end up with something like: click here to do something: https://yourapp.com/handle?ciphertext=ZTZKU1RFUmZqNTZrSWszeWYwaEtiM0RWVzRRNWlFcE1lalpCbWFBM3Z5TEY1R0xYdGprVDRsSmk5Nzc4Y3dXamJ4RUpLYmRxZ2RXS0lLM01oMUc1U0t2dUFlWktldERoVHdzcjl6SS9CMmZuRmtoQnBMVmtEeFFhaXhIUHZwVFM2MlQ0SURRZEpMNzZ0bUptN2p3M0VuT0tMME15RW8xcG5ZSW5hcnpFUm1qSlBWWEhEYVNMcU42VFd5WFdDWmFsQXJaWDNpT0xrMWhpNFN2aXI3RjE4dz09
I have two questions concerning ASP.Identity 2.0 "GenerateEmailConfirmationToken/GenerateEmailConfirmationTokenAsync" methods.
// Generate token
var token = Url.Encode(await UserManager.GenerateEmailConfirmationTokenAsync(user.Id));
Is this token stored in the database? I guess it should. But in which field? I just find "PasswordHash" and "SecurityStamp" on the User table. Both don't seem to match.
I was under the impression that once I generate an email token, the EmailConfirmed field of the User table would be set to false. But it stays true. So, what is the purpose of creating a token if the corresponding user account stays confirmed? Or in other words: What do I need to do in order to generate a new token AND also set the account to NOT confirmed?
To summarise the discussion in comments: tokens are not stored anywhere - they are crypto-generated (not exactly sure about exact process of generation) from SecruityStamp and when they are coming back, they can be de-crypted and compared.
As for EmailConfirmed field - this is for you to maintain and look after. You'll manually need to deny login for users with no confirmed email. And you'll need to set the flag when email confirmation does come through.
There's a strange tradition to ask user to re-enter his password when the registration form has failed the validation.
E.g. the CAPTCHA value was wrong and now the password field is empty: users have to re-enter it.
What's the reason for that? Is it really that unsafe to put the password back to the input, even through HTTPS?
Putting a value in the password input field would require it being in plain text in the html source.
An email confirmation gets sent when my website users making a booking. I have been requested to add a "Having trouble viewing this email?" link to the top which links to the email on the website.
I'm having trouble wondering how I should generate a link so the user could view this email.
Note that I am using a third party booking system which gives me a confirmation code such as: 12345BE913913 where 12345 is the property and BE is always BE and 913913 is a secondary number.
I'm wondering if I could just hash this number and make that the link? Eg sha1('12345BE913913') which turns into 070bae598f481351e24975d6509fc0a73cad9a17
And then the link in the email becomes something like href="http://blah.com/email/view/070bae598f481351e24975d6509fc0a73cad9a17
Question #1: Is this a pretty standard, secure way of doing it?
If so, I have one other concern... I would need to pull in this information in order to generate the email in my email/view. The web service only accepts the confirmation code, so I would have to feed the original one, 12345BE913913 to it. So I can't simply grab all the confirmation codes, sha1 them all and see which one equates to 070bae598f481351e24975d6509fc0a73cad9a17.
Question #2: Is my only option to get the booking information through the webservice that accepts the original confirmation code, to create a local database storing all the confirmation codes, and then get all of them SHA1'd and see if it equates to 070bae598f481351e24975d6509fc0a73cad9a17 to pull it up? It's not safe to use the actual confirmation code in the email, is it?
Why not pass both the confirmation number (as the primary key) and a MAC associated with it (to prevent people from guessing URLs.
URL Generation Pseudocode:
$mac = HMAC_SHA1($server_secret, $confCode);
$url = "http://$baseURL?conf=$confCode&m=$mac";
Email Display Pseudocode:
$mac = getParam("m");
$confCode = getParam("conf");
$expectedMac = HMAC_SHA1($server_secret, $confCode);
if($mac != $expectedMac) { # Or in real perl, ne instead of !=
return errorPage();
}
return email($confCode);
Why use SHA1 if you need the operation to be reversible? Why not instead encrypt it using a symetric algorithm such as Twofish to generate the URL. You can decrypt it on the server side using your key to recover the original confirmation code, then send the confirmation code to the 3rd party booking system. Since nobody else has your key, nobody else can recover the confirmation code.
Hashing the real identifier, and storing the hash as the key in a table to the original value for "reverse lookup" is a conventional approach.
That isn't the only option, however. You could encrypt the confirmation code. Since the confirmation codes are short and, and (I'm presuming) unique, it would be alright to use ECB mode with a block cipher, which would keep the resulting cipher text short (16 bytes instead of SHA-1's 20 bytes).
The caveat with ECB is that the same confirmation code will always produce the same cipher text. Most likely, a code is only sent in a single email; but, if it is sent more than once, an attacker would be able to determine that the email relates to the same confirmation code (but they wouldn't be able to determine the confirmation code itself).
I'm not sure what you mean by "safe". What can someone do with the confirmation number? Would they be able to use the hash to get the confirmation number from your site? Unless you use S/MIME (or PGP), an email is not private; assume an attacker can read email.
I have clear the process to sign a document. You need a certificate made by a CA. You have a public and private key. With the private you sign and with the public the people open your signed document. When you sign a document a math algoritm process the file and then generate a hash, later with the private key this hash is encrypted. Finally I need to add (concat) this encrypted hash to the document.
Now, to open this document I need to separate the encrypt hash code from the document. And I need the public key to verify the validity of the document. This is very clear for me.
So.. The questions is... From where the people get the public key??? And how I check who sign the document??
Do I need to append my certificate to the document that I want to sing??
If It's true. Is that not insecur??? give my certificate to everyone??
thanks,
What you are asking about is a public-private key cryptosystem. In RSA (one particular such system), the "public" and "private" keys are actually just two numbers that are prime factors of a larger number. Due to how modular exponentiation works (I'm not going to explain the math), the effect is that:
Anything encrypted with the "public" key can be decrypted with the "private" key
Anything encrypted with the "private" key can be decrypted with the "public" key
It works both ways. Now, after generating the pair, you keep one of them. That's the "private" one. To the other half, you add some identity information. In the case of X.509 (one particular certificate format), you add a "common name" and some auxiliary information like a date of creation. This is added to the "public" half of the certificate. This half of the certificate, the public key, you distribute somehow.
In the case of document signing, the distribution method is usually that you attach the public key. "Who signed the document" is answered by the X.509 certificate "common name" field. This will look something like "cn=Joe Blow, o=Widgets Inc, l=Washington, st=DC, c=US". You aren't giving the "certificate" to everyone - just the public portion. All that lets people do is:
Verify your signatures
Encrypt messages in such a way that only you can decrypt them
This doesn't let people forge messages so that they appear to be from you.
The hash is not "concatenated" to the document. Various data signing standards (PKCS#7, CAdES for generic data, XMLDSig for XML, PDF specification for PDF documents) describe different ways to incorporate signature data into the output file. All of these formats allow you to include the public key (usually X.509 certificate) together with the data for verification. And the goal of verifier is also to check whether the key itself is valid. Alternatively, the user might be supposed to know the public key.