首页 > 代码库 > ajax 访问--提高安全性

ajax 访问--提高安全性

首先受到struts token的启发,产生了客户端发起的ajax请求进行验证的想法,大致思路是客户端每次请求产生一个key ,然后服务端接收到key,然后解析,判断是否为合法key, 对于不带key 或者验证失败的直接拦截下来,从而减轻服务器的压力,好了废话不多说,上代码

首先我使用的是struts2的拦截器,(ps:不知道的度娘告诉你)

继承 AbstractInterceptor 实现init()和 intercept() ,从字面意思上去理解这两个方法 初始化 和拦截

第一个方法 就是从配置文件读取配置信息,没什么特别的

第二个方法 主要是分为两部分验证key 我这里 分 ajax 访问和普通方法 看代码 

public String intercept(ActionInvocation invocation) throws Exception {        String rs = null;        if (isTokenInterceptor) {            boolean flag = false;            String msg = "{_success : false,_operationMsg:‘非正常访问,属于非法客户端!‘}";            ActionContext ac = invocation.getInvocationContext();            HttpServletRequest request = (HttpServletRequest) ac.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");            if (PublicUtil.isNotEmpty(freeURL)) {                String urlValue[] = freeURL.split(",");                if (PublicUtil.isNotEmpty(urlValue)) {                    String as[];                    int j = (as = urlValue).length;                    for (int i = 0; i < j; i++) {                        String url = as[i];                        if (request.getRequestURI().indexOf(url) != -1) {                            flag = true;                            break;                        }                    }                }            }             if(!flag){                HttpSession session = request.getSession();                String requestToken;                HttpServletResponse response;                try {                    response = (HttpServletResponse) ac.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");                    String requestType = request.getHeader("X-Requested-With");                    if("XMLHttpRequest".equals(requestType)){ //验证是否为ajax 请求                        requestToken = request.getHeader(TOKEN_NAME);                        if(PublicUtil.isNotEmpty(requestToken) && requestToken.indexOf("||")!=-1){                            String token = (String) session.getAttribute(SESSION_TOKEN);                            if (!requestToken.equals(token)) {                                flag = true;                            } else {                                logger.warn(PublicUtil.toAppendStr(                                        "客户端表单防重复验证生效:客户端多次提交 requestToken:",                                        requestToken));                                msg = "{_success : false,_operationMsg : ‘对不起,网络异常,请重新提交尝试!‘}";                            }                            session.setAttribute(SESSION_TOKEN, requestToken);                        }                    }else{ //普通请求 通过读取cookie 来验证                        requestToken = CookieUtil.getCookie(request, TOKEN_NAME);                        if(PublicUtil.isEmpty(requestToken)){                            requestToken = DesUtil.getRequestKey();                        }                        if(PublicUtil.match("^[0-9]{8}$", DesUtil.strDec(requestToken))){                            String token = (String) session.getAttribute(COOKIE_TOKEN);                            if(PublicUtil.isEmpty(token)){                                token = requestToken;                            }                            if (requestToken.equals(token)) {                                flag = true;                            } else {                                logger.warn(PublicUtil.toAppendStr(                                        "客户端表单防重复验证生效:客户端多次提交 requestToken:",                                        requestToken, " url:", request.getRequestURI()));                                msg = "{_success : false,_operationMsg : ‘对不起,网络异常,请重新提交尝试!‘}";                            }                        }                        String nextToken = DesUtil.getRequestKey();                        CookieUtil.setCookie(response, TOKEN_NAME, nextToken);                        session.setAttribute(COOKIE_TOKEN, nextToken);                        flag = true;                    }                } catch (IllegalStateException e) {                    flag = false;                    msg = PublicUtil.toAppendStr(                            "{_success : false,_operationMsg : ‘Error creating HttpSession due response is commited to client. You can use the CreateSessionInterceptor or create the HttpSession from your action before the result is rendered to the client: ",                                    e.getMessage(), "‘}");                    e.printStackTrace();                }            }            if (flag) {                rs = invocation.invoke();            } else {                HttpServletResponse response = (HttpServletResponse) ac                        .get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");                response.setCharacterEncoding("UTF-8");                response.getWriter().write(msg);            }        } else {            rs = invocation.invoke();        }        return rs;    }

前台, 对于ajax 提交,我采用的header 夹带验证key的方式进行传递, 因为项目中使用的jquery 所以 我直接重写 $.ajax 方法就搞定了

var TOKEN_NAME = "Albedo-Requst-Token";(function($){    //备份jquery的ajax方法    var _ajax=$.ajax;        //重写jquery的ajax方法    $.ajax=function(opt){        //备份opt中error和success方法        var fn = {            error:function(XMLHttpRequest, textStatus, errorThrown){},            success:function(data, textStatus){}        }        if(opt.error){            fn.error=opt.error;        }        if(opt.success){            fn.success=opt.success;        }                //扩展增强处理        var _opt = $.extend(opt,{            beforeSend: function(request) {                request.setRequestHeader("Albedo-Requst-Token", getRequestKey()+"||"+opt.url); //产生一个时间不同时的唯一key 特别注意 时间不同,如果时间相同,可以应该一样            },            error:function(XMLHttpRequest, textStatus, errorThrown){                //错误方法增强处理                fn.error(XMLHttpRequest, textStatus, errorThrown);            },            success:function(data, textStatus){                //成功回调方法增强处理                if(typeof datahttp://www.mamicode.com/=="string"){ //对于被拦截下来的请求统一做提示                    try{                        eval("var rs = " + data);                        if(rs && rs._success == false && rs._operationMsg){                            if(!g_showTip) alert(rs._operationMsg);                            else setTimeout(function(){g_showTip(rs._operationMsg);},500);                        }                    }catch(e){}                }                fn.success(data, textStatus);            }        });        _ajax(_opt);    };})(jQuery);

当然,没有用这个的,也不要跪,至少还有?后面传参也是可以搞定的 ^_^, 

这样之后就搞定了,如果一个页面连续对一个地址发起几次请求,那么这样之后只会有第一个请求成功,之后的请求全部会被拦截下来

ps: 个人见解,有不足之处,可以提出来大家参考