java-web過濾器-XSS

新項(xiàng)目為了防止XSS攻擊辽装,直接把所有的html標(biāo)簽都過濾成""了,導(dǎo)致有個(gè)地方需要編輯存儲(chǔ)富文本的功能用不了了/(ㄒoㄒ)/~~透葛,產(chǎn)品讓我改续镇,我表示還沒寫過專門針對(duì)富文本的過濾器,我也沒好好研究過javaWeb的過濾器陵究,今天學(xué)習(xí)了一下眠饮。寫了個(gè)比較簡單的針對(duì)XSS攻擊的過濾器。

基本思路就是把http請(qǐng)求的參數(shù)攔截下來铜邮,針對(duì)一些特殊的字符過濾一遍仪召。
首先寫一個(gè)過濾器寨蹋。

public class XSSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        ModifyParametersWrapper wrapper = new ModifyParametersWrapper((HttpServletRequest) httpServletRequest);
        filterChain.doFilter(wrapper, httpServletResponse);
    }
     /**
     * 繼承HttpServletRequestWrapper,創(chuàng)建裝飾類扔茅,以達(dá)到修改HttpServletRequest參數(shù)的目的
     */
    private class ModifyParametersWrapper extends HttpServletRequestWrapper {

        private Map<String, String[]> requestParams;

        public ModifyParametersWrapper(HttpServletRequest request) {
            super(request);
        }

        /**
         * 獲取指定參數(shù)名的值已旧,如果有重復(fù)的參數(shù)名,則返回第一個(gè)的值 接收一般變量 召娜,如text類型
         *
         * @param name 指定參數(shù)名
         * @return 指定參數(shù)名的值
         */
        @Override
        public String getParameter(String name) {
            String parameter = null;
            String[] vals = getParameterMap().get(name);

            if (vals != null && vals.length > 0) {
                parameter = vals[0];
            }

            return parameter;
        }

        /**
         * 獲取指定參數(shù)名的所有值的數(shù)組
         */
        @Override
        public String[] getParameterValues(String name) {
            return getParameterMap().get(name);
        }

        @Override
        public Map<String, String[]> getParameterMap() {
            if (requestParams == null) {
                requestParams = new HashMap<String, String[]>();
                Map<String, String[]> originalQueryString = super.getParameterMap();
                if (originalQueryString != null) {
                    for (Map.Entry<String, String[]> entry : originalQueryString.entrySet()) {
                        //對(duì)參數(shù)名進(jìn)行過濾
                        String key = HTMLFilterUtil.cleanXSS(entry.getKey());
                        //對(duì)每個(gè)傳參進(jìn)行過濾
                        String[] rawValues = entry.getValue();
                        String[] filteredValues = new String[rawValues.length];
                        for (int i = 0; i < rawValues.length; i++) {
                              //具體的過濾規(guī)則
                            filteredValues[i] = HTMLFilterUtil.cleanXSS((rawValues[i]));
                        }
                        requestParams.put(key, filteredValues);
                    }
                }
            }
            return requestParams;
        }
}

具體的過濾規(guī)則
 /**
     * 標(biāo)簽部分轉(zhuǎn)譯
     * @param value
     * @return
     */
    public static String cleanXSS(String value) {
        //屏蔽掉xss攻擊和sql注入等危險(xiǎn)字符
        value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
        value = value.replaceAll("'", "&#39;");
        value = value.replaceAll("\"", "&#34;");


        value = value.replaceAll("\\\\", "");
        value = value.replaceAll("\\\\/", "");

        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("e-xpression\\\\((.*?)\\\\)\"", "");

        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("[\\\"\\\'][\\s]*vbscript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("[\\\"\\\'][\\s]*onload:(.*)[\\\"\\\']", "\"\"");
        return value;
    }

 /**
     * 標(biāo)簽全過濾
     * @param inputString
     * @return
     */
    public static String Html2Text(String inputString) {
        String htmlStr = inputString; //含html標(biāo)簽的字符串
        String textStr = "";
        java.util.regex.Pattern p_script;
        java.util.regex.Matcher m_script;
        java.util.regex.Pattern p_style;
        java.util.regex.Matcher m_style;
        java.util.regex.Pattern p_html;
        java.util.regex.Matcher m_html;

        try {
            String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; //定義script的正則表達(dá)式{或<script[^>]*?>[\\s\\S]*?<\\/script> }
            String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; //定義style的正則表達(dá)式{或<style[^>]*?>[\\s\\S]*?<\\/style> }
            String regEx_html = "<[^>]+>"; //定義HTML標(biāo)簽的正則表達(dá)式

            p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
            m_script = p_script.matcher(htmlStr);
            htmlStr = m_script.replaceAll(""); //過濾script標(biāo)簽

            p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
            m_style = p_style.matcher(htmlStr);
            htmlStr = m_style.replaceAll(""); //過濾style標(biāo)簽

            p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
            m_html = p_html.matcher(htmlStr);
            htmlStr = m_html.replaceAll(""); //過濾html標(biāo)簽

            textStr = htmlStr;
            // 過濾單雙引號(hào)
            textStr = textStr.replaceAll("\'", "&#39;");
            textStr = textStr.replaceAll("\"", "&#34;");
            textStr = textStr.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
            textStr = textStr.replaceAll("eval\\((.*)\\)", "");
            textStr = textStr.replaceAll("\\\\", "");
            textStr = textStr.replaceAll("\\\\/", "");

        } catch (Exception e) {
            System.err.println("Html2Text: " + e.getMessage());
        }

        return textStr;
    }

這樣可以過濾掉@RequestParam的參數(shù)运褪,但是如果要過濾直接post的json字符串需要重寫以下方法。

        private byte[] requestBody = null;

        public ModifyParametersWrapper(HttpServletRequest request) {
            super(request);
            try {
                requestBody = StreamUtils.copyToByteArray(request.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (requestBody == null) {
                requestBody = new byte[0];
            }
            //可以對(duì)字符串進(jìn)行操作玖瘸,但是我覺得json這種的還是反序列話為對(duì)象之后再處理比較好秸讹,
            String json = new String(requestBody, "UTF-8");
            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
            return new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return bais.read();
                }

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return true;
                }

                @Override
                public void setReadListener(ReadListener listener) {

                }
            };
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

最后需要把過濾器配置好。
下面是配置多個(gè)過濾器的方法雅倒。

@Configuration
public class FilterConfig {

    /**
     * 配置過濾器
     * 按照order值的大小璃诀,從小到大的順序來依次過濾
     * @return
     */
    @Bean
    @Order(Integer.MAX_VALUE - 1)
    public FilterRegistrationBean someFilterRegistration1() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(xssFilter());
        registration.addUrlPatterns("/filter/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("xssFilter");
        return registration;
    }

    /**
     * 配置過濾器
     * 按照order值的大小,從小到大的順序來依次過濾
     * @return
     */
    @Bean
    @Order(Integer.MAX_VALUE)
    public FilterRegistrationBean someFilterRegistration2() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(sessionFilter());
        registration.addUrlPatterns("/session/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("sessionFilter");
        return registration;
    }


    /**
     * 創(chuàng)建一個(gè)bean
     * @return
     */
    @Bean(name = "xssFilter")
    public Filter xssFilter() {
        return new XSSFilter();
    }
    /**
     * 創(chuàng)建一個(gè)bean
     * @return
     */
    @Bean(name = "sessionFilter")
    public Filter sessionFilter() {
        return new SessionFilter();
    }
}

這樣一個(gè)基本的過濾器就完成了蔑匣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劣欢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子裁良,更是在濱河造成了極大的恐慌凿将,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趴久,死亡現(xiàn)場離奇詭異丸相,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)彼棍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門灭忠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人座硕,你說我怎么就攤上這事弛作。” “怎么了华匾?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵映琳,是天一觀的道長。 經(jīng)常有香客問我蜘拉,道長萨西,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任旭旭,我火速辦了婚禮谎脯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘持寄。我一直安慰自己源梭,他們只是感情好娱俺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著废麻,像睡著了一般荠卷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烛愧,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天油宜,我揣著相機(jī)與錄音,去河邊找鬼屑彻。 笑死验庙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的社牲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼悴了,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼搏恤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起湃交,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤熟空,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后搞莺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體息罗,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年才沧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迈喉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡温圆,死狀恐怖挨摸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岁歉,我是刑警寧澤得运,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站锅移,受9級(jí)特大地震影響熔掺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜非剃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一置逻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧努潘,春花似錦诽偷、人聲如沸坤学。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽深浮。三九已至,卻和暖如春眠冈,著一層夾襖步出監(jiān)牢的瞬間飞苇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工蜗顽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留布卡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓雇盖,卻偏偏與公主長得像忿等,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子崔挖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.過濾器Filter簡介: 過濾器顧名思義就是位于中間層起到過濾作用的贸街,用于攔截請(qǐng)求或響應(yīng)信息。過濾器 (Fil...
    流川楓AI閱讀 873評(píng)論 0 6
  • 僅作為自己學(xué)習(xí)記錄使用狸相,文章來自: 1薛匪、http://blog.csdn.net/csh624366188/art...
    BakerZhang閱讀 1,013評(píng)論 1 5
  • Service的啟動(dòng) 一、概要 service的啟動(dòng)相對(duì)activity的啟動(dòng)來說比較簡單脓鹃。這里以startSer...
    Jesse_zhao閱讀 882評(píng)論 0 2
  • 2013-09-14 23:00:07 27:15巡撫有一個(gè)常例逸尖,每逢這節(jié)期,隨眾人所要的瘸右,釋放一個(gè)囚犯給他們娇跟。 ...
    大大花生閱讀 1,895評(píng)論 0 1
  • 孫子問:“爺爺,你這輩子最幸福的事情是什么尊浓?” 爺爺答:“娶了你奶奶逞频。” 孫子雙手拖腮栋齿,接著問:“那你們之間的故事...
    張記豐老師閱讀 429評(píng)論 0 3