You are not logged in Log in Join
You are here: Home » Members » jim » ZopeSecurity » ClientSideTrojan

Log in




Client side trojan issue


Imagine you have some kind of system that you administer through a web GUI, such as HotMail, your Netscape Admin server or a site like 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 JavaScript 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 JavaScript or other scripting support to take actions on the users behalf without him knowing it):

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.


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.


  • Provide control over privileges so that users can lower privileges and only raise them when necessary.
  • Allow users to perform common and useful task as an identified but unpriviledged user


Requires little or no software change.
Works on non-Zope sites.


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.
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.


See p1.1.

Provides a way to recover from damaging scripts
Unique to Zope


Doesn't work if a site doesn't support or allow undo.
Doesn't work with non-undoable transactions, such as RDBMS transactions.
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.
Doesn't help with inherently non-undoable operations, like undo.
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=SomeObject??. 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. :)


Leverages existing client behavior to get the required meta data to ensure request propriety.
Can likely be hidden behind the security policy abstraction, probably requires little or no user code changes.
Leverages a unique feature of the (new) Zope security model, which is that we check the privileges of the owner of executables.


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).

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.

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.
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.
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
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.
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.
All existing ZClient?? 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?)
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.
Would break xml-rpc, soap and other protocols that piggyback over HTTP unless we provide for some kind of special handling of those protocols.
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.
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.
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.
Can be defeated by Java-script, at least for within-site attacks.
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=SomeObject?. 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. :)


See p3.1, p3.2, p3.3.

Doesn't limit protection to POSTs? and GETs? with form data.
Can't be defeated by Java-script


See i3.2, i3.3, i3.4, i3.5, i3.6, i3.8, i3.9.

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".
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
You use a mini webapp (e.g. a CGI!) with the input of your current "username". It will keep issuing a 401 (thereby prompting the user to enter new, different user information) until the user accesses it with a different username. Having removed the web browser's previous concept of who to login to that realm with, this approach has successfully "logged out" the user.

A demo of this is available for download at


How about, instead of logging someone out (unauthenticating them), we unauthorize them until they perform some step to get re-authorized?

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.

Hm. 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.

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. :(
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).
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.
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.
The change in context can be provided in two ways:
  • Set a cookie
  • Set an opaque value in a Digest WWW-Authenticate header. (Note IE5 supports digest auth.)

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.

UI's may need to be redesigned to make greater use of frames.

Consider 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.

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)


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 ColdFusion?. 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?

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.
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 POSTed? 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.