JSP <c:out>标签中的escapeXML方法转义了哪些字符?

JSP的<c:out>标签有如下属性:

属性 描述 是否必要 默认值
value 要输出的内容
default 输出的默认值 主体中的内容
escapeXml 是否忽略XML特殊字符 true

 

value,default,以及escapeXML。

这里要讲述的就是escapeXML。

从上面的表格中可以看出,escapeXML属性默认值是true

 

一般我们用<c:out>标签的时候,最常用的就是value属性,对于escapeXml属性,却常常的忽略。

escapeXml的意思,就是对value值进行过滤,将其中的特殊字符给转义掉。

因为escapeXml的默认值是true的缘故,也就是默认开启了对value值的转义,这就默认的,让你在使用<c:out>标签时,提供了安全性。

许多没有意识到escapeXml优点的开发者,往往嫌弃<c:out>太麻烦,于是在页面输出值中,直接使用了el表达式。

我们看两个例子。

<body>

	<% 
	request.getServletContext().setAttribute("name", "hello escapeXml");
	 %>
	<div>
		<c:out value="${name}" escapeXml="true"></c:out>
	</div>
	<div>
		${name}
	</div>
	
</body>

 

以上的代码,页面输出结果是:

hello escapeXml

hello escapeXml

确实,在这种情况下,用<:out>以及用el表达式直接输出,结果是一样的。

但是稍微改一下,代码改动为:

<body>

	<% 
	request.getServletContext().setAttribute("name", "<script>document.write('hello escapeXml')</script>");
	 %>
	<div>
		<c:out value="${name}" escapeXml="true"></c:out>
	</div>
	<div>
		${name}
	</div>
	
</body>

 

页面的输出结果就变成了

<script>document.write('hello escapeXml')</script>

hello escapeXml

 

第一行,带有script标签的,确实是我们想要输出的内容,用<c:out>也完美的输出了!

第二行,直接使用el表达式,结果却是hello escapeXml,很明显,直接使用el表达式,实际上,执行了<script>中的js语句。

 

这就是漏洞的来源,可被用于XSS跨站攻击。

 

由此可见,在JSP页面输出结果,用<c:out>明显是安全的,原因在于escapeXml方法转义了可能影响安全的特殊字符,即便你在编写代码的时候,忘记给<c:out>加上escapeXml,也不要紧,因为escapeXml缺省的默认值是true。

 

那么,escapeXml方法到底转义了哪些字符呢?

关于这个,可以从JSTL的源码包中找到答案,主要看的OutSupport这个类。

package org.apache.taglibs.standard.tag.common.core;

import java.io.IOException;
import java.io.Reader;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;

/**
 * <p>Support for handlers of the &lt;out&gt; tag, which simply evalutes and
 * prints the result of the expression it's passed.  If the result is
 * null, we print the value of the 'default' attribute's expression or
 * our body (which two are mutually exclusive, although this constraint
 * is enforced outside this handler, in our TagLibraryValidator).</p>
 *
 * @author Shawn Bayern
 */
public class OutSupport extends BodyTagSupport {

    /*
     * (One almost wishes XML and JSP could support "anonymous tags,"
     * given the amount of trouble we had naming this one!)  :-)  - sb
     */

    //*********************************************************************
    // Internal state

    protected Object value;                     // tag attribute
    protected String def;			// tag attribute
    protected boolean escapeXml;		// tag attribute
    private boolean needBody;			// non-space body needed?

    //*********************************************************************
    // Construction and initialization

    /**
     * Constructs a new handler.  As with TagSupport, subclasses should
     * not provide other constructors and are expected to call the
     * superclass constructor.
     */
    public OutSupport() {
        super();
        init();
    }

    // resets local state
    private void init() {
        value = def = null;
        escapeXml = true;
	needBody = false;
    }

    // Releases any resources we may have (or inherit)
    public void release() {
        super.release();
        init();
    }


    //*********************************************************************
    // Tag logic

    // evaluates 'value' and determines if the body should be evaluted
    public int doStartTag() throws JspException {

      needBody = false;			// reset state related to 'default'
      this.bodyContent = null;  // clean-up body (just in case container is pooling tag handlers)
      
      try {
	// print value if available; otherwise, try 'default'
	if (value != null) {
            out(pageContext, escapeXml, value);
	    return SKIP_BODY;
	} else {
	    // if we don't have a 'default' attribute, just go to the body
	    if (def == null) {
		needBody = true;
		return EVAL_BODY_BUFFERED;
	    }

	    // if we do have 'default', print it
	    if (def != null) {
		// good 'default'
                out(pageContext, escapeXml, def);
	    }
	    return SKIP_BODY;
	}
      } catch (IOException ex) {
	throw new JspException(ex.toString(), ex);
      }
    }

    // prints the body if necessary; reports errors
    public int doEndTag() throws JspException {
      try {
	if (!needBody)
	    return EVAL_PAGE;		// nothing more to do

	// trim and print out the body
	if (bodyContent != null && bodyContent.getString() != null)
            out(pageContext, escapeXml, bodyContent.getString().trim());
	return EVAL_PAGE;
      } catch (IOException ex) {
	throw new JspException(ex.toString(), ex);
      }
    }


    //*********************************************************************
    // Public utility methods

    /**
     * Outputs <tt>text</tt> to <tt>pageContext</tt>'s current JspWriter.
     * If <tt>escapeXml</tt> is true, performs the following substring
     * replacements (to facilitate output to XML/HTML pages):
     *
     *    & -> &amp;
     *    < -> &lt;
     *    > -> &gt;
     *    " -> &#034;
     *    ' -> &#039;
     *
     * See also Util.escapeXml().
     */
    public static void out(PageContext pageContext,
                           boolean escapeXml,
                           Object obj) throws IOException {
        JspWriter w = pageContext.getOut();
	if (!escapeXml) {
            // write chars as is
            if (obj instanceof Reader) {
                Reader reader = (Reader)obj;
                char[] buf = new char[4096];
                int count;
                while ((count=reader.read(buf, 0, 4096)) != -1) {
                    w.write(buf, 0, count);
                }
            } else {
                w.write(obj.toString());
            }
        } else {
            // escape XML chars
            if (obj instanceof Reader) {
                Reader reader = (Reader)obj;
                char[] buf = new char[4096];
                int count;
                while ((count = reader.read(buf, 0, 4096)) != -1) {
                    writeEscapedXml(buf, count, w);
                }
            } else {
                String text = obj.toString();
                writeEscapedXml(text.toCharArray(), text.length(), w);
            }
        }
    }

   /**
     *
     *  Optimized to create no extra objects and write directly
     *  to the JspWriter using blocks of escaped and unescaped characters
     *
     */
    private static void writeEscapedXml(char[] buffer, int length, JspWriter w) throws IOException{
        int start = 0;

        for (int i = 0; i < length; i++) {
            char c = buffer[i];
            if (c <= Util.HIGHEST_SPECIAL) {
                char[] escaped = Util.specialCharactersRepresentation[c];
                if (escaped != null) {
                    // add unescaped portion
                    if (start < i) {
                        w.write(buffer,start,i-start);
                    }
                    // add escaped xml
                    w.write(escaped);
                    start = i + 1;
                }
            }
        }
        // add rest of unescaped portion
        if (start < length) {
            w.write(buffer,start,length-start);
        }
    }
}

 

该类的out方法注释中,也已经阐明,会转义的字符包括:

	& -> &amp;
    < -> &lt;
    > -> &gt;
	" -> &#034;
	' -> &#039;

同时需参考Util这个类,在org.apache.taglibs.standard.tag.common.core包下。

java定时器使用(Timer)
任务,并且设定任务间隔时间period void    schedule(TimerTask task, long delay) //参数Date日期,换成long形式...
创造金句三个新方法
01.数字法 这种方法非常简单,就是在你要表达内容前面加上数字。比如“三只松鼠”、“101只斑点狗”等等,但有一点要注意,数字尽量选择奇数,这样会更有力量感。 02.合体法 合体法,顾名思义,把两...
网站TKD是什么?
。 description最次,这个可以没有,然后是keyword,有更好,没有也没多大问题。 一般,在一些过度优化网站,每一篇文章,都会弄上关键词,通常在程序里,以标签形式出现,比方曾经网易博客,撰写...
海贼王克洛船长聪明之道
不高,克洛能想到第二个手段。 克洛聪明,所以对同一个问题,他能想出两个甚至三个解决方案,他挑一个最优解。 撇开主角光环不谈,克洛图谋可雅家产计划,实际上是成功,从掠夺财宝性价比看,是付出最少...
袁尚所犯下錯誤
,無法處理兄弟間矛盾,導致袁氏敗北,即便袁譚有責任,但袁尚責任更大。 那麼就來分析,袁尚到底犯哪些過錯? 典論曰:譚長而惠,尚少而美。紹妻劉氏愛尚,數稱其才,紹亦奇其皃,欲以為後,未顯而紹死。劉氏...
读后感|荒谬睡前故事——读《故事新编》
标签:荒谬睡前故事。 《故事新编》收录八个小故事,说是历史小说不大合适,若说是讽刺小说也不尽然,如此,只好承认这个集子名字再合适不过:它们是对中国神话、传说新杜撰。 这八个小故事由远到近,分别...
大地母亲悲伤
随着大地孩在黎明平原上行走,他们听到来自大地中心黑暗低语。 它向那些孩子灌输征伐思想和欺骗别人方法。许多舒哈鲁因此堕入黑暗,并开始变得邪恶。他们抛弃自己兄弟,无知地穿行在原野上。 大地...
巫妖王诞生
耐祖奥和他兽人进入扭曲虚空─这是一片在浑沌黑暗连接着所有世界异度空间。然而不幸是,基尔加丹和他手下恶魔们正在这里等待着耐祖奥一行到来。基尔加丹曾经发誓要让耐祖奥为他抗命付出代价,於是...
steamcn和贴吧一样垃圾
分享,主题里不能有他不允许字眼出现(犄角旮旯里随时更新,会随时触雷),版权争议,发个有贡献帖子(如优惠贴,写几千字版主就给几分草泥马老子不如投稿给报社,不和版主心意不仅没分还把你沉帖锁帖...
魔兽世界法师宏
/castsequence 奥术智慧,霜甲术 盾 #showtooltip /cast 冰锥术 /cast 暴风雪 左键传送,右键传送门 alt是幽暗城,shift雷霆崖,因为字符限制,写不雷霆崖传送门...
魔兽世界怀旧服 唤醒多回蓝小技巧+舞动之藤任务流程+唤醒宏使用方法
简介:非战斗状态用宏是不卡公共CD,但是战斗会卡公共CD导致浪费DPS,适合极度缺蓝情况和奈法这样BOSS。建议平时用普通唤醒,酌情使用宏 第一个:鼠标左右键宏(3个宏后面汉字换成自己武器...
购买或者交换友情链接需注意,什么样友情链接才是好
! (PS:这里有个通过快照投诉来更新快照手段,其实鉴别的话,也有方法,比如,你看一个快照,看其更新时间,与文章发布时间,做一个对比。好比一个页面,文章是18年发布,结果快照却显示是一个月...