1 安全编码原则
保持简单,程序只实现指定的功能。
坚持最小权限,把可能造成的危害降到最低。
默认不信任,采用白名单机制,只放行已知的操作。
永远不要相信用户的输入,对所有输入进行前台和后台两次检查。
2 常见WEB潜在问题
- 输入验证:嵌入到查询字符串、表单字段、cookie 和 HTTP 头中的恶意字符串的攻击。这些攻击包括命令执行、跨站点脚本(XSS)、SQL 注入和缓冲区溢出攻击。
- 身份验证:标识欺骗、密码破解、特权提升和未经授权的访问。
- 授权验证:访问保密数据或受限数据、篡改数据以及执行未经授权的操作。
- 配置管理:对管理界面进行未经授权的访问、具有更新配置数据的能力以及对用户帐户和帐户配置文件进行未经授权的访问。
- 敏感数据:泄露保密信息以及篡改数据。
- 会话管理:捕捉会话标识符,从而导致会话劫持及标识欺骗。
- 加密管理:访问保密数据或帐户凭据,或二者均能访问。
- 参数操作:路径遍历攻击、命令执行以及绕过访问控制机制,从而导致信息泄漏、特权提升和拒绝服务。
- 异常管理:拒绝服务和敏感的系统级详细信息的泄漏。
- 审核和记录:不能发现入侵迹象、不能验证用户操作,以及在诊断时出现困难。
3 基本开发安全规范
3.1 跨站点脚本(XSS)防范
XSS的类型:反射型XSS、存储型XSS、DOM型XSS。
跨站点脚本防范的基本原则:
一切的输入/输出都是有害的,不要信任任何输入/输出数据。
所有传递过程都不能保障无侵入,执行前、存储前、显示前都要进行”数据清洗”。
所有的数据校验、处理工作要在前端和服务器端两次进行。
目前所有的XSS通过com.keegoo.core.util.XSSUtil来过滤。
DOM-based XSS的防范当操作页面中DOM对象的时候,要对其输入的参数进行处理,防止XSS的注入。可采用escape、encodeURI、encodeURIComponent或自定义方法进行处理。示例:
window.location=encodeURI("http://www.dhgate.com");
对输入/输出进行Encode 将输入/输出进行转义成HTML实体编码(ISO 8859-1 Latin1)或其他编码,使得其在浏览器中不可自动执行。
不要在html元素和属性中使用未经转义的不安全内容。
3.2 防SQL注入规范
防SQL注入基本原则:所有用户输入都必须进行合法性校验。所有数据库SQL操作必须参数化。
回收开发人员等操作生产库权限:减少开发人员、非DBA操作生产库的权限;数据库数据查询要有权限分级和审核。
尽量使用PreparedStatement代替Statement,一方面,在大多数情况下,使用PreparedStatement的性能将优于使用Statement,另外一方面,可以最大限度的减少SQL注入发生的可能行。
用户提交的数据都应该做合法性校验,避免用户输入’,””,-,%,#,&,|,@,+等有可能导致SQL注入的危险字符给系统造成危害。
3.3 页面组件安全防范
页面标签必须关闭,属性值必须加引号。在页面中使用的标签不关闭,属性值不加引号往往成为被攻击点,攻击者很容易的利用这些漏洞进行注入。避免这些漏洞的出现可以提高被攻击的可能。
Form提交方式必须选用POST。Form默认的提交方式是Get,这种方式将表单中数据的按照variable=value的形式,使用”?”添加至Action所指向的URL后面,各个变量之间使用”&”连接。所要传递的信息量除受URL长度限制之外,信息内容都显示暴露。在使用Form的时候必须将提交方式置为POST。示例:
<form action="…" method="post" target="_blank">…</form>
所有的非ASCII字符在URL中传递时都需要按照协商好的编码方式做URL编码
推荐使用encodeURI、encodeURIComponent或者自定义encode实现。encodeURI、encodeURIComponent默认都返回UTF8编码的URL,区别在于encodeURI方法不会对下列字符进行编码: “:”、”/“、”;” 和 “?”。而encodeURIComponent则会对这些字符进行编码处理。尽量使用对象的innerText,不要使用innerHtml属性
对象的innerText属性默认会对输入的数据进行encode,使得如果数据的数据还有html可执行标记时不会直接执行,而如果使用innerHtml属性的话不会保障。输入框设置最大长度、输入数据类型限制。
输入框一般是攻击者比较钟意的攻击对象,攻击者可以通过输入框限制不足的弱点进行数据窃取(比如SQL注入)、或者制造迫害(如比XSS)。我们可以通过对输入框最大长度、输入数据类型的限制,从一定程度上防范这样的攻击。我们可以根据实际需求,对一些输入框限定只允许输入字母、数字等。同时对输入的数据长度做限制。关闭客户端自动完成功能,减少驻留在客户端数据。
设置
<Frame>/<iFrame>
受限,防止脚本执行
将<Frame>/<iFrame>
中security属性设置为restricted后, Frame中的脚本将不能执行(仅限于IE)。
3.4 敏感数据的安全防范
不能任意在Cookie、Session、ServletContext中存放数据,对于这些对象中存放的数据,必须有统一定义、说明、Lifecycle的管理等。
对于敏感信息都必须保障其私密性。在页面显示、操作交互中不可避免的会有一些如用户的标识信息、密码、帐号信息、涉及的金额信息等敏感数据(保密性的数据)的存在。为保障这些数据不被曝露而提高安全性,我们要做到所有敏感信息必须进行加密处理,不能以明文的形式存在于任何网络、内存及其它持久化介质中(如:数据库、文件磁盘系统等)。
所有的密码、key、帐号等机密信息都不能在URL中传递。
所有的密码、key、银行账号等机密信息都不能存储到Cookie,Session、ServletContext中。
防止信息泄漏:
在系统上线使用的log level对应的日志输出中不允许包含任何密码、key、账号等机密信息。
SVN集成分支上的代码中不允许存留可用的system.out/err.print语句。
在测试/调试阶段所使用的测试页面、单元测试模块等不允许提交到SVN集成分支上。
不允许将系统产生的错误异常信息直接显示给用户,需要有统一的错误处理。
尽量减少不必要的信息传递。在信息的传递过程中,如果当前Step中的对象、对象的属性、参数等在下一个Step中不需要,则不要再做传递,甚至可以显式的销毁。这样可以有效的减少信息被截获的机率,特别是敏感数据(例如用户密码、账户信息等等)。
3.5 WEB安全防范
- Cookie的安全防范:
(1)存储于cookie中的敏感数据必须加密。
(2)没有特殊要求下,尽量使用会话cookie(非持久化)。
(3)如果使用持久化cookie应该设置cookie超时。
(4)激活cookie安全传输,表示创建的 cookie 只能在https连接中被浏览器传递到服务器端进行会话验证,如果是http连接则不会传递该信息。
必须设置session的超时时间。web.xml中配置示例:
<session-config> <session-timeout>10</session-timeout> </session-config>
必须构建统一的错误处理页面。web.xml示例:
<error-page> <error-code>500</error-code> <location>/error.jsp</location> </error-page>
多线程中线程安全的防范:
- 尽量少用静态(static)变量和static方法。(除了静态常量:static final constants)。
- 尽量多线程框架(java.util.concurrent)构建多线程同步机制。
- 使用ThreadLocal避免多个线程之间类成员的共享冲突。
- 如非必要,不要使用synchronized关键字。必须要使用synchronized时,应将同步范围最小化,即将同步作用到最需要的地方,避免大块的同步块或方法等。
- 增加Referer的检查,防止非法访问。Referer是HTTP Header中的一个字段,当浏览器想服务器发送请求时,Referer用来通知服务器请求发起的位置。