secret_string - Remove secrets (passwords, keys...) from memory
Description
This Rubygem gives you ways to clean sensitive data (secrets, SSH keys, passwords) from your Ruby String variables in memory.
Install
Via gem command line:
gem install secret_string
If using bundler
, add this in your Gemfile
:
gem 'secret_string'
Usage
With a protecting scope
The simplest and more robust way to use it is with the SecretString.protect
method that gives a scope for a secret to be used from a String and will make sure this secret is removed from memory when code ends.
Example:
require 'secret_string'
secret = 'P4$Sw0rD' # Usually retrieved from a file, ENV var, user input...
# Create the protected scope
SecretString.protect(secret) do |secret_string|
# Let's try to display the password
puts "Password on screen is #{secret_string}"
# => Password on screen is XXXXX
# Its value can still be accessed using to_unprotected
puts "If we REALLY want to display it or use its real secret value somewhere: #{secret_string.to_unprotected}"
# => If we REALLY want to display it or use its real secret value somewhere: P4$Sw0rD
end
# Now that we are out of the protected scope, let's try leetch its value again!
puts "Outside of protection, my secret from memory is now #{secret}"
# => Outside of protection, my secret from memory is now
You can also control the silenced secret, in case you still need to display it in logs or messages:
require 'secret_string'
SecretString.protect('P4$Sw0rD', silenced_str: '<FAKE PASSWORD>') do |secret_string|
# Let's try to display the password
puts "Password on screen is #{secret_string}"
# => Password on screen is <FAKE PASSWORD>
end
With the SecretString
class
If you need more control (like having a simple scope is not enough), you can directly use the SecretString
class to protect your strings.
If you do so, don't forget to call the erase
method to clean their data, and make sure you didn't clone the secret in other variables.
Example:
require 'secret_string'
my_secret = SecretString.new('P4$Sw0rD', silenced_str: '<FAKE PASSWORD>')
puts "My secret handled without precaution is #{my_secret}"
# => My secret handled without precaution is <FAKE PASSWORD>
puts "My secret when I REALLY want its value is #{my_secret.to_unprotected}"
# => My secret when I REALLY want its value is P4$Sw0rD
my_secret.erase
puts "My secret after being erased is #{my_secret.to_unprotected}"
# => My secret after being erased is
Dealing directly with original Strings
You can erase any Ruby String using SecretString.erase
method:
require 'secret_string'
my_secret = 'P4$Sw0rD'
puts "My secret before erase is #{my_secret}"
# => My secret before erase is P4$Sw0rD
SecretString.erase(my_secret)
puts "My secret after being erased is #{my_secret}"
# => My secret after being erased is
The erase
and to_unprotected
methods have also been added to the core String class so that you can treat both String
and SecretString
easily within your code logic (no need to plague your code with if str.is_a?(SecretString)
). Those methods won't do or change anything to the normal Ruby Strings.
Example:
require 'secret_string'
strings = [
'Normal string',
SecretString.new('Secret: P4$Sw0rD', silenced_str: 'Secret: NO WAY')
]
puts "My strings are: #{strings}"
# => My strings are: ["Normal string", "Secret: NO WAY"]
puts "My unprotected strings are: #{strings.map(&:to_unprotected)}"
# => My unprotected strings are: ["Normal string", "Secret: P4$Sw0rD"
Change log
Please see CHANGELOG for more information on what has changed recently.
Testing
Automated tests are done using rspec.
To execute them, first install development dependencies:
bundle install
Then execute rspec
bundle exec rspec
Manual testing has been done using gdb
to effectively check that a Ruby process dumping its full memory on disk does not reveal secrets once erased by SecretString
(tested on Ruby 2.7).
Contributing
Any contribution is welcome:
- Fork the github project and create pull requests.
- Report bugs by creating tickets.
- Suggest improvements and new features by creating tickets.
Credits
License
The BSD License. Please see License File for more information.