Send bcrypt hash as parameter - url

I want to send a bcrypt hash with random hash as a URL parameter. For example
hash=$2y$10$SWNoIGJpbiBkYXMgU2Fsd.t/I3wS/nUqo5eRQp8b7oakL/kQlZ5da
So my questions are:
Is this a good idea or should I remove the salt from the hash? How can I do this? Is the first dot every time the delimiter?

You really shouldn't be putting someone BCrypt'd password out on the wire. Even though BCrypt is hard to brute-force; it's better to not make it easier for someone to get ahold of it.
I suggest, as user33888366 did, that if you need a kind of security token, use the HMAC of values in the url.
Read Life in a post-database world: using crypto to avoid DB writes for examples of using crypto to trust your urls.
Short version
http://myapp.com/resetPassword?userId=johnnysmith&expirationTime=1356156000&token=%SECURITYHASH%
where %SecurityHash% is the HMAC hash of:
userId
reset expiration time
bcrypt hash
When the URL comes it, parse it:
userId=johnnysmith&expirationTime=1356156000&token=%SECURITYHASH%
^^^^^^^^^^^ ^^^^^^^^^^
and recalculate the HMAC of:
johnnysmith
1356156000
johnnysmith's bcrypt hash
if it matches the passed security token, you know you have a valid request.

Related

What length does a unique key need to be secure and reliably unique?

I'm looking to generate a unique key/token for my Invites model. Example usage:
mysite.com/invites/XXXXXX
Where XXXXXX is the unique key/token... I'm using Rails 5 for my API and learned Rails 5 has a new way to generate a secure token like so:
Model
has_secure_token :access_token
The current Rails method creates a very LONG, unfriendly token: 973acd04bc627d6a0e31200b74e2236
My question: Does the token really need to be that long for a model like Invites which expire, meaning tokens are not permanent. Ideally I believe the UX is better with a shorter length token so the token doesn't appear like a bug to a user.
Does anyone know of any recommendations on token length for non-permanent tokens like invite URLs?
Does the token really need to be that long
Well it doesn't always need to. Normally in Rails we use SecureRandom to generate such unique tokens. You can always get the tokens of desired length like below and use those.
SecureRandom.hex(10) # => "52750b30ffbc7de3b362"
SecureRandom.hex(3) #=> "71edbe"

Implementing SagePay Form Integration with Ruby on Rails

I'm using SagePay's form integration method with a Ruby on Rails/EmberJS app. I'm handling all the complex payment construction in Rails.
In short, SagePay needs an encrypted, encoded 'crypt' string, which contains data such as the user's billing address, the amount, post-payment redirects, and other transaction data.
SagePay gives an encryption password in the test environment. The form integration guide says to build the crypt as a string, then encrypt it using AES-256 and the encryption password, then Base64 encode the string for POSTing to the Sage test payments server.
Here's how I've implemented this (using the Encryptor gem):
def encryptandencode(string)
salt = Time.now.to_i.to_s
secret_key = 'test-server-secret-key-from-sage'
iv = OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
encrypted_value = Encryptor.encrypt(string, :key => secret_key, :iv => iv, :salt => salt)
encoded = Base64.encode64(encrypted_value).encode('utf-8')
return encoded
end
where string is the unencoded, unencrypted Crypt string containing transaction data.
The problem
Encryptor refuses to use the given secret key. It says the key is too short.
What am I missing here?
I'm struggling to do the same thing in ASP.NET. I don't know why the example 'Integration Kits' they give you on the website are so complicated. They may represent elegant pieces of code in themselves, but they obfuscate how things are working by having functions call functions call methods using settings in the web.config file. For developers new to this API a simple example with all the code in one place would be helpful.
ANYWAY, I still haven't got it working but I have managed to overcome the problem you're having, though my method may not help you since I'm working in ASP.NET. I added a reference to the SagePay.IntegrationKit.DotNet.dll to my project, after which I was able to call the function
SagePay.IntegrationKit.Cryptography.EncryptAndEncode(<name=value collection>, <Encryption Password>)
I now appear to get a valid encrypted string to send to SagePay, my problem is that their website says the encryption is wrong, so this is still a work in progress.
I was struggling with this too, and receiving the same error message.
I finally decided to try each line from the Encryptor gem directly and no longer received that error message. Therefore I have ditched that gem from my Gemfile.
BTW, you have a few things wrong in your example:
you need to use 128 bit encryption, not the default 256: :algorithm => 'aes-128-cbc'
the initialisation vector needs to be the same as the key: :iv => secret_key
you mustn't use a salt
the result needs to be hex encoded not Base64
result = encrypted_value.split('').map { |c| "%02X" % c.ord }.join
The Test and Live Encryption password differ also check your encryption password is 16 characters in length.
Sage Pay Support

encrypting session information in rails

By default, rails uses cookie storage for session information. The tutorial I followed said that it was the best way and super fast, and that it all gets encrypted. But when I base64 decode the cookie content, I can see my session info there. It's mixed into a lot of garbled characters, but it's there.
What am I missing here?
Doesn't rails use that secret token thing to encrypt the info in the cookie? How can I make it do so?
Rails uses a secret token to sign the session. The raw data is still there, but changing it will cause it to not match the signature any more, and Rails will reject it. The cookie string looks like session_data--signature, the session data is a base64-encoded marshalled object, and the signature is HMAC(session string, secret token).
The general assumption of the session data is that it is not secret (since it generally should contain only a few things, like a CSRF token and a user ID), but it should not be changeable by a user. The cookie signing accomplishes this.
If you need to actually encrypt the data so that users could never see it, you could do so using something like OpenSSL symmetric encryption, or you could switch to a non-cookie data store.
This is a variant on my own app's cookie store; I haven't tested it, but in theory this should generate actually-encrypted cookies for you. Note that this will be appreciably slower than the default cookie store, and depending on its runtime, could potentially be a DOS vector. Additionally, encrypted data will be lengthier than unencrypted data, and session cookies have a 4kb limit, so if you're storing a lot of data in your session, this might cause you to blow past that limit.
# Define our message encryptor
module ActiveSupport
class EncryptedMessageVerifier < MessageVerifier
def verify(message)
Marshal.load cryptor.decrypt_and_verify(message)
end
def generate(value)
cryptor.encrypt_and_sign Marshal.dump(value)
end
def cryptor
ActiveSupport::MessageEncryptor.new(#secret)
end
end
end
# And then patch it into SignedCookieJar
class ActionDispatch::Cookies::SignedCookieJar
def initialize(parent_jar, secret)
ensure_secret_secure(secret)
#parent_jar = parent_jar
#verifier = ActiveSupport::EncryptedMessageVerifier.new(secret)
end
end

Creating Signature and Nonce for OAuth (Ruby)

I'm looking to access SmugMug's API from my application to grab users' albums and images (the users have been authenticated via ruby's OmniAuth).
According to SmugMug's OAuth API, OAuth requires six parameters.
I can get the token with OmniAuth, and the timestamp should be easy (Time.now.to_i right?). There are two things that I don't know how to generate -- the oauth_nonce and the oauth_signature.
According to the oauth docs, I generate the nonce via the timestamp, but how exactly would I do that? Does it need to be a certain length and limited to certain characters?
And of course the signature. How would I generate a HMAC-SHA1 sig with ruby? I know the oauth gem can do it, but I'd rather generate it myself to use with OmniAuth. Looking at the code, I'm having trouble deciphering how the oauth gem generates the sig.
Thank you for any help.
For the signature:
def sign( key, base_string )
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, key, base_string )
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
end#def
You don't have to generate the nonce from the timestamp, but it can make sense since the timestamp is obviously unique, so it makes a good starting input for any randomisation function.
I use this, (that I got from another question on here and modified)
def nonce
rand(10 ** 30).to_s.rjust(30,'0')
end#def
but you can use anything that generates a unique string.
See this gist by erikeldridge on github and Beginner’s Guide to OAuth for more
Edit
I've since found there's a better way to generate random strings in the Ruby standard library, SecureRandom.
A nonce can also be simply a large-ish, properly random number - for example, using Ruby's SecureRandom class (don't use 'rand'):
require 'securerandom'
...
nonce = SecureRandom.hex()
This generates a 16-byte random number in hex format.
Why you don't just use the Oauth ruby gems to do that ?

Generate temporary URL to reset password

I am looking to implement a Forgot Password feature on my website. I like the option where an email containing a temporary one-time use URL that expires after some time is sent to the user.
I have looked at the following pages to get these ideas but I am not sure how to implement this using ASP.NET and C#. As one of the users indicated, if I can implement this without storing this information inside the database, that will be ideal. Please advise.
Password reset by emailing temporary passwords
Thanks.
Probably the easiest way is going to be to modify your users table to add 2 extra columns, OR if you don't want to modify the existing table you could add a new dependent table called "UserPasswordReset" or something like that. The columns are like this:
PasswordResetToken UNIQUEIDENTIFIER,
PasswordResetExpiration DATETIME
If you go with the additional table route, you could do also add the UserID column, make it a primary key and a foriegn key reference back to your users table. A UNIQUE constraint would also be recommended. Then you simply use a Guid in your asp.net application as the token.
The flow could be something like this:
User requests password reset for their account
You insert a new record in the table (or update their user record) by setting the PasswordResetExpiration to a date in the future (DateTime.Now.AddDays(1)), and set the token to Guid.NewGuid()
Email the user a link to your ResetPassword.aspx page with the guid in the query string (http://www.yoursite.com/ResetPassword.aspx?token=Guid-here)
Use the ResetPassword.aspx page to validate the token and expiration fields. (I.E. Make sure DateTime.Now < PasswordResetExpiration)
Provide a simple form that allows the user to reset this password.
I know you wanted to avoid modifying the database, but it really is probably the simplest method.
#Alex
You can also use System.Security.Cryptography classes in .NET for the hash algorithms. For example:
using System.Security.Cryptography;
...
var hash = SHA256CryptoServiceProvider.Create().ComputeHash(myTokenToHash);
...
Here, the System.Guid class in your friend, as it will generate a unique (well, unique enough) 128-bit number:
Generate a new Guid ( System.Guid.NewGuid() )
Store that Guid somewhere (Application object maybe?)
Send a custom URL in an email with that Guid
When the user hits the site, make them enter the password you sent in the email
If the passwords match, go ahead and force them to enter a new password
I used a Hashing Class to create unique automatic logins made up of the current date/time and the users email address:
string strNow = DateTime.Now.ToString();
string strHash = strNow + strEmail;
strHash = Hash.GetHash(strHash, Hash.HashType.SHA1);
get the Hash Class from: http://www.developerfusion.com/code/4601/create-hashes-md5-sha1-sha256-sha384-sha512/
Then just take it from the URL using:
if (Request.QueryString["hash"] != null)
{
//extract Hash from the URL
string strHash = Request.QueryString["hash"];
}
I would definitely include the database in this process. Once a reset is requested, it's a good idea to indicate that the account is locked out.
For example, if you are changing your pw because you think your account may have been compromised, you definitely don't want it to remain accessible while you go about the change process.
Also, inclusion of "real" information in the reset token could be decoded if someone really wants it and has the horsepower. It would be safer to generate a random string, save it in the db in the row for that user, and then key back to it when the link is clicked.
This gives you two things:
1) There's nothing to decrypt, and therefore nothing of value can be gained from it.
2) The presence of the token in the user record indicates that reset is in progress and the account should be treated as locked out.
The goal of sending some data|string to user email is validation of account owner. Please care about some points:
Avoid sending important information in reset or activate link.
It's best way to store unique string data conjunction with user
account and send it as that link. but be aware if you send just one
section as link to user email and just check it in page, your
application may be in dangerous by brute-force or dictionary
attacker. It's enough to check a list of string to find some links
and change password. I know that has a little chance, but not zero.
Result:
I think it's better if you
combine user email with string link then encrypt them
(not hash because hashed value can't be reverse) and send to user
email.
User click and your page get the encrypted value.
decrypt value.
extract user email.
find email in database.
compare string from received link with other one attached to user
email in database.
Good luck.
I'd use a hash code to validate details in the password reset url. This can all be done without writing anything to the DB or sending any privileged info to an attaker.
To briefly explain normal password salt and hashing; say the salt is 1111 and the pasword is password, you'd concatenate the two and hash the string 1111password, say this gives you a hash of 9999, you'd then store the original salt 1111 and hash 9999 in your user record.
When you are validating a password you use the stored salt, concatenate the password attempt, hash it and compare with the stored hash. For example asecret becomes 1111asecret but hashes to 8888. This doesn't match the original hash so the password match fails.
Of course the salt and hash would normally be properly generated and calculated with established crypto libraries (don't invent your own!).
For the password reset URL I'd put in the unique identifier for the user, i.e. email address, the date the request is made, and a new hash. This hash would be generated from those details concatenated together plus the salt and hash already stored for the user.
For example:
Email: user#example.com
Request Date: 2014-07-17
Salt: 1111
Hash: 9999
Generate a new hash of those concatenated, i.e. 'user#example.com2014-07-1711119999', say this gives a hash of 7777.
The URL I then generate would then have the email, request date and the new hash:
https:\\www.example.com\ResetPassword?email=user#example.com&requestdate=2014-07-17&hash=7777
The server will combine the email and supplied date with it's salt and hash and confirm the hash it generated is the same as the supplied one. If this is Ok then it will show the reset form with the same three parameters hidden behind it, otherwise an error. These get resubmitted and rechecked when the new password is entered to prevent that form being spoofed.
The email address needs to be supplied to make the request and it is only sent out in an email to the same address. the date is hardly priveleged info and the hash is not reversible so gives nothing anyway. Nothing has been written to the database and any tampering with the parameters causes the hash to fail and the URL to report an error.
There is an issues with this approach. A safe hash makes the token really long. Either you integrate the salt into the hash itself (makes it about 20 charactes longer), or you store this unique salt in the database. If you store the salt in the database, you could as well store a random token which is not derrived from any existing
Depending on your needs, you could encrypt information, in a format similar to the following format
(UserId)-(ExpireDate)
Encrypt the data, make that the link, then decrypt the data and take action from there...
Crude, but most likely usable, and not requiring DB usage

Resources