170 lines
7.1 KiB
Plaintext
170 lines
7.1 KiB
Plaintext
<div class="widget">
|
|
<div class="widget-header">
|
|
<div class="title">
|
|
<span class="fs1" aria-hidden="true" data-icon=""></span> A6 - Sensitive Data Exposure - Clear-text storage of SSN(s)
|
|
</div>
|
|
</div>
|
|
<div class="widget-body">
|
|
<div id="accordion1" class="accordion no-margin">
|
|
<div class="accordion-group">
|
|
<div class="accordion-heading">
|
|
<a href="#collapseSSNOne" data-parent="#accordion1" data-toggle="collapse" class="accordion-toggle">
|
|
<i class="icon-info icon-white">
|
|
</i>
|
|
Description
|
|
</a>
|
|
</div>
|
|
<div class="accordion-body in collapse" id="collapseSSNOne" style="height: auto;">
|
|
<div class="accordion-inner">
|
|
<p class="desc">
|
|
The Railsgoat application stores and transmits Social Security Numbers insecurely.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-group">
|
|
<div class="accordion-heading">
|
|
<a href="#collapseSSNTwo" data-parent="#accordion1" data-toggle="collapse" class="accordion-toggle">
|
|
<i class="icon-bug icon-white">
|
|
</i>
|
|
Bug
|
|
</a>
|
|
</div>
|
|
<div class="accordion-body collapse" id="collapseSSNTwo" style="height: 0px;">
|
|
<div class="accordion-inner">
|
|
<p class="desc">
|
|
The Railsgoat application stores user's Social Security Numbers in plain-text within the database and because of this, it fails to adequately protect these numbers from theft. Additionally, the user's full SSN is sent back to the user within an HTTP response from the application.
|
|
</p>
|
|
<p class="desc">
|
|
The WorkInfo model (app/models/work_info.rb) is missing code to encrypt this data prior to storage. Additionally, while code exists to render only the last 4 numbers of an SSN (shown below), at no time is it used.
|
|
</p>
|
|
<pre class="ruby">
|
|
# We should probably use this
|
|
def last_four
|
|
"***-**-" << self.decrypt_ssn[-4,4]
|
|
end
|
|
</pre>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-group">
|
|
<div class="accordion-heading">
|
|
<a href="#collapseSSNThree" data-parent="#accordion1" data-toggle="collapse" class="accordion-toggle">
|
|
<i class="icon-lightning icon-white">
|
|
</i>
|
|
Solution
|
|
</a>
|
|
</div>
|
|
<div class="accordion-body collapse" id="collapseSSNThree" style="height: 0px;">
|
|
<div class="accordion-inner">
|
|
<p><b>SSN Storage - SOLUTION</b></p>
|
|
<p class="desc">
|
|
There is a lot of guidance on adequately protecting sensitive data at rest and using a layered defensive approach. Make no mistake, this should not be your sole means of securing sensitive data. That being said, there are at least four precautions that should be taken.
|
|
<li>The sensitive data is encrypted everywhere, including backups</li>
|
|
<li>Only authorized users can access decrypted copies of the data </li>
|
|
<li>Use a strong algorithm</li>
|
|
<li>Strong key is generated, protected from unauthorized access, and key change is planned for.</li><br/>
|
|
</p>
|
|
|
|
<p class="desc">
|
|
In the following code, we demonstrate switching from the storage of full SSN(s) in clear-text to storing them in the AES-256 encrypted format. The first thing to do is build the encrypt and decrypt functions. These can be found within app/models/work_info.rb.
|
|
</p>
|
|
<pre class="ruby">
|
|
def encrypt_ssn
|
|
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
|
|
aes.encrypt
|
|
aes.key = key
|
|
aes.iv = iv if iv != nil
|
|
self.encrypted_ssn = aes.update(self.SSN) + aes.final
|
|
self.SSN = nil
|
|
end
|
|
|
|
def decrypt_ssn
|
|
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
|
|
aes.decrypt
|
|
aes.key = key
|
|
aes.iv = iv if iv != nil
|
|
aes.update(self.encrypted_ssn) + aes.final
|
|
end
|
|
|
|
def key
|
|
raise "Key Missing" if !(KEY)
|
|
KEY
|
|
end
|
|
|
|
def iv
|
|
raise "No IV for this User" if !(self.key_management.iv)
|
|
self.key_management.iv
|
|
end
|
|
|
|
def cipher_type
|
|
'aes-256-cbc'
|
|
end
|
|
</pre>
|
|
<p class="desc">
|
|
Also within the WorkInfo model, we add the following line of code...
|
|
</p>
|
|
<pre class="ruby">
|
|
before_save :encrypt_ssn
|
|
</pre>
|
|
<p class="desc">
|
|
The remaining pieces are:
|
|
<li> We "seed" the database with per-user initialization vectors (IV) and store them within the key_management table</li>
|
|
<li> Separate production and development encryption keys. Production keys should be stored in an HSM, environment variable, etc. but never within the source code. Development keys are irrelevant if not being used for real data</li>
|
|
<li> Change the view where SSNs are called and rendered to the user so that the "last_four" method is called instead</li>
|
|
<li> For new user's who are registering, we create an initialization specific to their account</li>
|
|
</p>
|
|
<pre class="ruby">
|
|
# SEED DATA
|
|
work_info.each do |wi|
|
|
list = [:user_id, :SSN]
|
|
info = WorkInfo.new(wi.reject {|k| list.include?(k)})
|
|
info.user_id = wi[:user_id]
|
|
info.build_key_management({:user_id => wi[:user_id], :iv => SecureRandom.hex(32) })
|
|
info.SSN = wi[:SSN]
|
|
info.save
|
|
end
|
|
</pre>
|
|
<pre class="ruby">
|
|
# SEPARATE PROD AND DEV KEYS (config/initializers/key.rb)
|
|
if Rails.env.production?
|
|
# Specify env variable/location/etc. to retrieve key from
|
|
elsif Rails.env.development?
|
|
KEY = "123456789101112123456789101112123456789101112"
|
|
end
|
|
</pre>
|
|
<pre class="ruby">
|
|
# CHANGE VIEW TO CALL LAST FOUR METHOD (app/views/work_info/index.html.erb)
|
|
<%= CGI.unescapeHTML("<td class="ssn"><%= @user.work_info.last_four %></td>") %>
|
|
</pre>
|
|
<pre class="ruby">
|
|
def build_benefits_data
|
|
build_retirement(POPULATE_RETIREMENTS.shuffle.first)
|
|
build_paid_time_off(POPULATE_PAID_TIME_OFF.shuffle.first).schedule.build(POPULATE_SCHEDULE.shuffle.first)
|
|
build_work_info(POPULATE_WORK_INFO.shuffle.first)
|
|
# Uncomment below line to use encrypted SSN(s)
|
|
work_info.build_key_management(:iv => SecureRandom.hex(32))
|
|
performance.build(POPULATE_PERFORMANCE.shuffle.first)
|
|
end
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-group">
|
|
<div class="accordion-heading">
|
|
<a style="background-color: rgb(181, 121, 158)" href="#collapseSSNFour" data-parent="#accordion1" data-toggle="collapse" class="accordion-toggle">
|
|
<i class="icon-aid icon-white">
|
|
</i>
|
|
Hint
|
|
</a>
|
|
</div>
|
|
<div class="accordion-body collapse" id="collapseSSNFour" style="height: 0px;">
|
|
<div class="accordion-inner">
|
|
My SSN seems pretty important, hope it's kept safe!
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> |