Secure Erasing of Password from Memory in Ruby

Nullify a variable in ruby

I am not sure if simply using password_in_string_form = nil would be enough.

No, it would not be enough. The object might or might not be garbage collected immediately, and even if it was, that does not cause the contents to be erased from memory.

However, unless they have been frozen, Ruby strings are mutable. Thus, as long as you do not freeze the password string, you can replace its contents with zeroes, or random characters, or whatever before you let go of it. In particular, this should work, subject a few provisos, covered later:

(0 ... password_in_string_form.length).each do |i|
password_in_string_form[i] = ' '
end

But care needs to be exercised, for this approach, which may seem more idomatic, does not work:

# SURPRISE! This does not reliably remove the password from memory!
password_in_string_form.replace(' ' * password_in_string_form.length)

Rather than updating the target string's contents in-place, replace() releases the contents to Ruby's internal allocator (which does not modify them), and chooses a strategy for the new contents based on details of the replacement.

The difference in effect between those two approaches should be a big warning flag for you, however. Ruby is a pretty high-level language. It gives you a lot of leverage, but at the cost of control over fine details, such as whether and how long data are retained in memory.

And that brings me to the provisos. Here are the main ones:

  • As you handle the password string, you must take care to avoid making copies of it or of any part of it, or else to capture all the copies and trash them, too. That will take some discipline and attention to detail, because it is very easy to make such copies.

  • Trashing the password string itself may not be enough to achieve your objective. You also need to trash any other copies of password in memory, such as from upstream of isolating the password string. If yours is a web application, for instance, that would include the contents of the HTTP request in which the password was delivered to your application, and probably more strings derived from it than just the isolated password string. Similar applies to other kinds of applications.

  • passwords may not be the only thing you need to protect. If an adversary is in a position where they can steal passwords from the host machine's memory, then they are also in position to steal the sensitive data that users access after logging in.

For these and other reasons, if the security requirements for your server dictate that in-memory copies of user passwords be destroyed as soon as they are no longer needed, then (pure) Ruby may not be an appropriate implementation language.

On the other hand, if an adversary obtains sufficient access to scrape passwords from memory / swap, then it's probably game over already. At minimum, they will have access to everything your application can access. That doesn't make the passwords altogether moot, but you should take it into consideration in your evaluation of how much effort to devote to this issue.

Ruby - encrypted_strings

With a symmetric encryption scheme, you only need the same password for encryption and decryption. And from the looks of it, the password is stored in an instance variable on the encrypted string:

>> secret = '123'
=> "123"
>> crypted = secret.encrypt(:symmetric, :password => "password")
=> "R5RVA511Nzw=\n"
>> crypted.instance_variables
=> ["@cipher"]
>> crypted.instance_variable_get("@cipher")
=> #<EncryptedStrings::SymmetricCipher:0x101192768 @password="password", @algorithm="DES-EDE3-CBC">

So yes, if you store the crypted object as above, you'll be storing the password as well. The goal then is to store only the string content of crypted without its instance variables. I thought that crypted.to_s or String(crypted) would accomplish this, but neither do. As a workaround, you can string interpolate it, explicitly pass it to String#new, or explicitly remove the instance variable:

>> "#{crypted}".instance_variables
=> []
>> String.new(crypted).instance_variables
=> []
>> crypted.send :remove_instance_variable, :@cipher
=> #<EncryptedStrings::SymmetricCipher:0x101192768 @password="password", @algorithm="DES-EDE3-CBC">
>> crypted.instance_variables
=> []

Once you have only the string content, you can decrypt it with the password at a later point:

>> "R5RVA511Nzw=\n".decrypt(:symmetric, :password => "password")
=> "123"

Is my method of encrypting encryption keys secure?

The scheme seems very complicated, and the devil is always in the details. If your application is capable of retrieving the data without the user's permission, then all of the encryption sugar you add might not be worth much, because attacks are likely to come through the application layer.

Take a look at how (good) full disk encryption software works. Without getting too much into specifics, think about just taking the user's password, hashing it (using whatever hash function you like) and using that as a symmetric key when you encrypt the data. If the user forgets their password, the data is pretty useless.

You can add some salt in there to prevent a dictionary attack, but you need to store the salt somewhere...

For the admin access, generate a random password, e-mail it to the admin, and then hash it, encrypt the data with it, and store it separately on the database.

Take a look at http://blog.cryptographyengineering.com/2011/11/how-not-to-use-symmetric-encryption.html, it goes into depth about how to best handle IVs and encryption modes.

Is it secure to store passwords as environment variables (rather than as plain text) in config files?

On a more theoretical level, I tend to think about levels for security in the following ways (in order of increasing strength) :

  • No security. Plain text. Anyone that knows where to look, can access the data.
  • Security by Obfuscation. You store the data (plaintext) someplace tricky, like an environment variable, or in a file that is meant to look like a configuration file. An attacker will eventually figure out what's going on, or stumble across it.
  • Security provided by encryption that is trivial to break, (think caesar cipher!).
  • Security provided by encryption that can be broken with some effort.
  • Security provided by encryption that is impractical to break given current hardware.
  • The most secure system is one that nobody can use! :)

Environment variables are more secure than plaintext files, because they are volatile/disposable, not saved;
i.e. if you set only a local environment variable, like "set pwd=whatever," and then run the script,
with something that exits your command shell at the end of the script, then the variable no longer exists.
Your case falls into the first two, which I'd say is fairly insecure. If you were going to do this, I wouldn't recommend deploying outside your immediate intranet/home network, and then only for testing purposes.

rails ssh password security

With public key authentication, you're just authenticating between your webserver and the server you're ssh'ing to. So if I understand your layout, then anyone who goes to the page doesn't need a password to get in. If you are passing a password via post, you can simply filter it from your logs with something like this

filter_parameter_logging :password

in your Application controller. Then its just being passed around in memory, not stored anywhere static. Though hashing and salting in the view via javascript and then decoding in the controller is probably still a good idea if you aren't using SSL. I'm certainly not going to recommend against an extra security measure that is fairly simple to implement...

Edit: Looks like the way to filter parameters in Rails 3 is

config.filter_parameters += [:password]

in config/application.rb

Storing a shared key for Rails application

there is really no way to accomplish that goal. (this is the same problem all DRM systems have)

You can't keep things secret from the operating system. Your application has to have the key somewhere in memory and the operating system kernel can read any memory location it wants to.

You need to be able to trust the operating system, which means that you then can also trust the operating system to properly enforce file access permissions. This in turn means that can store the key in a file that only the rails-user-process can read.

Think of it this way: even if you had no key at all, what is to stop an attacker on the server from simply changing the application code itself to gain access to the disabled functionality?



Related Topics



Leave a reply



Submit