draft document -- 2003年6月11日html
做为一名web开发者,任什么时候候当你构建一个Web应用时,有责任确保你的应用程序可以作什么和什么是应该作的:在发生错误的时候优雅的处理错误;让用户获取不到他们不该该查看的数据;防止恶意用户对应用程序进行的干扰操做。java
然而,详细的讨论如何去构建一个稳定的web应用程序是一个太过复杂的主题,这一篇短文设计的是构建基于Velocity的web应用程序常见的几个问题。短文是从一个开发者的角度写起的,他须要同大量的html模板开发人员和最终用户接触。咱们鼓励读者发表本身的意见,其余问题和相关的设计建议请致信 Velocity 用户列表,或者直接联系做者,Will Glass-Husain。web
Velocity 如何帮助开发者建立一个稳定的App数据库
一般,Velocity 是一个html设计师容易学会,而且不会难用的web模板工具。这一点基于以下的几个要素:apache
Velocity 模板语言(VTL)是简单的。 使用几个简单的指令,外加应用自己定义的引用,须要学习的东西少(也不怎么凌乱)。缓存
页面文件中不存储非展现用的信息。 对比JSP文件,它经常须要带上一个页面头文件。若是一个不懂技术的web设计师去掉了这个头部,那么这个JSP页面就不起做用了。在一个Velocity模板中这样的头部或者其余技术信息是不须要的。安全
在一个web页面中没有Java代码。 这样就消除了一些共有的错误和混乱设计,同时让恶意的页面编辑者去调用没必要要的Java代码变得困难。服务器
一个方法的异常不会阻塞一个页面的建立。 使用MethodExceptionEventHandler,一个方法异常能够被获取和记录日志。cookie
一个无效的引用不会阻塞一个页面的建立。 模板指令中无效的引用一般被忽略不计。页面中一个无效的引用将会简单的把其引用参考字打印出来。(好比:$foo)。app
基于如上的缘由,大部分Velocity开发者将会发现:没有什么离奇的现象或者问题,页面以一种直接的方式被渲染。
基于Velocity稳定和安全性的具体问题
考虑安全和稳定要素时,你须要意识到基于Velocity的web应用程序的几个特性。
Velocity 是一个模板工具, 而不是一个框架。 它不解决任何像认证、访问控制、会话状态或者数据持久化这样的问题。
VTL方法调用其实是Java的方法调用。 这意味着一个糟糕的velocity应用程序设计使得模板设计者改变系统的状态,直接执行SQL查询或者随意的实例化Java类。潜在的安全威胁将在下面被详细提到。
VTL引用具备Java类型。尽管对被模板编辑者是不可见的,每个引用仍是一个具备特定类型的Java对象。若是 $apple 是一个 integer 的 “1”, $orange是一个String 的“1”,$banana是一个 double 的 “1.0”,那么根据VTL这些对象没有一个是==(对等)的。典型的非技术html模板设计者可能会对此感到迷惑。(事实上,若是对象不是同一个类型的,会有对它们字符串值的比较。所以, 在VTL中, $apple和 $orange如今是对等的了。)
在构建安全,稳定的Velocity Web应用程序中的最佳实践。
以下所列是可以帮助你构建一个稳定的Velocity Web应用程序的最佳实践。它们包括:
在上下文环境context中审查全部没必要要的方法。
编码HTML特殊字符,以免交叉脚本漏洞。(cross-scripting)
使用最新且作了合适设置的app服务器。
进行适合生产中使用的Velocity配置
在上下文环境context中审查全部没必要要的方法。
开发者放在上下文环境中的引用通常有一到两个重要的目的。
一、提供在页面上面显示的动态信息(好比:当前用户的名字)。
二、提供辅助的控制结构和信息的从新格式化(好比:格式化数字的工具)。
把存在的对象或者bean放入上下文环境这样的作法是颇有诱惑力的。当你这样作的时候,你必须意识到一个很重的警告。模板能够调用对象在页面上下文环境中可用的任何公共方法。这意味着你应该当心地,只提供能安全的被模板设计者访问的方法。
为了隐藏没必要要的方法,开发者须要建立一个包装对象。须要重点注意的是,成为一个对象的子对象或者实现一个接口以隐藏方法作得还不够。缘由是:
使用接口对于模板设计者访问实现了这个接口的这个类的任何公共方法没有施加任何影响。
当模版设计者可以使用 VTL 指令 $reference.super().badmethod() 调用一个来自父类的方法时,采用子类的方式没有帮助。
有一些须要特别关注的事情:
不要包含那种拥有能够改变应用状态的任何方法的对象。那样作的话会破坏 MVC 模式,并且很难去调试。
避免拥有能够执行SQL查询的方法的对象/关系型数据库对象。Jakarta 项目 Torque 和 Turbine的用户须要特别注意的是:生成的Torque对象包含了一个能够访问org.apache.Torque.util.BasePeer 类的一个实体的getPeer方法。这个类包含了许多容许随意执行SQL查询的方法。
永远不要把文件和相似的对象放到上下文环境中。永远经过封装的对象展现文件系统信息。
编码HTML特殊字符,以免交叉脚本漏洞。
任什么时候候一个web应用程序要显示以前用户输入的文本,都存在一个包含非法文本的风险。一般,这样的文本可能包含将致使页面表现超出做者预期行为的,使用了Javascript 的 HTML 标签。当页面被第二我的看到的时候,这是一个问题:被包含的文本会弹开窗口;抓取cookie信息;或者拦截输入到表单里面的数据。正由于这是一个广泛的web应用程序设计问题,网上才会查到大量的有关这个潜在危险的更多信息。
解决办法是:在屏幕上显示它们以前,一直避免使用HTML特殊字符。至少,做以下的替换:
原文文本 替换文本
< <
> >
" "
& &
为了更好的可读性,也要替换这些:
原文文本 替换文本
回车符
两个空格 一个空格跟着
有四种可能被用到的替换文本的方法
一、你能够在处理用户输入时回避掉这样的文本,使用编码的形式存储它们。这对于模板设计者来讲是最简单的,可是会在当你须要在其余场景下使用没有回避的文本形式时引起问题。
二、你能够建立一个在显示时回避文本的工具。(例 1,以下)
三、你能够为上下文环境的全部文本建立一个封装的对象,自动回避这样的字符串。(例 2)。
四、如 Danil Dekany 建议的那样,Velocity 能够包含一个新的,能够在块内自动回避文本的指令#escape。
例 1:Velocity 回避文本的工具。
$HTMLText.setText($textFromUser).Escaped
$HTMLText.setText($textFromUser).EscapedMultiLine
第一行全部的 HTML 字符都会被回避掉, 显示 $textFromUser 的原始文本。第二将把任何传入的返回转换成
表现形式。(注意:你将不会想在全部状况下都这样作。好比:你应该包含做为在一个表单textarea域中Enter值的传入返回值。
例 2:使用一个封装的文本处理对象。
$textFromUser.Escaped
$textFromUser.EscapedMultiLine
$textFromUser.PlainText
在这个例子中, 上下文环境中的 $textFromUser 被定义成了一个拥有 Escaped,EscapedMultiLine 和 PlainText 属性的封装对象。第一个属性显示 HTML 代码被避免的文本。第二个也编码的传入返回。最后一个属性返回跟输入时同样的文本。若是三个属性一个都没有给出,默认显示的文本应该被避免掉。
例 3:使用 #escape 指令(没有被实现)。
#escape("html")
... Tons of HTML here...
... interpolations will be implicitly escaped
#end
使用最新且作了合适设置的app服务器。
对于任何web应用程序,确保你基于Velocity的app是运行于使用最近更新或者服务包的应用服务器上。研究研究跟安全相关的配置设置,跟踪已经发布的漏洞。做者遇到的一些问题包括:
配置你的应用服务器,使用 -Xmx java 命令行选项使Java虚拟机容许一个足够的最大栈空间。若是没有这个设置,你有的应用颇有可能抛出 OutOfMemoryError 。
当使用一个web服务器和Apache Tomcat 时,你常常必须明确禁止用户访问 WEB-INF, META-INF,和其余系统路径。
上溯至版本 4.1.12 版本的 Apache Tomcat 应该欺骗性的使用 DefaultServlet 来显示 Velocity 页面, JSP,或者任何其余web树结构中的模板,它们的源代码。
配置一个 Java Security Manager 限制文件的访问(从web 树和模板路径的外部)和危险的方法,如 System.exit()和 getClassLoader 的访问。这已经被技术性的包含在了现当前版本的Velocity中(1.3.1),没有被彻底支持。尤为是,一些Velocity类须要访问Classloader,而其它应该被严格限制。若是你对于这些问题不是很熟悉,Velocity用户列表也许能帮助你着手开始。
只有一个基本的准则——当心关注你的特有系统的问题。
进行适合生产中使用的Velocity配置
一个安装在生产服务器上的web应用程序比开发环境下,一般在配置上有很大的不一样。确保利用Velocity的扩展性的 develope-guide.html#Velocity配置Keys和Values配置选项,去建立一个稳定和专业的部署。
下面是一些建议:
建立一个 EventCartridge 和 Event Handler 去获取方法异常。记录异常日志,可是运行页面继续进行处理。
打开Velocity页面的缓存,除了能加速页面渲染的处理外,这样也避免了在必然的状况下因为过分的也页面内调致使的“内存溢出”。
建立赞成的错误页面,以赞成你的应用的观感。在获取到 ParseErrorException 和 ResourceNotFoundException 时显示这个错误页面(由 Velocity.getTemplate()抛出)。包含一个对用户友好的错误消息(以Velocity引用的形式传给页面),而且为 开发者和系统管理员记录技术性的详细日志。
同不受信任的HTML 模板设计者一块儿工做
(注意:下面一些特定的引用代码是过期的。见版本1.5 WGH的增补清单 - 2005/10/7)
许多Velocity应用程序,一小组人(或者仅仅一我的)为开发一个web应用而协同工做。这种状况下,开发者主要关注的是为最终用户建立一个用户友好的安全应用。开发者为页面设计提供一些简单的技术指导,大部分有尤为是一个VTL引用工具清单,和一些访问web树的CVS和FTP设置。在这个广泛的场景中,开发者和模板编辑者都有确保让应用安全平稳的进行工做的责任。
其余的Veloctiy应用,一大群模板设计者建立模板文件,也许是来自外部的开发组织。经常,这些模板设计者没有直接访问CVS树或者web文件系统。而多是经过一个web管理界面上传他们为这个web应用上传的模板文件。这在中状况下,模板编辑者应该被看作是不受信任的。不论是什么模板被上传到了系统里面,都须要特别关注web应用程序的集成。
然而不彻底清楚到底有多少Velocity Web 应用程序是属于这个范畴的,做者遇到过五六个建立过这种类型应用程序的开发者。做者本身也管理这一个基于Velocity的web站点,里面有上百个HTML模板设计者,他们拥有具备上传模板能力的帐号。
一些在同不受信任的模板设计者一块儿开发一个web应用程序时的注意事项:
如上所述,在上下文环境中只提供安全的引用。方法不能改变app的状态、执行SQL查询,或者访问文件系统。
复审 #include 和 #parse 的潜在使用。在做者的应用程序中,模板文件盒私有的用户数据起初被存储在同一个资源路径下的web树的平行目录中。这意味着任何模板用户能使用来自另一个用户的模板和数据。Serge Knystautas 提出了一个针对这个困境的可能的解决方案,它是去建立一个跟用户相关资源加载器,加载属于当前用户的模板文件。另外的一个解决办法是使用一个做者开发Velocity的包,它容许开发者经过使用事件Handler控制实际由 #include 和 #parse 返回的模板。(典型的,这将限制每一个帐户只包含那个帐户中的页面)。(更新:新的事件Handler包含在源代码树中,发布于 版本 1.5 - WGH中)
此外,上面关于配置一个security manager的话题在这种类型的应用中变得很重要。开发者应该意识到模板设计者具备调用 getClassLoader() 返回一个可以在默认配置中实例化任何类和调用任何方法的 ClassLoader。做者已经为Velocity推出了一个限制这种危险能力的包。(更新:计划于版本 1.6 - WGH 中)
明确的最安全的途径是限制模板设计在一小组受信任的模板编辑者中。然而,在有一大群用户能够上传模板的状况下,Velocity仍然是一个有用的工具。这种状况下,你必须更加当心的考虑围绕系统集成和安全衍生的问题。
鸣谢
做者很感谢velocity用户列表中的许多为这些相关问题提供过建议,特别是那些加入了这个 discussion thread 中的成员。
这里是原文的地址:
http://wiki.apache.org/velocity/BuildingSecureWebApplications