网站漏洞处理总结

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

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 漏洞修复

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

注意: 攻击代码不一定在<script></script>中

  • 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  • 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
  • 对数据进行Html Encode 处理
  • 过滤或移除特殊的Html标签, 例如: <script>, <iframe> , < for <, > 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 类

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 过滤器

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 中增加过滤器相关

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

参考

http://topmanopensource.iteye.com/blog/2079474

2. tomcat 7 设置 cookie 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中定义一个异常。

  1. 修改tomcat/conf/context.xml
    <Context useHttpOnly="true"></context>
  2. 修改tomcat/conf/web.xml
<session-config>  
    <cookie-config>  
        <http-only>true</http-only>  
    </cookie-config></span>  
</session-config>
  1. 修改tomcat/conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"  
               connectionTimeout="20000"  
               redirectPort="8443" secure="true" />

参考

http://binary-space.iteye.com/blog/2373933

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> 

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容