天天看點

mybatis中的like查詢,$取值時防sql注入和通配符注入,#取值時防通配符注入

在mybatis中用like查詢時,如果使用者輸入的值有"_"和“%”,則會出現這種情況:

使用者本來隻是想查詢“abcd_”,查詢結果中卻有"abcd_"、"abcde"、"abcdf"等等;使用者要查詢"30%"(注:百分之三十)時也會出現問題。

測試後發現無論你是用#{xxxx }還是用${xxxx }取值都會存在這些問題,而且用${xxxx }取值時還存在sql注入的問題。

為了解決這些問題,我在背景對使用者傳入的值進行了處理,代碼如下:

import org.apache.commons.lang3.StringUtils;

/**
 * mybatis中like查詢時,需用該方法處理字元,防止sql注入<br>
 * sql server 2005測試有效
 * 
 * @date    2013年12月9日 下午4:08:54
 * @version 1.0
 * @author  luoy
 */
public class SqlUtil {

	private static final String H = "#";
	private static final String S = "$";

	/**
	 * mapper.xml中的取值方式為#{}時
	 * @param str like的查詢條件
	 * @return
	 */
	public static String likeEscapeH(String str) {
		return likeEscapeZ(str, H, true, true);
	}
	
	/**
	 * mapper.xml中的取值方式為${}時
	 * @param str like的查詢條件
	 * @return
	 */
	public static String likeEscapeS(String str) {
		return likeEscapeZ(str, S, true, true);
	}
	
	/**
	 * @param str   like的查詢條件
	 * @param type  mapper.xml中的取值方式,隻能“#”或“$”
	 * @param start 字元串前部是否拼接“%”
	 * @param end   字元串尾部是否拼接“%”
	 * @return
	 */
	public static String likeEscapeZ(String str, String type, boolean start, boolean end) {
		if (StringUtils.isBlank(str)) {
			return null;
		}
		StringBuffer buffer = new StringBuffer();
		// 拼接順序不能改變
		if (S.equals(type)) {
			buffer.append(" '");
		}
		if (start) {
			buffer.append("%");
		}
		int len = str.length();
		//注意:"]"不能處理
		for (int i = 0; i < len; i++) {
			char c = str.charAt(i);
			switch (c) {
			case '\'':
				if (S.equals(type)) {
					buffer.append("''");// 單引号替換成兩個單引号
				} else {
					buffer.append(c);
				}
				break;
			case '[':
				buffer.append("[[]");
				break;
			case '_':
				buffer.append("[_]");
				break;
			case '%':
				buffer.append("[%]");
				break;
			case '^':
				buffer.append("[^]");
				break;
			case '!':
				buffer.append("[!]");
				break;
			default:
				buffer.append(c);
			}
		}
		
		if (end) {
			buffer.append("%");
		}
		if (S.equals(type)) {
			buffer.append("' ");
		}
		return buffer.toString();
	}
	
	public static void main(String[] args) {
		String str = "aaaa]p'100%_a[[][][]][[][]]df[]dfaf]";
		System.out.println("result#: " + likeEscapeH(str));
		System.out.println("result$: " + likeEscapeS(str));
	}
}
           

看了代碼的人應該很容易就明白了。這裡的三個方法分别對應多種可能的情況,第一個是#号取值,參數前後都加百分号;第二個方法是$取值,參數前後都加百分号;第三個方法是參數可配,而且考慮到了,有時候不需要前後都加百分号的情況。

xml中的寫法:

1,

<if test="xxx != null" >

select * from tabale_name a where  a.xxx like ${xxx }

</if>

2,

<if test="xxx != null" >

select * from tabale_name a where  a.xxx like #{xxx }

</if>

添加oracle适用類

import org.apache.commons.lang3.StringUtils;

/**
 * oracle 适用<br/>
 * mybatis中like查詢用$取值時,需用該方法處理字元,防止sql注入<br/>
 * 
 * @date 2016年01月20日
 * @author 羅勇
 */
public final class SqlUtil {

    /**
     * mapper.xml中的取值方式為${}時
     * 
     * @param str
     *            like的查詢條件
     * @return
     */
    public static String likeEscape(String str) {
        return likeEscape(str, true, true);
    }

    /**
     * @param str
     *            like的查詢條件
     * @param start
     *            字元串前部是否拼接“%”
     * @param end
     *            字元串尾部是否拼接“%”
     * @return
     */
    public static String likeEscape(String str, boolean start, boolean end) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        // 拼接順序不能改變
        buf.append(" '");
        if (start) {
            buf.append("%");
        }
        boolean flag = false;
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            switch (c) {
            case '\'':
                buf.append("''");// 單引号替換成兩個單引号
                break;
            case '_':
                buf.append("\\_");
                flag = true;
                break;
            case '%':
                buf.append("\\%");
                flag = true;
                break;
            default:
                buf.append(c);
            }
        }

        if (end) {
            buf.append("%");
        }
        buf.append("' ");
        if (flag) {
            buf.append("escape '\\' ");
        }
        return buf.toString();
    }

    private SqlUtil() {
    }

    public static void main(String[] args) {
        String str = "aaaa]p'100%_a[[][][]][[][]]df[]dfaf]!bbb^";
        System.out.println("result$: " + likeEscape(str));
    }
}
           

繼續閱讀