2

I am making a gem to wrap an API. The service requires a few login parameters so I made a Connection class to initialize by passing in all login values, and storing with instance variables. One of these values, @secret_access_key is secret, obviously. It is not readable within the app. But while testing the gem in irb, I see the secret key displayed along with all other instance variables when the object is returned.

mws = MWS::Connection.new :access_key => '1', :secret_access_key => 'SECRET!!!', :merchant_id => '3', :marketplace_id => '4'
 => #<MWS::Connection:0x007fbd22acef40 @access_key="1", @merchant_id="3", @marketplace_id="4", @secret_access_key="SECRET!!!">

I am paranoid that the secret key will show up in Heroku logs, app error messages, or whatever else.

Should I be worrying? If so, what's the best way to store or hide this information?

Also, I am using httparty gem to manage this, is there something better I can do with that gem?

Erik J
  • 828
  • 9
  • 22

2 Answers2

7

You could use this workaround:

class MWS::Connection
  def inspect
    "#<MWS::Connection:#{object_id}>"
  end
end

Of course the secret key will still be accessible, but it shouldn't show up in any logs now:

mws = MWS::Connection.new :access_key => '1', :secret_access_key => 'SECRET!!!', :merchant_id => '3', :marketplace_id => '4'
# => #<MWS::Connection:0x007fbd22acef40>
mws.instance_variable_get(:@secret_access_key) # => 'SECRET!!!'
Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • Overriding Object#inspect can also be very useful in limiting very verbose output in the exception call stack. As #inspect is called recursively on all instance variables (objects) in an object, the string can easy become very long for composite objects. One consequence is having to scroll up through pages of CLI output to read an exception, for example. Better to override #inspect with just the info you need. – MatzFan Jul 15 '22 at 12:41
2
class MWS::Connection
  def initalize(opts)
    ...
    @secret_access_key = Cypher.encypher(opts[:secret_access_key]) if opts[:secret_access_key]
  end

  def secret_access_key
    Cypher.decypher @secret_access_key
  end
end

class Cypher
  def self.encypher(str)
    str + 'fancy_encryption_protocol'
  end

  def self.decypher(str)
    str.sub 'fancy_encryption_protocol$', ''
  end
end
Mori
  • 27,279
  • 10
  • 68
  • 73