Fork me on GitHub

网站漏洞处理总结

最近实验室网站检测出了漏洞,需要修复,以下对修复内容给做点总结

1. XSS 攻击

XSS 攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为 XSS,XSS 是一种在web应用中的计算机安全漏洞,它允许恶意 web 用户将代码植入到提供给其它用户使用的页面中。

XSS 如何发生

假如有下面一个textbox

<input type="text" name="address1" value="value1from">

value1from是来自用户的输入,如果用户不是输入value1from,而是输入

"/><script>alert(document.cookie)</script><!-

那么就会变成

<input type="text" name="address1" value=""/><script>alert(document.cookie)</script><!- ">

嵌入的JavaScript代码将会被执行

或者用户输入的是 "onfocus="alert(document.cookie) 那么就会变成
<input type="text" name="address1" value="" onfocus="alert(document.cookie)">

事件被触发的时候嵌入的JavaScript代码将会被执行
攻击的威力,取决于用户输入了什么样的脚本

HTML Encode

XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的”中括号”, “单引号”,“引号” 之类的特殊字符进行编码。

XSS 漏洞修复

原则: 不相信客户输入的数据

注意: 攻击代码不一定在

  • 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  • 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
  • 对数据进行Html Encode 处理
  • 过滤或移除特殊的Html标签, 例如: <script>, <iframe> , &lt; for <, &gt; for >, &quot for
  • 过滤JavaScript 事件的标签。例如 “onclick=”, “onfocus” 等等。

HTML Encode 和URL Encode的区别

刚开始我老是把这两个东西搞混淆, 其实这是两个不同的东西。
HTML编码前面已经介绍过了,关于URL 编码是为了符合url的规范。因为在标准的url规范中中文和很多的字符是不允许出现在url中的。
例如在baidu中搜索”测试汉字”。 URL会变成
http://www.baidu.com/s?wd=%B2%E2%CA%D4%BA%BA%D7%D6&rsv_bp=0&rsv_spt=3&inputT=7477

所谓URL编码就是: 把所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)

输入过滤实现

新建 XssHttpServletRequestWrapper 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.jeecms.common.web;
import static com.jeecms.common.web.Constants.UTF8;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* @author Tom
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private String[]filterChars;
private String[]replaceChars;
public XssHttpServletRequestWrapper(HttpServletRequest request,String filterChar,String replaceChar,String splitChar) {
super(request);
if(filterChar!=null&&filterChar.length()>0){
filterChars=filterChar.split(splitChar);
}
if(replaceChar!=null&&replaceChar.length()>0){
replaceChars=replaceChar.split(splitChar);
}
}
public String getQueryString() {
String value = super.getQueryString();
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
public String[] getParameterValues(String name) {
String[]parameters=super.getParameterValues(name);
if (parameters==null||parameters.length == 0) {
return null;
}
for (int i = 0; i < parameters.length; i++) {
parameters[i] = xssEncode(parameters[i]);
}
return parameters;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/> getHeaderNames 也可能需要覆盖
*/
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 将容易引起xss漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private String xssEncode(String s) {
if (s == null || s.equals("")) {
return s;
}
try {
s = URLDecoder.decode(s, UTF8);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < filterChars.length; i++) {
if(s.contains(filterChars[i])){
s=s.replace(filterChars[i], replaceChars[i]);
}
}
return s;
}
}

新建 XSSFilter 过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.jeecms.common.web;
/**
* @author Tom
*/
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class XssFilter implements Filter {
private String filterChar;
private String replaceChar;
private String splitChar;
FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterChar=filterConfig.getInitParameter("FilterChar");
this.replaceChar=filterConfig.getInitParameter("ReplaceChar");
this.splitChar=filterConfig.getInitParameter("SplitChar");
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request,filterChar,replaceChar,splitChar), response);
}
}

在 web.xml 中增加过滤器相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<filter>
<filter-name>XssFilter</filter-name>
<filter-class>com.jeecms.common.web.XssFilter</filter-class>
<init-param>
<param-name>SplitChar</param-name>
<param-value>@</param-value>
</init-param>
<init-param>
<param-name>FilterChar</param-name>
<param-value>'@"@\@#@:@%@></param-value>
</init-param>
<init-param>
<param-name>ReplaceChar</param-name>
<param-value>\'@\"@\@#@:@\\%@></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XssFilter</filter-name>
<url-pattern>*.jspx</url-pattern>
</filter-mapping>

Tomcat 7对会话cookie自动启用HttpOnly cookie标记,查看配置以确保该选项为被禁用。

要启用HttpOnly,必须在 CATALINA_BASE/conf/context.xml 中做如下设置,使之全局应用于所有应用程序:

在需要通过JavaScript访问会话cookie的情况下,使用HttpOnly可能会影响应用程序功能。如果应用程序需要通过JavaScript访问HttpOnly cookie,可以在METAINF/context.xml中一个单独的Context中定义一个异常。

  1. 修改tomcat/conf/context.xml
    <Context useHttpOnly="true"></context>
  2. 修改tomcat/conf/web.xml
    1
    2
    3
    4
    5
    6
    7
    <session-config>
    <cookie-config>
    <http-only>true</http-only>
    </cookie-config></span>
    </session-config>
    ```
    3. 修改tomcat/conf/server.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## 3. tomcat 禁用不安全的http请求模式
WebDAV (Web-based Distributed Authoring and Versioning) 一种基于 HTTP 1.1协议的通信协议.它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对Web Server直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”)来表明Request-URI指定的资源的不同操作方式:
- OPTIONS 返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。 
- HEAD 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。 
- GET 向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在web app.中。其中一个原因是GET可能会被网络蜘蛛等随意访问。 
- POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 
- PUT 向指定资源位置上传其最新内容。 
- DELETE 请求服务器删除Request-URI所标识的资源。 
- TRACE 回显服务器收到的请求,主要用于测试或诊断。 
- CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 
- 方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed);当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。 
- HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。当然,所有的方法支持的实现都应当符合下述的方法各自的语义定义。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。
- http的访问中,一般常用的两个方法是:GET和POST。其实主要是针对DELETE等方法的禁用。
tomcat conf web.xml(url下禁用的请求方式)

<security-constraint>  
    <web-resource-collection>  
        <url-pattern>/*</url-pattern>  
        <http-method>PUT</http-method>  
        <http-method>DELETE</http-method>  
        <http-method>HEAD</http-method>  
        <http-method>OPTIONS</http-method>  
        <http-method>TRACE</http-method>  
    </web-resource-collection>  
    <auth-constraint>  
        </auth-constraint>  
    </security-constraint>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## 4. HttpOnly标记
Tomcat 7对会话cookie自动启用HttpOnly cookie标记,查看配置以确保该选项为被禁用。
要启用HttpOnly,必须在 `CATALINA_BASE/conf/context.xml` 中做如下设置,使之全局应用于所有应用程序:
`<Context useHttpOnly='true' .../>`
在需要通过JavaScript访问会话cookie的情况下,使用HttpOnly可能会影响应用程序功能。如果应用程序需要通过JavaScript访问HttpOnly cookie,可以在METAINF/context.xml中一个单独的Context中定义一个异常。
## 5. 错误页面Web应用服务器版本泄露
Web服务器未能正确处理异常请求导致Web服务器版本信息泄露,攻击者收集到服务器信息后可进行进一步针对性攻击。
由于默认的错误页面会泄露一些内部信息(比如版本号和堆栈轨迹),所以应该用包含一般错误信息(比如处理您的请求时出错了)的自定义错误页面取而代之。
每个web应用程序的web.xml文件里应包含以下配置,该文件位于CATALINA_HOME/webapps/$WEB_APP/WEB-INF:
<error-page>
    <error-code>500</error-code>
    <location>/errorpages/error.html</location>  
</error-page>
<error-page>
    <exception-type>java.lang.Throwable</exception-type>  <location>/errorpages/error.html</location>
</error-page>

```

此外,如果Manager应用程序没被移除,必须手动将位于 CATALINA_HOME/webapps/manager/WEB-INF/jsp/ 的错误页面里的“Tomcat 7“版本信息移除。

参考

http://topmanopensource.iteye.com/blog/2079474
http://binary-space.iteye.com/blog/2373933
http://www.voidcn.com/article/p-edpibtrp-bnw.html

------------- The endThanks for reading-------------