zoukankan      html  css  js  c++  java
  • 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 data=="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: 个人见解,有不足之处,可以提出来大家参考

  • 相关阅读:
    curl crt
    test with nmap
    C#查询XML解决“需要命名空间管理器”问题
    Dapper实用教程
    javascript 计算两个日期的差值
    Glib学习笔记(二)
    安装osquery笔记
    Golang多线程简单斗地主
    PHP扩展开发之Zephir
    zabbix 安装记录
  • 原文地址:https://www.cnblogs.com/lljj/p/3849103.html
Copyright © 2011-2022 走看看