shiro安全框架擴充套件教程–設計資料物件校驗器,如何防止xss以及csrf攻擊

aielves發表於2014-12-05

       很多時候我們都知道,xss,csrf都需要通過我們前臺傳入的資料,然後再輸出到頁面,渲染成可執行指令碼,導致載入頁面即可執行或者被動型的讓使用者點選各種常用的按鈕來觸發

指令碼效果,所以我們需要嚴格篩選以及控制過濾資料物件的各個屬性欄位值,我相信很多人都用validator,但是我感覺這樣可訂製的靈活性是比較低的,然後我自己就想設計一個可插拔式,可訂製的校驗器;當我們的普通validator不再滿足到資料篩選的時候,可在第二重校驗器實現我們的資料過濾

我就不囉嗦為何要設計的背景了,下面我就帖程式碼說明下自己的設計思路

1.寫個總的校驗器介面,利用泛型規定返回檢視型別,還有校驗物件的型別

package com.silvery.plugin.validator;

/**
 * 資料校驗器介面
 * 
 * @author shadow
 * 
 * @param <R>
 *            檢視型別
 * @param <T>
 *            校驗物件
 */
public interface FormValidator<R, T> {

	public R validate(T t) throws FormValidateException;

}

2.定義一個返回檢視的物件

package com.silvery.plugin.validator;

import java.util.Map;

/**
 * 資料校驗結果檢視
 * 
 * @author shadow
 * 
 */
public class FormValidateResult {

	private boolean success; // true=成功;false=失敗
	private Map<String, Object> errorMap; // 失敗對應資訊

	public FormValidateResult() {
		this(false);
	}

	public FormValidateResult(boolean success) {
		this.success = success;
	}

	public boolean isSuccess() {
		return success;
	}

	public void setSuccess(boolean success) {
		this.success = success;
	}

	public Map<String, Object> getErrorMap() {
		return errorMap;
	}

	public void setErrorMap(Map<String, Object> errorMap) {
		this.errorMap = errorMap;
	}

}

3.寫一個專門執行校驗器的執行類

package com.silvery.plugin.validator;

import java.lang.reflect.Method;
import java.util.List;

import com.silvery.utils.ReflectUtils;

/**
 * 
 * 資料校驗器執行類
 * 
 * @author shadow
 * 
 */
public class SimpleFormValidator<T> {

	/**
	 * 表單校驗方法
	 * 
	 * @param t
	 *            校驗資料物件
	 * @return 資料校驗檢視
	 * @throws FormValidateException
	 *             校驗異常
	 */
	public FormValidateResult validate(T t) throws FormValidateException {
		return validate(null, t);
	}

	/**
	 * 表單校驗方法
	 * 
	 * @param validator
	 *            使用者自定義校驗器
	 * @param t
	 *            校驗資料物件
	 * @return 資料校驗檢視
	 * @throws FormValidateException
	 *             校驗異常
	 */
	public FormValidateResult validate(FormValidator<FormValidateResult, T> validator, T t)
			throws FormValidateException {
		FormValidateResult validateResult = new FormValidateResult();
		// 優先執行使用者自定義校驗器,如不通過則跳出
		if (validator != null) {
			validateResult = validator.validate(t);
			if (!validateResult.isSuccess()) {
				return validateResult;
			}
		}
		return validateForXSS(t);
	}

	/** 校驗是否存在XSS攻擊指令碼,當前只檢測String型別宣告欄位 */
	private FormValidateResult validateForXSS(T t) {
		List<Method> methods = ReflectUtils.getMethods(t.getClass());
		for (Method method : methods) {
			if (method.getName().startsWith("set")) {
				Class<?>[] parameterClass = method.getParameterTypes();
				// 引數不能為null, 引數只有一個, 引數型別只能是String
				if (parameterClass != null && parameterClass.length == 1 && parameterClass[0].equals(String.class)) {
					// ReflectUtils.writeValueByMethod(t, method, "test");
				}
			}
		}
		return new FormValidateResult(true);
	}

}

4. 實現我們的校驗器介面,自己寫所需邏輯過濾

package com.silvery.project.cms.validator;

import java.util.HashMap;
import java.util.Map;

import com.silvery.plugin.validator.FormValidateException;
import com.silvery.plugin.validator.FormValidateResult;
import com.silvery.plugin.validator.FormValidator;
import com.silvery.project.cms.model.Authority;

/**
 * 許可權實體資料校驗器實現
 * 
 * @author shadow
 * 
 */
public class AuthorityFormValidator implements FormValidator<FormValidateResult, Authority> {

	@Override
	public FormValidateResult validate(Authority t) throws FormValidateException {
		// TODO do some validate operate
		FormValidateResult formValidateResult = new FormValidateResult();
		Map<String, Object> errorFieldMap = new HashMap<String, Object>();
		formValidateResult.setSuccess(true);
		formValidateResult.setErrorMap(errorFieldMap);
		return formValidateResult;
	}

}

4. 工作都準備得差不多的話,就開始接入到我的業務

/** 校驗物件資料合法性 */
	protected ServiceResult<T> validateForm(ServiceResult<T> serviceResult, T t) throws FormValidateException {
		FormValidateResult formValidateResult = new SimpleFormValidator<T>().validate(initFormValidator(), t);
		if (formValidateResult.isSuccess()) {
			return serviceResult.setSuccess(true);
		} else {
			return formValidateResult2ViewResult(serviceResult, formValidateResult);
		}
	}

@Override
	public ServiceResult<T> insert(T model) {
		ServiceResult<T> serviceResult = createServiceResult();
		try {
			serviceResult = validateForm(serviceResult, model);
			if (!serviceResult.isSuccess()) {
				return serviceResult;
			}
			int count = getDefaultDao().insert(model);
			if (count > 0) {
				serviceResult.setSuccess(true).setMessage(
						new StringBuffer("成功儲存[").append(count).append("]條記錄").toString());
			} else {
				serviceResult.setMessage("沒有儲存到任何記錄");
			}
		} catch (Exception e) {
			logErrorResult(serviceResult, e);
		}
		return serviceResult;
	}

後語, 我也沒有寫明確的xss,csrf過濾規則,我只是提供一個可無縫接入業務的校驗器實現,可以讓你動態修改裡面的資料,或者是攔截資料,希望對大家有幫助

 


相關文章