Client side trojan issue
Description
Imagine you have some kind of system that you administer through a
web GUI, such as HotMailx, your Netscape Admin server or a site
like Zope.org. You get in to work and use this service for a while
(check your mail, manage your servers, whatever). For our example,
lets say you were using the netscape admin server.
Later in the day someone sends you an email asking you to look at
a web page. You go the page using the browser session where earlier
you had logged in to the admin server. However, the page does a
redirect to a url of your admin server that causes your main web
server to be deleted! The redirect will succeed, as you've already
logged in to the admin server earlier with sufficient privileges to
delete your server.
There are a few variations on this theme, involving JavaScriptx that
can silently submit a hidden form to do the same sort of thing. It
appears that most web applications involving authentication are
vulnerable to this sort of attack.
Web clients will cache your credentials and send them automatically
to a realm that you have visited earlier in the session, which in a
stateless system is a reasonable behavior. The problem is that the
client is also willing to let almost any page on the Web take actions
automatically on your behalf through the use of things like redirects
or javascript code.
An Example
Lets say I know that you run a web server that includes a through-
the-web management server on your site (such as NS Enterprise
Server). I can probably assume that you've used the default ports etc.
during installation.
If you've logged into the management server at some point during
the browser session and I can get you to view my HTML page during
that same session, then there is a very good chance that I can
force you to unwittingly delete your main web server installation
using a plain HTML form that submits itself (via javascript) as
soon as the document is loaded. That form is submitted to the
function of the management server that deletes the server.
Most browsers, when first installed, will pop up a dialog of some
sort warning you when you are submitting form information. Most
browsers also give you the option of selecting "never bother me with
this again" right on the dialog. How many reading this have turned
this off? A large number, I suspect (myself included). Because we
cannot be bothered with those silly dialogs, we will all be in the
same boat when our first clue that something is wrong will be
when we see the response from our management server (some variation
of "Congratulations! You have deleted your entire main web site
successfully!").
We have verified that this attack works with some real-world tests
involving NS enterprise server and some through-the-web mail services.
At this point, we highly suspect that almost any through-the-web
management system (including through-the-web management systems for
certain operating systems) is probably vulnerable to this sort of
trojan attack.
The amount of actual damage
that could be done and the difficulty of knowing enough about the
environment to pull off an attack vary depending on the service in
question, but at best that is security-by-obscurity. Note that CERT
has issued an advisory that touches on this in passing (noting the
possibility of using JavaScriptx or other scripting support to take
actions on the users behalf without him knowing it):
http://www.cert.org/advisories/CA-2000-02.html.
Coming up with a workable technical solution to this is tricky - there
is nothing in the current Web infrastructure that deals with this
directly. Web clients and servers have a means of dealing with
authentication (are you really who you say you are?) and authorization
(the server says "no, you are not allowed to do that"), but they do
not have a way of verifying intent ("do you really mean to delete
your site, or has someone tricked you into this?").
Who is affected
Potentially any Web-accessible system is vulnerable to this type of
attack.
Operational measures
As noted below, we would very much like to come up with a solution
that either prevents or significantly reduces the risk of this type
of attack. This Wiki will serve as an ongoing discussion toward that
goal. In the meantime, managers of not only Zope sites but any Web-
managed system should should take some operational precautions to
reduce their risk.
Do not view untrusted content in any browser session where you have
previously logged in to any web-based system with privileges that
could be abused.
Turn off javascript! While it is not the only way, javascript is by
far the easiest way for an attacker to make a Web client take actions
on your behalf.
The stakes are high
There is a serious security problem here. Although it is not
Zope's fault, it is a problem that Zope should deal with.
Because one of the cornerstones of the Zope philosophy is the
ability to safely delegate responsibility, we don't feel that
relying on operational security alone is an adequate answer. Our
goal is to come up with a solution to prevent or significantly
mitigate the risk of such an attack against Zope sites.
Mitigation
First, there probably isn't a "solution" to this problem.
There are a variety of operational and technical strategies we can
investigate to mitigate the risks.
Mitigation 1, Curtail time logged in and activities
This is an operational mitigation technique.
Never view untrusted
content while logged in with privileges that could be abused and
always end your session with those privileges as soon as
your work is done.
Variations:
Pros:
- p1.1
Requires little or no software change.
- p1.2
Works on non-Zope sites.
Issues
- i1.1
By default, Zope doesn't provide a facility to log out,
other than re-booting your browser. :( This is true for any
system that relies on basic authentication.
- i1.2
This is very hard for the user to manage, especially
web infrastucture. There aren't good ways to control
privilege. There are many degrees of priviledge and in many
applications, much useful functionality requires a level of
priviledge which can be exploited to do harm.
Mitigation 2, Undo
This is an operational mitigation technique.
Undo provides a certain level of protection.
Pros:
See p1.1.
- p2.1
Provides a way to recover from damaging scripts
- p2.2
Unique to Zope
Issues:
- i2.1
Doesn't work if a site doesn't support or allow undo.
- i2.2
Doesn't work with non-undoable transactions, such as
RDBMS transactions.
- i2.3
Doesn't work if it involves objects that change often
(e.g. the catalog). This can and should be mitigated
by efforts to mitigate hot spots.
- i2.4
Doesn't help with inherently non-undoable operations, like undo.
- i2.5
It may not be possible for a user to know that they've been
hacked, so that may not know to undo.
Mitigation 3, minimal referer checks
For "unsafe" requests, the security machinery could attempt to get the
HTTP Referer header from the request and determine if it seems to
point to a local object. If not, the request will be denied.
An unsafe request is a request of a protected resource through a POST
request or a GET request with a query string.
If necessary for xml-rpc or soap, we might allow a request to omit
http referer if it has auth data in a form that would not be
automatically provided by the browser.
If the referer does appear to be a local object, we look at the local
object and see if it has an owner. If it does, then we only allow
access of the owner would have access. For example, suppose you wrote
a page that has a redirect to
Members/jim/manage_deleteObjects?id:list=SomeObjectx?. Zope would see
that your page was the referer and that it was owned by you. Since you
don't have rights to run manage_deleteObjects in my folder, the
request would be unauthorized.
In addition, if the object has (new) proxy roles, then they would
apply too, so they could offer further protection. I can use (new)
proxy roles to prevent you from shooting me with my own wiki. :)
Pros:
- p3.1
Leverages existing client behavior to get the required meta
data to ensure request propriety.
- p3.2
Can likely be hidden behind the security policy abstraction,
probably requires little or no user code changes.
- p3.3
Leverages a unique feature of the (new) Zope security model,
which is that we check the privileges of the owner of
executables.
Issues:
i3.1 --How do you get into a protected resource if the referer has to
be a local resource with a peer level of privilege? (The "entry
point" problem).
- jim
Put another way. How does someone get into the management
interface in the first place? We need to distinguish bwteeen
"safe" and "unsafe" management operations. I propose that, at
least by default, that we only check HTTP_REFERER for POST
requests and GET requests with form data. Perhaps there could
be a way for the programmer to override this rule.
- i3.2
It is not possible to say for sure that all browsers send the
referer header. The conventional browsers seem to, so this
probably isn't a big problem, though we should document which
browsers we know we support.
- jim
Right. You have to pay something, and this seems like a
pretty small price to pay. Plus, keep in mind that we now
allow people to replace our security policy with a different
one and they'd be able to disable this feature if they felt
it was too restrictive and were willing to bear the risk.
- mj
Just listing browsers will not suffice. Junkbuster, a
filtering proxy (which I use), filters out the referrer header.
Documentation will have to make it clear that the referrer
header is used and for administring Zope in a default install
requires you to bypass such a proxy. However: some corporate
firewalls also filter this out, and the end user doesn't always
have control over this, nor over the Zope server he is
administering. Think of an Intel employee becoming a member of
Zope.org.
- i3.3
Regardless of browser, users trying to access a Zope site may
be coming in through a filtering proxy that either strips or
provides bogus referrer information. This should be documented so
that people are aware of the potential problem.
- i3.4
Transitions from SSL to insecure connections will lose
referrer information. This should be a pretty rare thing in
practice, but could conceivably cause seemingly odd behaviors if
sites are set up in mixed SSL/clear configurations, so it should
probably be documented.
- i3.5
All existing ZClientx? scripts will likely break unless we
make changes to have the referrer set by the library itself
(maybe we could set referrer to the actual target?)
- jim
Or provided some other way to spell that they are
special. Alternatively, we could provide another way for them
to spell authentication data that isn't provided by browsers.
- i3.6
Would break xml-rpc, soap and other protocols that piggyback
over HTTP unless we provide for some kind of special handling of
those protocols.
- jim
This definately needs some thought. See above. In the
short term, if we feel that xml-rpc can't be spoofed from
HTML or java-script, we could simply not require the HTTP
referer, but I think I'd rather just provide a different way
to spell authentication data.
- i3.7
May break existing applications, though the likelihood of
this is hard to gauge. This is probably tolerable, since
developers should be able to fix apps by changing ownership or
other non- code changes. It is possible that the objects
comprising the existing applications would become "unowned" when
the security policy changes are applied, in which case there
probably would be no breakage.
- jim
Yes. Something we have to remember is that the stakes are
high. We're going to have to be willing to give up something
to get what we want.
- i3.8
Can be defeated by Java-script, at least for within-site
attacks.
- i3.9
Security design becomes harder because one needs to
consider security implications of hyperlinks (and forms).
For example, suppose I have an unprotected but highly
priviledged (unowned or owned by a priviledged user) page that
provides a form or a link to do something bad. Such a page
could be exploited by a malicious unpriviledged page.
Mitigation 4, referer checks and auto-logout
The security machinery will attempt to get the HTTP Referer header
from the request and determine if it seems to point to a local
object. If the referer is missing or is non local, then the user
will be logged out. They can access the requested resource only if
they provide new credentials.
If necessary for xml-rpc or soap, we might allow a request to
omit http referer if it has auth data in a form that would
not be automatically provided by the browser.
If the referer does appear to be a local object, we look at the
local object and see if it has an owner. If it does, then we only
allow access of the owner would have access. For example, suppose
you wrote a page that has a redirect to
Members/jim/manage_deleteObjects?id:list=SomeObjectx.
Zope would see that your page was the referer and that it was owned
by you. Since you don't have rights to run manage_deleteObjects in
my folder, the request would be disallowed.
In addition, if the object has (new) proxy roles, then they would
apply too, so they could offer further protection. I can
use (new) proxy roles to prevent you from shooting me with my own
wiki. :)
Pros:
See p3.1, p3.2, p3.3.
- p4.1
Doesn't limit protection to POSTsx and GETsx with form data.
- p4.2
Can't be defeated by Java-script
Issues:
See i3.2, i3.3, i3.4, i3.5, i3.6, i3.8, i3.9.
- i4.1
What is a local object? It is tempting to say that it is
an object that is outside the user's "realm", which might be
the folder where their user folder is. For now, an object is
local if it's on the same (possibly virtual) Zope "site".
- i4.2
How do you log someone out?
- Cookie-based authentication
You simply expire the cookie and
give them a login form. When they submit the login form,
they'll be coming from inside. (BTW, the login form should be
clever enough to take them back to where they were trying to
go.)
It might be a good idea to display a page first that
explains what's happening and gives them the option
of going forward. This way they could avoid logging our.
Of course, Javascript could defeat this, but at least
this would help with accidental logouts.
- Basic authentication
tbd
Paul
How about, instead of logging someone out (unauthenticating
them), we unauthorize them until they perform some step to
get re-authorized?
- Jim
On further reading and contemplation .....
Maybe we should separate authentication from login
and authorization. This relates to the notion of
controlling your own priviledge. Your notion of
automatically reducing someone's priviledge is a special
case. Maybe we don't view "log-out" as a change in
authentication, or authorization (sort-of, email
is failing me).
"Logging" out can be viewed as stopping work in a
priviledged session. It could be orthoginal to
authentication. Maybe you still know I'm Jim, but I
don't want you to take anything I say seriously.
So, when we get a request from a funny place (or no
place), we log someone out, without necessarily
de-authenticating them. They must do something special to
be able to start doing priviledged things again.
The problem is that we need to make them, the human, do
something that javascript can't fake. This is the hard
part. It seems that the only way to be sure that
they are realy doing something is to make them enter a
secret that isn't available to javascript.
Using re-authentication is probably very problematic for
certificate authentication.
I wonder if there is some way to fight Javascript
with Javascript? I wonder if there is some Javascript
thing that we could do that could ask the user to
verify an action and that can't be subverted by attacking
Javascript.
- i4.3
It may be hard to allow someone to log in safely. For example,
we might not want to return a login form to a frame in a
malicious frame set, as java-script in the frame-set might be
able to steal the password from the form. :(
- i4.4
How do you get into a protected resource if the referer has
to be a local resource with a peer level of privilege? (The
"entry point" problem).
- Jim
Put another way. How does someone get into a
protected interface in the first place? They have to
authenticate. This hinges on the ability to log someone
out when they come from the wrong place.
- Brian
I just don't know if you can reliably tell the
difference in context. For example: My browser tries to
go to manage_main, sending no credentials and and empty
(or offsite) referer. The system challenges me. My browser
retries the request, sending my credentials and the same
empty or offsite referer. Zope sees my bad referer, logs
me out, I get challenged again... ad infinitum. Note that I
am making an assumption here that the referer
remains the same as the request that was initially challenged
(or becomes undefined). We should verify that.
- Jim
The change in context can be provided in two ways:
OTOH, it would be very nice if we didn't have to
mix-up authentication with this, although I
don't see a way around it right now. See my response to
Paul's comment in i4.2.
- i4.5
UI's may need to be redesigned to make greater use of
frames.
Consider zope.org. An "unpriviledged" page, like a news item
has links to priviledged pages, such as "Personalize". An
attempt to follow such a link would fail. We would need to
redesign this interface so that the menu was in a
priviledged page in one frame, while the news item was in a
separate page.
- Brian
I don't think that this will actually solve the
problem. The referer when you click on a link in the frame
will still be the actual page in the frame, not the frameset,
so the behavior would basically be the same as if frames were
not involved, wouldn't it? (unless you can design a site where
the "privileged frame" can drive everything and you never have
to click on a link in the "content" frame - that seems highly
unrealistic to me though)
Idea:
- Michael
Can the code that generates a "genuine" form include some kind of ID code that changes? If the form is not submitted with a valid ID then it is rejected. The validity of the ID also times out after a specified period.
I have implemented a system like this in a login form in ColdFusionx. When the form is generated it includes a hidden, random ID. A copy of the ID is held in a CF session variable. When the form is submitted, the ID on the submitted form must match that held in the session var for the login attempt to succeed. Sessions in CF are relationships between a CF "application" on a server and a client. They time out after a specified period. Perhaps have one ID for a whole session instead of a different one every time the form is created.
Could a clever client-side trojan find one of those forms and read the ID from it?
- Adamsc
this is exactly the approach I outlined in response to a BUGTRAQ posting on the same subject. Since you've already had to build or use a session manager to handle the logins properly, you can use either the session identifier directly or a random session variable for authentication (e.g. modify.php?ID=1234&Confirmed=RANDOM_SESSION_ID). The only way someone could create the fake form would be figuring out the session identifier; if your session manager is buggy enough to allow that, the attacker could directly hijack your system anyway.
- oliverb
The http/1.1 rfc also mentions the problem of a client side trojan( rfc2616, 9.1.1). While they don't go into depth, perhaps it's worth to cite one or two sentences:
"Implementors should be aware that the software represents the user in
their interactions over the Internet, and should be careful to allow
the user to be aware of any actions they might take which may have an
unexpected significance to themselves or others.
In particular, the convention has been established that the GET and
HEAD methods SHOULD NOT have the significance of taking an action
other than retrieval. These methods ought to be considered "safe".
This allows user agents to represent other methods, such as POST, PUT
and DELETE, in a special way, so that the user is made aware of the
fact that a possibly unsafe action is being requested."
So why not restrict the manage_* methods to just accept POSTedx requests. This wouldn't cure the problem of javascript, but the unsecurity of the client can't be the concern of the server side anyway.
|