当前位置:网站首页>Solution to the conflict between security automatic login and anti CSRF attack

Solution to the conflict between security automatic login and anti CSRF attack

2022-07-19 07:21:00 Walk in the clouds

Project scenario :

Using technology , Back end srpingboot+security, front end Vue+elementui+axios

Problem description :

security There are two powerful functions : Automatic login and anti CSRF attack . prevent CSRF The function of the attack is plain , Just one more token verification . However, when these two functions are turned on at the same time , There will be POST/PUT Request no access .

Cause analysis :

The reason for the problem here is token, For establishing a connection at one time ,CRFS Of token Is the only one. , But automatic login skips the login process , therefore CRFS Of token Values are regenerated , Which means that previously saved token Invalid. . Therefore, you only need to retrieve and save .
There is a major problem here : When you log in automatically , Go directly to the main page , But there are multiple asynchronous requests to get data under the main page , This will be sent many times token value . There will be problems that are sometimes effective and sometimes ineffective .

Solution :

After testing , If you only send a request once when logging in , Then send other asynchronous requests , It can guarantee that there is only one session conversation . You can also ensure that only one is sent token. This ensures that the asynchronous request sent later uses the same token. Therefore, we need to add one more request , This request can do nothing , Only the first request is guaranteed . Therefore, it is best to put it in App.vue Of beforeCreate Function . As shown below :
export default {
    
	name: 'app',
	beforeCreate() {
    
		//  there axios Encapsulated in window in , Therefore, it can guarantee the call to 
		//  solve   No landing  CRFS problem 
		var xmlhttp;
		if (window.XMLHttpRequest) {
     // code for IE7+, Firefox, Chrome, Opera, Safari
			xmlhttp = new XMLHttpRequest();
		} else {
     // code for IE6, IE5
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		};
		if (!xmlhttp) {
    
			console.log(" I won't support it xml send out ")
			return;
		};
		//  Send synchronization request , After ensuring success, you can request other asynchronous requests 
		xmlhttp.open("get", process.env.VUE_APP_PROXYNAME + "/ok?t=" + Math.random(), false);
	}
}

The backend first guarantees to do it once after the login is successful token send out , Save in cookie in , Ensure that there is no need for any operation on the front end

/** *  Login successful callback  */
public class LoginSuccessResponse extends SimpleUrlAuthenticationSuccessHandler {
    
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        /** *  obtain CSRF secret key  * "csrf": { * "headerName": "X-CSRF-TOKEN",  It must be this act key * "parameterName": "_csrf", * "token": "" * }, *  Send the key to the front , Each request is written in the header , *  for example  X-CSRF-TOKEN: 'token', To ensure normal access  *  Use Cookie Ensure that the front end does not need to do any operation  */
        CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
        //  Use here fastjson Turn into JSON Format 
        Cookie cookie = new Cookie("csrf", URLEncoder.encode(JSON.toJSONString(csrfToken),"UTF-8"));
        //  preservation 10 God , Ensure sufficient survival time 
        cookie.setMaxAge(60 * 60 * 24 * 10);
        cookie.setPath("/");
        response.addCookie(cookie);
        // sendCsrfToken Record boolean value , In a browser session , Ensure to send once toekn value 
        request.getSession().setAttribute("sendCsrfToken", true);
        out.flush();
        out.close();
    }
}

Next is the configuration request /ok, Ensure normal access under automatic login

/** *  Public request  */
@Controller
@Slf4j
public class CommonController {
    

    /** *  Solve the problem of login free CRFS Verification questions  * @param request * @param response * @throws UnsupportedEncodingException */
    @GetMapping("/ok")
    @ResponseBody
    public void ok(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
    
        Object sendCsrfToken = request.getSession().getAttribute("sendCsrfToken");
        if (sendCsrfToken == null || (boolean) sendCsrfToken == false) {
    
            CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
            Cookie cookie = new Cookie("csrf", URLEncoder.encode(JSON.toJSONString(csrfToken),"UTF-8"));
            cookie.setMaxAge(60 * 60 * 24 * 10);
            cookie.setPath("/");
            response.addCookie(cookie);
            log.info(" Login free users {}, send out csrfToken:{}", SecurityContextHolder.getContext().getAuthentication().getName(),csrfToken.getToken());
            request.getSession().setAttribute("sendCsrfToken", true);
        }
    }
}

After configuration, you can ensure that cookie There will always be an effective crsftoken value , You only need to configure the request header before each request interception to access it normally . as follows :

_axios.interceptors.request.use(
	function(config) {
    
		let cookie = document.cookie;
		if (cookie) {
    
			//  Use here vue-cookies plug-in unit , You can also go straight from cookie Get data in 
			let csrf = VueCookies.get("csrf ")
			if (csrf) {
    
				config.headers[csrf.headerName] = csrf['token'];
			}
		}
		// Do something before request is sent
		return config;
	},
	function(error) {
    
		// Do something with request error
		return Promise.reject(error);
	}
);
原网站

版权声明
本文为[Walk in the clouds]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/200/202207170520449923.html