loading...

Day 14: #100DaysofCode - Finalized my Sinatra Project -Security

sincerelybrittany profile image Brittany ・7 min read

#100DaysofCode (63 Part Series)

1) Day 1 of #100DaysofCode - Understanding Iterators 2) Day 2: #100DaysofCode - I updated to Catalina and All HELL Broke Loose 3 ... 61 3) Day 3: #100DaysofCode - Oh No, SQL 4) Day 4: #100DaysofCode - More Iterators 5) Day 5 - #100DaysofCode - Setting up a Sinatra App 6) Day 6 : #100DaysofCode - Setting up a Sinatra App : Part 2 - Config.ru 7) Day 7: #100DaysofCode - Setting up a Sinatra App - Part 3 8) Day 8: #100DaysofCode - Setting up Sinatra Database - Part 4 9) Day 9: #100DaysofCode - ActiveRecord and a Database 10) Day 10: #100DaysofCode - ActiveRecord and a Database 11) Day 11 : #100DaysofCode - RESTful Routes 12) Day 12: #100DaysofCode and Day 1 of #Javascript30 13) Day 13 - #100DaysofCode - #Javascript30 - Day 2 - CSS + JS Clock 14) Day 14: #100DaysofCode - Finalized my Sinatra Project -Security 15) #Day 15: #100DaysofCode - View my Sinatra Project 16) Day 16 - #100DaysofCode - Understanding MVC 17) Day 17 : #100DaysofCode - Knowing your Ruby Version & what Errno::EADDRINUSE means is important! 18) Day 18 of #100daysofCode - 3 challenges 19) Day 19 of #100daysofCode - Hashes 101 20) Day 20: #100DaysofCode - Practice makes perfect 21) Day 21 : #100DaysofCode - Cascading Style Sheets 101 22) Day 22 - #100daysofCode - CSS 101 Part 2 23) Day 23 - #100DaysofCode - Updated My Portfolio 24) Day 24 - #100DaysofCode - Practicing CSS Grid and Emmet Shortcuts on VSCode 25) Day 25 - #100DaysofCode - Intro to Rails 26) Day 26 - #100DaysofCode - Accessing Rails Commands 27) Day 27 : #100DaysofCode - Still reviewing the basic rails concepts . . . 28) Day 28 : #100DaysofCode - Adding Dev.to blogs to personal page 29) Day 29 : #100DaysofCode - Very Simple Rails App CRUD Practice 30) Day 30 : #100DaysofCode - Very basic rails continued 31) Day 31 - #100DaysofCode - Rails Routes 101 32) Day 32 : #100DaysofCode - Resources for learning to code 33) Day 33 - #100DaysofCode - Setting up my app on Heroku 34) Day 34 - #100DaysofCode - New/edit action versus create/update action 35) Day 35 : #100DaysofCode - A Code Challenge Completed 36) Day 36 - #100DaysofCode - Rails form_for versus form_tag 37) Day 37 : #100DaysofCode - 30 seconds of code 38) Day 38 - #100DaysofCode - Built my first basic rails application 39) Day 39 : #100DaysofCode - I updated my github profile page 40) Day 40 : #100DaysofCode - I need project ideas 41) Day 41 : #100DaysofCode - Collaboration 42) Day 42 : #100DaysofCode - The Planning of a Project 43) Day 43 : #100DaysofCode - The Amazing Faker Gem 44) Day 44 : #100DaysofCode - Code or Youtube? 45) Day 45 : #100DaysofCode - Basic Nested Forms 46) Day 46 : #100DaysofCode - Still reviewing form_for 47) Day 47 : #100DaysofCode - How do you code? 48) Day 48 : #100DaysofCode - Code Along 49) Day 49 : #100DaysofCode - Still Coding Along 50) Day 50 : #100DaysofCode - Keep Coding Along 51) Day 51 : #100DaysofCode - Code Along 52) Day 52 : #100DaysofCode - No Wifi, No Problem 53) Day 53: #100DaysofCode - Created user log in and log out functionality 54) Day 54 : #100DaysofCode -Review on setting up log in & sign up 55) Day 55 : #100DaysofCode - In Need of Advice on Reading Poorly Written Documentation 56) Day 56 : #100DaysofCode - A Tweet - Devise - Users 57) Day 57 : 100DaysofCode - Remembering to Git Commit Often 58) Day 58 : #100DaysofCode - Beginning to Learn Python 59) Day 59 : #100DaysofCode - Focused on My Rails Project 60) Day 60 : #100DaysofCode - CSS in Rails 61) Day 61 : #100DaysofCode - Omniauth? 62) Day 62 : #100DaysofCode - Sign in using a Third Party, Rails 63) Day 63 : #100DaysofCode - Refactoring

My Sinatra Project

SECURITY

Something that became very important during the building of my Sinatra project was SECURITY. It is important that once your application is deployed that you ensure that you are taking proper precautions to make sure that your application is secure from cyber attacks. While building my first Sinatra project, I learned a lot about some of the most basic and simple ways to make sure that your project is secure.

1. gitignore

Some may not agree, but I feel like every project on Github should have a .gitignore file. A .gitignore file allows us to "hide" certain files by preventing those files from being pushed/tracked by git. It is very simple to use, just create a file named .gitignore and then add the name of the file that you want to ignore. So for example, I had a notes file that I wanted to keep for myself and I did not want the world/github to know about. I created my .gitignore file and then created a file named secret_notes.txt.

Within my .gitignore file, I added the following:

secret_notes.txt

It was that simple.

If you recall from my previous post , when building a Sinatra project, your environment will have a "SINATRA_ENV" which defines your deployment environment, configures our database, and requires all the files in our app.require a password. My project was no different, my environment looked like this:

ENV['SINATRA_ENV'] ||= "development"

if ENV['SINATRA_ENV'] == "development"
  require_relative "../secrets"
end

require 'bundler/setup'
Bundler.require(:default, ENV['SINATRA_ENV'])

ActiveRecord::Base.establish_connection(
  :adapter => "sqlite3",
  :database => "db/#{ENV['SINATRA_ENV']}.sqlite"
)

The above requires my "../secrets", but when you go to my Github repo the secrets file is not available, as you may have guessed, the file was placed in my gitignore file and although you can not see it I will tell you that I placed a secure sessions password and api keys in the secrets.rb file.

2. Securing Users Password

One way to protect the users interacting with your application is to protect their passwords. An easy way to do this is to use the bcrypt-ruby gem. The gem essentially takes a users password and encrypts it by using a hash algorithm.

I used bcrypt in my application by adding the gem to my gemfile by running: bundle add bcrypt

The bcypt Ruby gem provides you with has_secure_password method. The has_secure_password method encrypts passwords by hashing and salting the passwords and generating a password_digest. bcrypt requires that you use password_digest as your attribute name in your user migrations table. I did that in my users table, like this:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :username
      t.string :email
      t.string :location
      t.integer :age
      t.string :password_digest
      t.timestamps
    end
  end
end

Then within my users model, I made sure add the has_secure_password macro inside of my User class, like this:


class User < ActiveRecord::Base 

has_secure_password
has_many :watchlists
has_many :stocks, through: :watchlists
validates :username, uniqueness: true
validates :username, presence: true
validates :email, presence: true

end

2. Sessions & User Authentication

A great way to ensure that someone is who they claim to be when they sign up and login is to use cookie and session based authentication.

What is cookie and session based authentication?
Cookies and Sessions are used to store information. Cookies are only stored on the client-side machine, while sessions get stored on the client as well as a server.

What that means is that once you sign up a cookie is saved on the browser and a session is stored on the server. From then on every time you you log in or make future request, some of data stating that it is you gets sent with your HTTP request, confirming that you are an authenticated user.

To set up my sessions I enabled sessions and created a sessions secret to my applications_controller.

  enable :sessions
  set :session_secret, ENV['SESSION_PASSWORD']

3. Secure password

How did I create a secure sessions password for my environment? I generated a secured random number by using the sysrandom gem. It is recommended that everyone use a gem similar to this to generate secure passwords. Simply do the following in your terminal to get a secure password:

First install the sysrandom:

gem install sysrandom

Then run the following, which will generate a random string of hexadecimals:

ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"

It should return something similar to this:

5ac1ac3c2ec64ef76ac91018059f541b7e8f437fbda1ccddb4f2c56a9ccf1e75

I used that number to require it in my environment, I also required my api numbers provided by the IEX CLOUD api.

My secrets.rb file looked like this:

ENV['SECRET_TOKEN_ID'] = "sk_oiherbnbdlfoiuhejkwbf9ubkjdhfuihf"
ENV['PUBLISHABLE_TOKEN_ID'] = "pk_kjdhfewuohjwni23yhuijkebiwr"
ENV['SESSION_PASSWORD'] = "5ac1ac3c2ec64ef76ac91018059f541b7e8f437fbda1ccddb4f2c56a9ccf1e75"

3. Sanitizing User Input

Input sanitization describes cleansing and scrubbing user input to prevent it from jumping the fence and exploiting security holes. But thorough input sanitization is hard. While some vulnerable sites simply don’t sanitize at all, others do so incompletely, lending their owners a false sense of security.

Simply put, when a user is going to your website, they may not have the best intentions. For me, I wanted a user to come to my website and create a Watchlist name through a form like this:

<h3>Create a New Watchlist</h3>

<form action="/watchlists" method="POST">
  <input type="text" name="watchlist[name]" id="watchlist_name" placeholder="Watchlist Name"><br>
  <input type="submit" value="Create Watchlist">
</form>

But what if instead of the user inputting text, they inserted a piece of javascript that generated a pop up box on the application, something like this:

<script>
function myFunction() {
  alert("Hello! I am an alert box!");
}
</script>

What if the user created a script that jeopardized my entire application and created a pop up box for all users using my application. There are ways to prevent this and I learned two different ways to avoid this kind of attack while building this project.

Using The Sanitize Gem

The first way I learned was to use the sanitize gem to avoid SQL injection, cross-site scripting (XSS), and remote file inclusion (RFI).

The gem allows us to Sanitize.fragment(html) to

I chose to use Sanitize.fragment(html) which uses its strictest settings by default, which means it will strip all HTML and leave only safe text behind. This gem is helpful because you can personalize it to allow certain html elements in the input from users. Feel free to look at the gem docs for more examples.

Personally, I used the gem in my post '/watchlists' within my watchlist_controller after a user creates a new name for a watchlist, it will Sanitize the user input and save it after it is Sanitized, like this --

   post '/watchlists' do
     authenticate
    if params[:watchlist][:stock] == nil
     @watchlist = current_user.watchlists.new(name: Sanitize.fragment(params[:watchlist][:name]), user_id: params[:user_id])
      if @watchlist.save
        flash[:message] = "You have successfully created a watchlists."
      redirect "/watchlists"

Using .Gsub

When you google grep and gsub you'll see something like this:
Grep search for matches to argument pattern within each element of a character vector: they differ in the format of and amount of detail in the result and .gsub replaces all occurrences. If replacement contains backreferences which are not defined in pattern the result is undefined (but most often the backreference is taken to be "")

To grasp a better understanding, I collaborated with some of my classmates and learned how to prevent a user from inputting inappropriate data into my application while signing up. One way is by using grep, regex and .gsub.

Within my signup controller you will see that the post signup has the following information:

  post '/signup' do
      @u = User.new(:username => params[:username].gsub(/[\<\>\/]/, ""),
                          :password => params[:password],
                          :email => params[:email].gsub(/[\<\>\/]/, ""),
                          :location => params[:location].gsub(/[\<\>\/]/, ""),
                          :age => params[:age].gsub(/[\<\>\/]/, ""))
      if @u.save
          session[:user_id] = @u.id
          redirect "/watchlists"
      else
          erb :'sessions/signup'
      end
  end

The .gsub searches for matches in my argument pattern (/[\<\>\/]/, "") and if it matches it will result in an undefined/blank answer. So if someone signs up and puts <h1> Hello</h1> as there username. It will result in a username of h1helloh1 removing the <> tags and essentially not effecting the application at all, but instead gives the user a ridiculous username.

I learned a lot about how to protect my application and the individuals using my application while building this application and look forward to learning more ways to protect future projects that I build.

Resources
Password_digest column in User migration table

Add Authentication to Your Rails App With bcrypt

Feel free to use my Sinatra Project and contribute to it.

Song of the day

#100DaysofCode (63 Part Series)

1) Day 1 of #100DaysofCode - Understanding Iterators 2) Day 2: #100DaysofCode - I updated to Catalina and All HELL Broke Loose 3 ... 61 3) Day 3: #100DaysofCode - Oh No, SQL 4) Day 4: #100DaysofCode - More Iterators 5) Day 5 - #100DaysofCode - Setting up a Sinatra App 6) Day 6 : #100DaysofCode - Setting up a Sinatra App : Part 2 - Config.ru 7) Day 7: #100DaysofCode - Setting up a Sinatra App - Part 3 8) Day 8: #100DaysofCode - Setting up Sinatra Database - Part 4 9) Day 9: #100DaysofCode - ActiveRecord and a Database 10) Day 10: #100DaysofCode - ActiveRecord and a Database 11) Day 11 : #100DaysofCode - RESTful Routes 12) Day 12: #100DaysofCode and Day 1 of #Javascript30 13) Day 13 - #100DaysofCode - #Javascript30 - Day 2 - CSS + JS Clock 14) Day 14: #100DaysofCode - Finalized my Sinatra Project -Security 15) #Day 15: #100DaysofCode - View my Sinatra Project 16) Day 16 - #100DaysofCode - Understanding MVC 17) Day 17 : #100DaysofCode - Knowing your Ruby Version & what Errno::EADDRINUSE means is important! 18) Day 18 of #100daysofCode - 3 challenges 19) Day 19 of #100daysofCode - Hashes 101 20) Day 20: #100DaysofCode - Practice makes perfect 21) Day 21 : #100DaysofCode - Cascading Style Sheets 101 22) Day 22 - #100daysofCode - CSS 101 Part 2 23) Day 23 - #100DaysofCode - Updated My Portfolio 24) Day 24 - #100DaysofCode - Practicing CSS Grid and Emmet Shortcuts on VSCode 25) Day 25 - #100DaysofCode - Intro to Rails 26) Day 26 - #100DaysofCode - Accessing Rails Commands 27) Day 27 : #100DaysofCode - Still reviewing the basic rails concepts . . . 28) Day 28 : #100DaysofCode - Adding Dev.to blogs to personal page 29) Day 29 : #100DaysofCode - Very Simple Rails App CRUD Practice 30) Day 30 : #100DaysofCode - Very basic rails continued 31) Day 31 - #100DaysofCode - Rails Routes 101 32) Day 32 : #100DaysofCode - Resources for learning to code 33) Day 33 - #100DaysofCode - Setting up my app on Heroku 34) Day 34 - #100DaysofCode - New/edit action versus create/update action 35) Day 35 : #100DaysofCode - A Code Challenge Completed 36) Day 36 - #100DaysofCode - Rails form_for versus form_tag 37) Day 37 : #100DaysofCode - 30 seconds of code 38) Day 38 - #100DaysofCode - Built my first basic rails application 39) Day 39 : #100DaysofCode - I updated my github profile page 40) Day 40 : #100DaysofCode - I need project ideas 41) Day 41 : #100DaysofCode - Collaboration 42) Day 42 : #100DaysofCode - The Planning of a Project 43) Day 43 : #100DaysofCode - The Amazing Faker Gem 44) Day 44 : #100DaysofCode - Code or Youtube? 45) Day 45 : #100DaysofCode - Basic Nested Forms 46) Day 46 : #100DaysofCode - Still reviewing form_for 47) Day 47 : #100DaysofCode - How do you code? 48) Day 48 : #100DaysofCode - Code Along 49) Day 49 : #100DaysofCode - Still Coding Along 50) Day 50 : #100DaysofCode - Keep Coding Along 51) Day 51 : #100DaysofCode - Code Along 52) Day 52 : #100DaysofCode - No Wifi, No Problem 53) Day 53: #100DaysofCode - Created user log in and log out functionality 54) Day 54 : #100DaysofCode -Review on setting up log in & sign up 55) Day 55 : #100DaysofCode - In Need of Advice on Reading Poorly Written Documentation 56) Day 56 : #100DaysofCode - A Tweet - Devise - Users 57) Day 57 : 100DaysofCode - Remembering to Git Commit Often 58) Day 58 : #100DaysofCode - Beginning to Learn Python 59) Day 59 : #100DaysofCode - Focused on My Rails Project 60) Day 60 : #100DaysofCode - CSS in Rails 61) Day 61 : #100DaysofCode - Omniauth? 62) Day 62 : #100DaysofCode - Sign in using a Third Party, Rails 63) Day 63 : #100DaysofCode - Refactoring

Posted on by:

sincerelybrittany profile

Brittany

@sincerelybrittany

Web Developer | Software Engineer πŸ‘©πŸΎβ€πŸ’» | Determined | Music & Dance | #100DaysofCode | #WomenWhoCode

Discussion

markdown guide