diff --git a/app/models/pay.rb b/app/models/pay.rb index 74116a3..78f0278 100644 --- a/app/models/pay.rb +++ b/app/models/pay.rb @@ -11,7 +11,7 @@ class Pay < ActiveRecord::Base validates :bank_routing_num, presence: true validates :percent_of_deposit, presence: true - # actions + # callbacks before_save :encrypt_bank_account_num def as_json diff --git a/app/views/layouts/tutorial/logic_flaws/_insecure_crypto_reuse.html.erb b/app/views/layouts/tutorial/logic_flaws/_insecure_crypto_reuse.html.erb index d7ce9f3..c9e9e53 100644 --- a/app/views/layouts/tutorial/logic_flaws/_insecure_crypto_reuse.html.erb +++ b/app/views/layouts/tutorial/logic_flaws/_insecure_crypto_reuse.html.erb @@ -16,7 +16,9 @@
+ The Railsgoat application allows employees of Metacorp to choose the Remember Me option at login, which creates a cookie named auth-token. The encryption routine used to generate the auth-token allows the application to extract a user ID. When decrypted, a user ID is extracted and the user is authorized appropriately. This same encryption routine is used elsewhere in the application in a manner such that a clever attacker can generate an auth_token cookie with whatever user ID they prefer and authorize to the application as a different user. +
+ Within the file lib/encryption.rb, there are two encryption related methods that we have exposed: +
+
+ # Added a re-usable encryption routine, shouldn't be an issue!
+ def self.encrypt_sensitive_value(val="")
+ aes = OpenSSL::Cipher::Cipher.new(cipher_type)
+ aes.encrypt
+ aes.key = key
+ aes.iv = iv if iv != nil
+ new_val = aes.update("#{val}") + aes.final
+ Base64.strict_encode64(new_val).encode('utf-8')
+ end
+
+ def self.decrypt_sensitive_value(val="")
+ aes = OpenSSL::Cipher::Cipher.new(cipher_type)
+ aes.decrypt
+ aes.key = key
+ aes.iv = iv if iv != nil
+ decoded = Base64.strict_decode64("#{val}")
+ aes.update("#{decoded}") + aes.final
+ end
+
+
+ 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 auth_token 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.
+ 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:
+
+ # callbacks + before_save :encrypt_bank_account_num + + def encrypt_bank_account_num + self.bank_account_num = Encryption.encrypt_sensitive_value(self.bank_account_num) + end ++
+ Additionally, we render that encrypted value (purposefully) when the show action is created within the app/controllers/pay_controller.rb file: +
+
+ def show
+ respond_to do |format|
+ format.json { render :json => {:user => current_user.pay.as_json} }
+ end
+ end
+
+ + Lastly, we re-use this same routine within the following code is used to create a user's auth_token cookie upon sign-up or creation (app/models/user.rb): +
+
+ before_create { generate_token(:auth_token) }
+
+ def generate_token(column)
+ begin
+ self[column] = Encryption.encrypt_sensitive_value(self.user_id)
+ end while User.exists?(column => self[column])
+ end
+
Insecure Encryption Re-use ATTACK:
- insert attack ++ Navigate to the Pay section of the application. Enter your bank account number but use the number 1 as your bank account number. Once the information is entered and submitted, you'll see the encrypted value of your bank account number (1) returned. URL encode the special characters (+ and ==) and use this value as your auth_token cookie. Navigate to your dashboard and you'll have the ability to access administrative functionality. +
Insecure Encryption Re-use SOLUTION:
- insert solution ++ Create an entirely new encryption routine or create the SHA1 hash with a different salt. +