Security
Important: Security and Secure Coding is a much bigger topic that I can cover here. (Or, in fact, much bigger than I am qualified to cover.) * Recognize my limits, and don’t assume you know more than you think you do. * Make friends with an expert.
Code injection
- Keep code and data separate.
- Don’t allow user input to become executable code.
- If you come from a C/C++/Java background, this may sound trivial. But, in the world of scripting languages, it is frighteningly easy.
- Consider the
expressMVC
example.- Enter the following as a description: `You should sanitize your input.
- Notice that you see the tags when you show this new toy.
- Now change
<%=
to<%-
intoyShow.ejs
. - Notice that we can see the formatting.
- That may sound cool; but, edit it to forget the closing tag.
- Now, edit it to include
<img src='https://cis.gvsu.edu/~kurmasz/Images/buzz1.jpg'>
- What if that image src was
https://evil.com/evil.php?evilParameters
- Now, how about
<script>console.log("Uh oh")</script>
- Can you see how this is a bad idea that could get worse?
- Rails sanitizes output by default
- to override, append
.html_safe
to string
- to override, append
- Another approach would be to sanitize the data as soon as it comes into the app.
- See
express-validator
package for JavaScript Express - Sanitizing input for Rails seems less necessary since the output is so well sanitized. But, it could still be a good idea in certain situations.
- Think carefully how/when/whether you want the data sanitized. Turning
<>
into<>
won’t have the intended effect when using<%= %>
in EJS.
- See
- Beware of calls that will “execute” strings
- JavaScript’s
eval
–eval('console.log("Hello, there")')
; - Ruby’s
eval
- Never allow user input into
eval
calls. - Better yet, avoid them altogether.
- JavaScript’s
SQL Injection
- SQL Injection is another way user input can sneak into executable code.
-
Consider this line of code:
sqlStmt =
SELECT * from Authors where name="${nameInput}"
; - Now imagine that
nameInput
is pulled directly from an HTML form and containsFred"; DROP TABLE Authors; SELECT * from Authors where name="
- The resulting value of
sqlStmt
will beSELECT * from Authors where name="Fred"; DROP TABLE Authors; SELECT * from Authors where name=""
- The user has managed to inject his own SQL code into your application.
- In other words, the user was able to run an arbitrary SQL statement.
- Protections
- Sanitizing input (e.g., escaping quotation marks, semi-colons, etc.)
- SQL libraries that will only run one command per call (unless overridden)
- SQL libraries that contain query builders.
- Active Record (used by Rails) lets you write queries this way:
Client.where(first_name: nameInput)
- These query builder libraries presumably check the parameters carefully and/or are structured in such a way that malicious parameter values generate invalid SQL.
- Active Record (used by Rails) lets you write queries this way:
- https://xkcd.com/327/
CSRF XSRF
- Cross-site request forgery
- https://owasp.org/www-community/attacks/csrf
- Imagine a form at your bank that sends money to another person.
- Form does a POST to a route like
/transfer
- Form does a POST to a route like
- How can this same request be sent from another site?
- Another site can have the same form with the same action.
- Why can’t just anybody send a POST to the route and transfer money from your account?
- Need to be logged in (i.e., need the session cookie)
- How can we get your browser to send your session cookie from a different web page?
- Key idea: Cookies always go back to the server that sent them regardless of the window/tab.
- How can a malicious site send a request on your behalf? Hint: It uses a form, not JS.
- You are logged into 53.com in one tab
- You visit evil.com in another tab
- evil.com displays a form (e.g., sign up for a newsletter)
- forms can have hidden fields. So, this form may have visible “username” and “email”, but it could also have fields identical to the “transfer money” form from 53.com
- When you click “Submit”, the data is posted to 53.com and your session cookie goes with it!
- How can you prevent this attack?
- Synchronizer Token: When sending a page with a form, embed a hidden field with a random number.
- When that form is submitted check for the presence of that random number.
- evil.com won’t have it.
- Rails automatically adds this “invisible” token
- Inspect a form and show the “hidden” input named
authenticity_token
- If you use rails as an API (e.g., for React), you need to disable this authenticity token.
- (Need to use CORS instead; but, that’s a discussion for a different day.)
- Inspect a form and show the “hidden” input named