一个常见的 XSS 攻击向量是攻击者以某种方式将 JS 代码输入到 Web 应用程序中,这样该代码然后显示在网页的 DOM 中并因此被激活的情况。
为了防止这种 XSS,您必须确保后端服务器不会将用户生成(未清理)的 html 发送到浏览器...(这与 qooxdoo 无关)。
也就是说,常规的 qooxdoo 小部件通常不会将数据显示为 html,因此即使没有智能服务器,您也相当安全。例外是 qx.ui.basic.Label 小部件及其后代。如果您设置rich 属性,Label 小部件能够直接显示HTML。 rich 属性默认设置为 false,但如果启用它,则必须确保不显示“危险”的 html 内容。
只有极少数(非必需的)qooxdoo 小部件允许您将 HTML 代码插入 DOM。在这些情况下,您必须注意清理数据。有问题的小部件是:
qx.ui.embed.Html
qx.ui.table.cellrenderer.Html
qx.ui.progressive.renderer.table.cell.Html
qx.ui.virtual.cell.Html
qx.ui.virtual.layer.HtmlCell
qx.ui.virtual.layer.HtmlCellSpan
如果您确实使用 qx.html.* 和 qx.bom.* 和 qx.dom.* 对象直接使用 DOM,那么您将超出 qooxoo 的范围,必须注意采取相应的措施。
另一个重要的攻击媒介是身份验证 cookie。大多数攻击都是通过让浏览器在用户不知道的情况下将请求与 cookie 一起发送到其服务器来实现的。
Qooxdoo 本身确实不要求您使用 cookie。由于 qooxdoo 应用程序设计运行在单个浏览器窗口中,因此您可以在不使用 cookie 的情况下工作。实现这样的事情的一种简单方法是拥有一个“服务器访问单例”,它负责与后端的所有通信,并在添加到每个请求的特殊标头中提供访问令牌。
下面的代码可以作为 cookie 问题的指南。
qx.Class.define('myapp.Server', {
extend : qx.io.remote.Rpc,
type : "singleton",
construct : function() {
this.base(arguments);
this.set({
timeout : 60000,
url : 'QX-JSON-RPC/',
serviceName : 'default'
});
},
properties: {
sessionCookie: {
init: null,
nullable: true
}
},
members : {
/**
* override the request creation, to add our 'cookie' header
*/
createRequest: function() {
var req = this.base(arguments);
var cookie = this.getSessionCookie();
if (cookie){
req.setRequestHeader('X-Session-Cookie',this.getSessionCookie());
}
return req;
}
}
});
如果您在myapp.uiLogin 中提供登录弹出窗口,您可以替换
标准callAsync,如果后端对您的请求不满意,则添加以下内容以弹出登录窗口。
/**
* A asyncCall handler which tries to
* login in the case of a permission exception.
*
* @param handler {Function} the callback function.
* @param methodName {String} the name of the method to call.
* @return {var} the method call reference.
*/
callAsync : function(handler, methodName) {
var origArguments = arguments;
var origThis = this;
var origHandler = handler;
var that = this;
var superHandler = function(ret, exc, id) {
if (exc && exc.code == 6) {
var login = myapp.uiLogin.getInstance();
login.addListenerOnce('login', function(e) {
var ret = e.getData();
that.setSessionCookie(ret.sessionCookie);
origArguments.callee.base.apply(origThis, origArguments);
});
login.open();
return;
}
origHandler(ret, exc, id);
};
if (methodName != 'login') {
arguments[0] = superHandler;
}
arguments.callee.base.apply(this, arguments);
},
查看the CallBackery application,了解它在实际应用程序中的工作原理。