In all of the reference pages I've found with regards to encrypting the ViewState, the only comment on the password is "your password here".
Are there any recommendations regarding the length / complexity of the password that we should use?
Depends on Mojarra version. It had several flaws/fails in earlier versions.
In Mojarra 1.2.x - 2.1.18, it was never actually used. The JNDI entry name was namely incorrectly documented. It was documented as com.sun.faces.ClientStateSavingPassword (with same prefix as Mojarra's other web.xml context parameters), but the code actually checks for ClientStateSavingPassword. You should then register it on that name instead.
<env-entry>
<env-entry-name>ClientStateSavingPassword</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>[Your Password]</env-entry-value>
</env-entry>
Otherwise, the client state is actually not encrypted.
In Mojarra 1.2.x - 2.0.3, the password will be used as a SecureRandom seed to generate a DES algorithm key. So, generally, the same rules apply as to "real world" passwords. Only, this can be easily compromised if the password is "too easy" and the attacker successfully guesses/bruteforces/figures the password.
In Mojarra 2.0.4 - 2.1.x, they changed the algorithm from DES to AES and the code now don't actually use the provided password anymore to generate the key (to prevent potential comprisions). Instead, a completely random key is generated, which is more safe. The JNDI entry now basically controls whether the client state should be encrypted or not. In other words, it behaves now like a boolean configuration entry. It thus absolutely doesn't matter anymore which password you use.
<env-entry>
<env-entry-name>ClientStateSavingPassword</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>[Any value is interpreted as boolean=true to enable encryption]</env-entry-value>
</env-entry>
In Mojarra 2.1.19 - 2.1.x, they fixed the code to align the documentation on JNDI entry name. So you could use the documented JNDI entry name:
<env-entry>
<env-entry-name>com.sun.faces.ClientStateSavingPassword</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>[Any value is interpreted as boolean=true to enable encryption]</env-entry-value>
</env-entry>
However, this still doesn't affect the AES key, which was changed since 2.0.4, it still basically only enables/disables the encryption.
In Mojarra 2.2.0 - 2.3.x, as part of JSF 2.2 specification (chapter 7.8.2), client side state is now by default always encrypted. It will only be disabled when web.xml context parameter com.sun.faces.disableClientStateEncryption is set with value true. It still uses AES algorithm with a completely random key. The JNDI entry com.sun.faces.ClientStateSavingPassword is now not used anymore.
In Mojarra 2.2.6 - 2.3.x, they added as per issue 3087 a new JNDI entry which allows you to specify the AES key in Base64 encoded format, the jsf/ClientSideSecretKey. This is part of the bugfix on failing client side state when a JSF webapp is used in cluster environment, because each server used a different AES key which would only cause a ERROR: MAC did not verify! when state is restored in a different server than the one which saved the state, as described in issue 2557.
<env-entry>
<env-entry-name>jsf/ClientSideSecretKey</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>
You can use this AES key generator to generate one (refresh the page to regenerate), or use below snippet to generate your own Base64-encoded AES256 key:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // Use 128 for AES128 (when server don't have JCE installed).
String key = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded());
System.out.println(key); // Prints AES key in Base64 format.
Related
I have a private key file encrypted with a password that also contains non-US-ASCII characters (e.g. passwörd or s€cret).
I didn't find a way to use this key file from an indy based server, as Indy seems to use MBCS to convert the unicodestring password to an octet string.
According to https://www.rfc-editor.org/rfc/rfc8018 (end of section 3) UTF-8 is a common encoding rule for password octet string.
According to my investigations Indy (I'm using the version that comes with Delphi 10.2 Tokyo) uses IndyTextEncoding_OSDefault inside PasswordCallback (IdSSLOpenSSL.pas) to convert the (Unicode)String to a PAnsiChar.
IndyTextEncoding_OSDefault() (in IdGlobal.pas) sets GIdOSDefaultEncoding to TIdMBCSEncoding and also returns it. GIdOSDefaultEncoding is not globally available and I also didn't find a method to set it.
Is there a possibility to either change the encoding PasswordCallback uses or already pass the password as byte array/PAnsiChar/RawByteSting to Indy?
There is no option to change the charset that Indy uses for encoding Unicode passwords. You would have to alter Indy's source code and recompile it. In a future version, I'll consider changing it to UTF-8, or make it user-configurable.
Note that IndyTextEncoding_OSDefault is MBCS only on Windows. It is UTF-8 on other platforms.
Otherwise, you would have to call OpenSSL's SSL_CTX_set_default_passwd_cb() function directly to replace the password callback with your own function, then you can do whatever you want with it.
This is in the view
<g:passwordField name="password" required="" value="${usuarioInstance?.password}"/>
This would be a part of the controller
pass = params.password.encodeAsSHA1()
This will be returned into the view again
${pass.password}
the ${pass.password} needs to change to text or decode the SHA1()
My advice:
don't use sha-1, it's insecure
don't unencrypt a password and display it in a form field. Make the user type it in if they want to change it, if they haven't entered anything then don't update that property
use spring security which by default manages all the headaches of web security and uses Bcrypt out of the box.
Security is something every dev needs to take seriously and if the client insists on unsecure practices then they need to be educated.
Edit: #zaph makes a good point below so I should add it - don't encrypt passwords. A password should never be able to be translated back into plain text. Always hash (and salt) them and compare the user input hash to the stored hash. If you choose not to use Spring Security, you can use Bcrypt standalone and use the static Bcrypt.checkpw(userInputPw, hashedPw) method to check it.
Final Edit: To avoid any confusion (since #zaph seems confused in the comments) my recommendation is to use Bcrypt - specifically, use Spring Security.
I'm following Apple's guide towards composing a CloudKit Web Services request. The bit I'm having trouble with is Step 2, under "Authenticate Web Service Requests":
Compute the ECDSA signature of this message with your private key.
Before getting to this point, I generated my certificate, a .pem file, which when opening it in a text editor shows me my private key, so I have that in string format too.
I've also followed the steps for generating what it refers to as a message, which I now have as a string.
So given that I have a private key, (or the .pem file if required), and a message as a string, it should in theory be fairly simple for me to get a ECDSA signature of the message, computed with my private key. But here's where I'm struggling. Libraries that I've found online seem to take a far more complicated approach, with different moving parts, no reference to a .pem file and talk of generating new public/private keys.
Any help with this step would be greatly appreciated.
It appears that the documentation and the actual API for Ruby’s OpenSSL EC support are both currently rather lacking. In particular, in Ruby <= 2.3.1 the OpenSSL::PKey::EC doesn’t follow the same API as RSA and DSA keys for signing and verifying. What you would want to do, but currently can’t with EC keys, is this (all the code here assumes you have called require 'openssl' somewhere):
# Get the key, here I'm reading the file
priv_key = OpenSSL::PKey.read(File.read('eckey.pem'))
# This should be the appropriately formatted string
data = "some data to sign"
# The hash algorithm, I assume SHA256 is being used
digest = OpenSSL::Digest::SHA256.new
# This doesn't work in 2.3.1, but does in 2.4.0-preview1
signature = priv_key.sign(digest, data)
As I note in the comments, this does work in Ruby 2.4.0-preview1, but that’s likely not much use to you.
To get it working with current Ruby, you need to do something like this:
# As before:
priv_key = OpenSSL::PKey.read(File.read('eckey.pem'))
data = "some data to sign"
signature = priv_key.dsa_sign_asn1(OpenSSL::Digest::SHA256.digest(data))
Both these techniques give you a binary string. I think you will need to base64 encode it before adding it as your request header.
To extract the public key to check the signature verifies is also a bit tricky (although you could just use the openssl command line and read in the file). The public_key methods returns an OpenSSL::PKey::EC::Point object rather than an actual key, so we need to recreate one from the private key. The verify method does work on Ruby 2.3.1:
pub = OpenSSL::PKey::EC.new(priv_key.group)
pub.public_key = priv_key.public_key
data = "some data to sign"
digest = OpenSSL::Digest::SHA256.new
puts pub.verify(digest, sig, data)
The Apple page doesn’t appear to specify the hash algorithm to use, but from what I’ve seen it looks like SHA-256 is right. (Also I could have got this completely wrong and Apple are using a completely different format. I’d be keen to know whether or not this code works you you).
I'm building a little token-based authentication library for my (rails based) api server which uses redis to store generated auth tokens. The line I'm worried about is: user_id = $redis.get("auth:#{token}"), where token is what's passed in to authenticate_or_request_with_http_token.
If this were SQL, that'd be a huge red flag - string interpolated SQL queries are pretty insecure. As far as I can tell, however, doing string interpolation on a redis key query isn't insecure.
My source for the above claim is the redis documentation here: http://redis.io/topics/security (under the string escaping and nosql injection header), but I wanted to make sure that this is the case before I get a Bobby Tables attack.
The documentation you are pointing to is quite explicit:
The Redis protocol has no concept of string escaping, so injection is impossible under normal circumstances using a normal client library. The protocol uses prefixed-length strings and is completely binary safe.
There is a small attack vector for these kinds of string injections. While the redis documentation is clear about the difficulty of executing multiple commands on the database, it does not mention that the key separator (':' in your example) usually needs to be escaped when used as the part of a key.
I have seen a redis database using these keys:
oauth_token:123456 (which contained a hash of OAuth token parameters) and
oauth_token:123456:is_temp (which contained a boolean property to indicate whether the OAuth token is a temporary token)
Trusting the user input without escaping might result in GET oauth_token:#{token} accidentally ending up as GET oauth_token:123456:is_temp (when token has been set to 123456:is_temp by the user).
So I highly recommend to properly escape colons from potential user input to make sure your key paths cannot be tricked like this.
NOTE: Someone recommended to fix the example above by using oauth_token:123456 and oauth_token:is_temp:123456, but that is flawed (for the user-provided token is_temp:123456). The correct solution to that problem (without escaping) would be to use keys oauth_token:info:123456 and oauth_token:is_temp:123456 to make sure these keys cannot overlap whatever the user-provided input was (or simply escape colons).
Basically Redis is immune from escaping issues when the input string is used verbatim. For example:
SET mykey <some-attacker-chosen-data>
However Redis is not immune from issues arising by using non validate input in the context of string interpolation, as showed by Sven Herzberg. In order to turn the Sven example into a safe one, it is possible to just use an Hash, and avoid reverting to interpolation. Otherwise either use not common prefixes to use in conjunction with keys interpolation, or use some basic form of sanity check on the input, which is, filtering away the separator used, or better, validate that the input is actually a number (in the specific example).
So while Redis does not suffer from the typical injection attacks of SQL, when used untrusted input in the context of a string interpolation used to create key names, or even worse, Lua scripts, some care should be taken.
I'm interested in url signing (e.g. http://.../?somearg=value&anotherarg=anothervalue&sig=aSKS9F3KL5xc), but I have a few requirements which have left me without a solution yet.
I'll be using either PHP or Python for pages, so I'll need to be able to sign and verify a signature using one of the two.
My plan was to use a priv/pub key scheme to sign some data, and be able to verify that the signature is valid, but here's where it gets complicated:
The data is not known when the verification is happening (it is not just somearg=value&anotherarg=anothervalue)
My first instinct was to use OpenSSL, e.g. with a RSA keypair, to do something along the lines of signing by: openssl rsautl -sign -inkey private.pem -in sensitive -out privsigned and verifying based on the privsigned data and key ONLY: openssl rsautl -verify -inkey public.pem -in privsigned -pubin.
Using PHP's openssl_get_privatekey() and openssl_sign() signs the data just fine, but I need to know the (decrypted!) data in order to verify (which I will not have): openssl_get_publickey() and openssl_verify($data, $signature, $pubkeyid); from http://php.net/openssl_verify.
Or am I missing something here?
So I looked into HMAC, but although many hash function are available in both Python and PHP, I'm baffled as to how I'd go about verifying the hash.
PHP's hash_hmac() allows me to create a hash using a "key" (or in this case a string-key). But how do I go about verifying that a hash is valid (i.e. &sig= hasn't just been manually put in by the end user &sig=abcdefg1234.
So to sum up (sorry for the long question): How can I verify that a signature/hash has been made by my server's (cert/string)key (given I can not verify by redoing the hash of said data)? And do you have any preferences as to which route I should chose, Priv/pub-key or HMAC?
Any pointers big or small is greatly appreciated!
Thanks in advance,
Josh
As Henning Makholm pointed out, HMAC is a better choice than public key. There are some best practices you should consider for your particular scenario that will impact your choices:
Do you want to consider the hostname and scheme (http/https) in the signature? Maybe.
Do you want to consider the path in the signature? Probably.
Do you want to consider the query string in the signature? Probably.
Do you want to normalize the argument order and escaping prior to signing? Usually not.
Do you want to embed signature time etc (to create time-limited URLs)?
Do you want to tie the signed URL to some other user state, such as cookie?
Are you using user-generated or user-visible content directly in the HMAC? If so, you should "salt" the key using a value that is randomized for each request.
When computing the signature, you'll need to encode it in a URL-friendly way (base64 and base32 are popular choices) and choose an HMAC algorithm (such as SHA-256), and decide how many bits of the signature you want to keep (truncating the HMAC value in half is usually safe). If you choose base64, beware of the different alphabets used by url-safe vs non-url-safe implementations.
Here is a pseudocode implementation (w/o error checking or salting etc) for signing path + query string:
const secret = ...;
def sign(path, querystring):
return path + "?" + querystring + "&sig=" + url_encode(base64_encode(hmacsha256(secret, path + "?" + querystring).truncate(16)))
def verify(path, querystring):
querystring_without_sig = remove_query_parameter(querystring, "sig")
sig = base64_decode(url_decode(get_query_parameter(querystring, "sig")))
if hmacsha256(secret, path + "?" + querystring_without_sig)[:16] != sig:
raise "invalid sig"
HMAC SHA256 is recommended and is available in all common languages.
Java:
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secret);
return mac.doFinal(value.getBytes());
Python:
hmac.new(secret, input, hashlib.sha256).digest()
PHP:
hash_hmac("sha256", value, secret);
HMAC is a symmetric algorithm, so there is no separate creation and checking algorithm. To check, you simply compute the hash as it should have been computed originally, and check that the result equals what you actually got from the client. The security rests on the HMAC key only existing on your server.
Unless you need the signatures to be verifiable by someone who doesn't know the secret key, HMAC is probably a better choice than public-key systems, for reasons of efficiency. It can take several milliseconds to create or verify a public-key signature (some years ago I timed one implementation at 15 ms per operation), whereas HMAC is quite fast.
(Oh, and you cannot verify any kind of signature without knowing the data it's supposed to sign. That wouldn't make any sense, as far as I can see).
If you want to use HMAC and Python, then:
$ pip install ska
On the client side
from ska import sign_url
signed_url = sign_url(
auth_user='user',
secret_key='your-secret_key',
url='http://e.com/api/'
)
Produced URL looks like as follows.
http://e.com/api/?valid_until=1378045287.0&auth_user=user&signature=YlZpLFsjUKBalL4x5trhkeEgqE8%3D
On the server side
Note, that in example below request.GET is given as example. It will most likely vary from what's used in your framework (unless you use Django).
from ska import validate_signed_request_data
validation_result = validate_signed_request_data(
data = request.GET, # Note, that ``request.GET`` is given as example.
secret_key = 'your-secret_key'
)
The validate_signed_request_data produces a SignatureValidationResult object, which basically holds two properties:
result (bool): True if data is valid. False otherwise.
reason (list): List of strings, indicating validation errors.