hql注入を防止する方法


sshフレームワークではhqlクエリが頻繁に使用され、jdbcプログラミングと同様にhql注入を防止する必要があります.hql注入とは、フォームに「'」や「or」などのsql構文の保留字や文法記号を入力し、よく使われる検証を巧みに避ける手段にすぎない.
通常の解決策は、ダイナミックパラメータの設定です.具体的な方法は次のとおりです.
まずhqlを組み立てます.「?」で変数値の代わりに.次にhibernateにパラメータ値を動的に注入します.表現が難しい.やはりコードを貼りましょう.

/**
 *   hql    
 * @param form
 * @param pageNo
 * @param pageSize
 */
public Page pageByHql(TeamForm form, int pageNo, int pageSize){
    String teamCode = form.getTeamCode();
    String teamName = form.getTeamName();
    String principal = form.getTeamPrincipal();
    String eventCode = form.getSecondType();
    if(StringUtils.isEmpty(eventCode))
        eventCode = form.getFirstType();		//      ,       
		
    //
    StringBuffer hql = new StringBuffer("select distinct c from Team c ");
    List params = new ArrayList();
    if(eventCode!=null && !eventCode.equals(""))
        hql.append(",PreEventTypeRes p ");
    hql.append(" where 1=1 ");
    if(teamCode!=null && !teamCode.equals("")){
        hql.append(" and c.teamCode like ?");
        params.add("%"+teamCode+"%");
    }
    if(teamName!=null && !teamName.equals("")){
        hql.append(" and c.teamName like ?");
        params.add("%"+teamName+"%");
    }
    if(principal!=null && !principal.equals("")){
        hql.append(" and c.teamPrincipal like ?");
        params.add("%"+principal+"%");
    }
    if(eventCode!=null && !eventCode.equals("")){
        hql.append(" and c.teamId=p.resId and p.eventTypeCode like ?");
        params.add("%"+eventCode+"%");
    }
    hql.append(" and c.delSign!='1' ");
    hql.append(" order by c.teamCode asc");
    return teamDao.findPageByHQL(hql.toString(), pageNo, pageSize,params.toArray());
}

上のコードの考え方は、まずhql列を組み立てる時間をすべて「?」代替変数.変数値をlistに同時に読み込みます.本来は配列が要求される(後述dao層の実現)が,配列長が動的に増大しないためlistで最後に変換する.
ここで注意しなければならないのは、一般的にhqlに直接スペルするには、変数に単一引用符を付ける必要があります.ただしパラメータリストには追加できません.hibernateは私たちのために自動的に追加します.これがhql注入を防ぐための鍵かもしれないと思います.
以下を理解しやすいように,最後のコア実装コードを貼り付ける.

/**
	 * <ol>
	 * <li>           。      。      
	 * </ol>
	 * 
	 * @param queryString
	 *            final String -    
	 * @param currentPage
	 *            final int -       
	 * @param rows
	 *            final int -     
	 * @return -   
	 */
	protected List findPageListByHQL(final String queryString, final int currentPage, final int rows, final Object[] params) throws DAOException {
		try {
			return getHibernateTemplate().executeFind(new HibernateCallback() {
				public Object doInHibernate(Session session)
						throws HibernateException {
					Query q = session.createQuery(queryString);
					
					//     
					if (params != null){
						 for (int i = 0; i < params.length; i++) {
					            q.setParameter(i, params[i]);
					        }
					}
					
					if (currentPage > -1) {
						q.setFirstResult((currentPage - 1) * rows);
					}
					if (rows > -1) {
						q.setMaxResults(rows);
					}
					List list = q.list();
					if (list == null) {
						list = Collections.EMPTY_LIST;
					}
					return list;
				}
			});
		} catch (DataAccessException e) {
			logger.error(e.getMessage(), e);
			throw new DAOException(e);
		}
	}

もちろん、ページを分けなければ、そのマルチコードを書く必要はありません.getHibernateTemplate()を直接使います.find(String queryString,Object[]values)でいいです.
 
肝心なのは人の心を防ぐことだ.はあ...