You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by GitBox <gi...@apache.org> on 2022/11/17 10:21:29 UTC

[GitHub] [dolphinscheduler] EricGao888 opened a new issue, #12931: [Improvement][Security] Add CSRF protection

EricGao888 opened a new issue, #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931

   ### Search before asking
   
   - [X] I had searched in the [issues](https://github.com/apache/dolphinscheduler/issues?q=is%3Aissue) and found no similar feature requirement.
   
   
   ### Description
   
   * Currently, we do not have CSRF protecting for form submission and we haven't enabled `CSRF` of Spring Security. We could enable it and improve the front end at the same time by adding `CSRF-token` to protect `DS` from `CSRF` attack.
   
   ### Are you willing to submit a PR?
   
   - [X] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] hdygxsj commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
hdygxsj commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1329186601

   please assign to me if no one is implementing it @EricGao888 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] EricGao888 commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
EricGao888 commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1329214027

   > please assign to me if no one is implementing it @EricGao888
   
   Great! Thanks for helping out : )


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] hdygxsj commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
hdygxsj commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1359312576

   At present, the following technical details need to be discussed
   **1.Whether it is necessary to introduce spring security dependencies on the back end to make dolphinscheduler safe from csrf attacks**
   The spring security csrf module does the following
   * If the cookie in the request does not contain a CSRF-TOKEN, a CSRF-TOKEN is generated and a set cookie is added to the request
   
   <div align="center"> code snippet in org.springframework.security.web.csrf.CsrfFilter</div>
   
   ```java
                   CsrfToken csrfToken = this.tokenRepository.loadToken(request);
   		boolean missingToken = (csrfToken == null);
   		if (missingToken) {
   			csrfToken = this.tokenRepository.generateToken(request);
   			this.tokenRepository.saveToken(csrfToken, request, response);
   		}
   ```
   <div align="center"> code snippet in org.springframework.security.web.csrf.CookieCsrfTokenRepository</div>
   
   ```java
           @Override
   	public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
   		String tokenValue = (token != null) ? token.getToken() : "";
   		Cookie cookie = new Cookie(this.cookieName, tokenValue);
   		cookie.setSecure((this.secure != null) ? this.secure : request.isSecure());
   		cookie.setPath(StringUtils.hasLength(this.cookiePath) ? this.cookiePath : this.getRequestContext(request));
   		cookie.setMaxAge((token != null) ? this.cookieMaxAge : 0);
   		cookie.setHttpOnly(this.cookieHttpOnly);
   		if (StringUtils.hasLength(this.cookieDomain)) {
   			cookie.setDomain(this.cookieDomain);
   		}
   		response.addCookie(cookie);
   	}
   ```
   * Determine whether the request path needs to be protected by CSRF
   <div align="center"> code snippet in org.springframework.security.web.csrf.CsrfFilter</div>
   
   ```java
                 if (!this.requireCsrfProtectionMatcher.matches(request)) {
   			if (this.logger.isTraceEnabled()) {
   				this.logger.trace("Did not protect against CSRF since request did not match "
   						+ this.requireCsrfProtectionMatcher);
   			}
   			filterChain.doFilter(request, response);
   			return;
   		}
   ```
   * Compare the CSRF token in the cookie with the CSRF token in the http request header or the token in the http request param
   <div align="center"> code snippet in org.springframework.security.web.csrf.CsrfFilter</div>
   
   ```java
                  String actualToken = request.getHeader(csrfToken.getHeaderName());
   		if (actualToken == null) {
   			actualToken = request.getParameter(csrfToken.getParameterName());
   		}
   		if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
   			this.logger.debug(
   					LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
   			AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
   					: new MissingCsrfTokenException(actualToken);
   			this.accessDeniedHandler.handle(request, response, exception);
   			return;
   		}
   		filterChain.doFilter(request, response);
   ```
   
   If we don't introduce spring security in the future, we can also implement csrf defense by adding a filter similar to CsrfFilter
   
   **2.How do we save the csrf token to prevent attackers from stealing it**
   * Whether we implement interceptors ourselves on the back end or use spring security, on the front end we need to think about how to store csrf tokens securely to prevent attackers from stealing them so that csrf defenses fail.
   
   I found that after calling the login interface, the front end would save the sessionId returned after successful login into the cookie again, and the cookie saved in this way instead of the set-cookie in the http response header would be stolen by other websites
   
   <div align="center"> code snippet in use-login.ts</div>
   ```ts
     const handleLogin = () => {
       state.loginFormRef.validate(async (valid: any) => {
         if (!valid) {
           const loginRes: LoginRes = await login({ ...state.loginForm })
           debugger
           await userStore.setSessionId(loginRes.sessionId)
           await userStore.setSecurityConfigType(loginRes.securityConfigType)
           cookies.set('sessionId', loginRes.sessionId, { path: '/' })
          ……
         }
       })
     }
   ```
   
   This results in an attacker using the following code for a csrf attack, as shown below
   ```tsx
   import { defineComponent, ref } from "vue";
   import cookies from 'js-cookie'
   
   export default defineComponent({
     setup() {
       const csrfToken = cookies.get('XSRF-TOKEN')
       return {
         csrfToken
       }
     },
     render() {
       return (<div><form action="http://127.0.0.1:5173/dolphinscheduler/projects" method="post">
         <input type="hidden"
           name="projectName"
           value="aasdasd" />
         <input type="hidden"
           name="userName"
           value="admin" />
         <input type="submit"
           value="Win Money!" />
         <input type="hidden" name="_csrf" value={this.csrfToken}></input>
       </form></div>)
     }
   })
   ```
   ![1671536386598](https://user-images.githubusercontent.com/35210666/208658487-6c8f9d6d-3072-4d3c-beee-442a06b9181c.png)
   
   Once the dolphinscheduler user clicks the button in the diagram, a csrf attack completes
   
   ![1671536625047](https://user-images.githubusercontent.com/35210666/208659235-10bcfbc8-95ef-4a83-bd71-5a99a1b18555.png)
   
   Maybe we can save the csrf token in pinia, but I'm not sure there is any risk that pinia will be stolen by other websites
   
   * In order to make csrf token more secure, do we need to consider the encryption of csrf token?
   
   The front end places the csrf token in the header or parameter. The back end uses the public key to decrypt the csrf Token in the http request and compares it to the token in the cookie
   
   **3.Whether to perform csrf defense on login requests**
   
   As mentioned in spring security, an attacker can forge login requests to obtain csrf token for subsequent attacks, but our login api must input the username and password.    In my opinion, when the attacker has obtained the username and password, he can directly log in from the website, at this point, the csrf defense is meaningless
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] devosend commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
devosend commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1370806088

   > At present, the following technical details need to be discussed **1.Whether it is necessary to introduce spring security dependencies on the back end to make dolphinscheduler safe from csrf attacks** The spring security csrf module does the following
   > 
   > * If the cookie in the request does not contain a CSRF-TOKEN, a CSRF-TOKEN is generated and a set cookie is added to the request
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >                 CsrfToken csrfToken = this.tokenRepository.loadToken(request);
   > 		boolean missingToken = (csrfToken == null);
   > 		if (missingToken) {
   > 			csrfToken = this.tokenRepository.generateToken(request);
   > 			this.tokenRepository.saveToken(csrfToken, request, response);
   > 		}
   > ```
   > 
   > code snippet in org.springframework.security.web.csrf.CookieCsrfTokenRepository
   > ```java
   >         @Override
   > 	public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
   > 		String tokenValue = (token != null) ? token.getToken() : "";
   > 		Cookie cookie = new Cookie(this.cookieName, tokenValue);
   > 		cookie.setSecure((this.secure != null) ? this.secure : request.isSecure());
   > 		cookie.setPath(StringUtils.hasLength(this.cookiePath) ? this.cookiePath : this.getRequestContext(request));
   > 		cookie.setMaxAge((token != null) ? this.cookieMaxAge : 0);
   > 		cookie.setHttpOnly(this.cookieHttpOnly);
   > 		if (StringUtils.hasLength(this.cookieDomain)) {
   > 			cookie.setDomain(this.cookieDomain);
   > 		}
   > 		response.addCookie(cookie);
   > 	}
   > ```
   > 
   > * Determine whether the request path needs to be protected by CSRF
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >               if (!this.requireCsrfProtectionMatcher.matches(request)) {
   > 			if (this.logger.isTraceEnabled()) {
   > 				this.logger.trace("Did not protect against CSRF since request did not match "
   > 						+ this.requireCsrfProtectionMatcher);
   > 			}
   > 			filterChain.doFilter(request, response);
   > 			return;
   > 		}
   > ```
   > 
   > * Compare the CSRF token in the cookie with the CSRF token in the http request header or the token in the http request param
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >                String actualToken = request.getHeader(csrfToken.getHeaderName());
   > 		if (actualToken == null) {
   > 			actualToken = request.getParameter(csrfToken.getParameterName());
   > 		}
   > 		if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
   > 			this.logger.debug(
   > 					LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
   > 			AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
   > 					: new MissingCsrfTokenException(actualToken);
   > 			this.accessDeniedHandler.handle(request, response, exception);
   > 			return;
   > 		}
   > 		filterChain.doFilter(request, response);
   > ```
   > 
   > If we don't introduce spring security in the future, we can also implement csrf defense by adding a filter similar to CsrfFilter
   > 
   > **2.How do we save the csrf token to prevent attackers from stealing it**
   > 
   > * Whether we implement interceptors ourselves on the back end or use spring security, on the front end we need to think about how to store csrf tokens securely to prevent attackers from stealing them so that csrf defenses fail.
   > 
   > I found that after calling the login interface, the front end would save the sessionId returned after successful login into the cookie again, and the cookie saved in this way instead of the set-cookie in the http response header would be stolen by other websites
   > 
   > code snippet in use-login.ts
   > ```ts
   >   const handleLogin = () => {
   >     state.loginFormRef.validate(async (valid: any) => {
   >       if (!valid) {
   >         const loginRes: LoginRes = await login({ ...state.loginForm })
   >         debugger
   >         await userStore.setSessionId(loginRes.sessionId)
   >         await userStore.setSecurityConfigType(loginRes.securityConfigType)
   >         cookies.set('sessionId', loginRes.sessionId, { path: '/' })
   >        ……
   >       }
   >     })
   >   }
   > ```
   > 
   > This results in an attacker using the following code for a csrf attack, as shown below
   > 
   > ```tsx
   > import { defineComponent, ref } from "vue";
   > import cookies from 'js-cookie'
   > 
   > export default defineComponent({
   >   setup() {
   >     const csrfToken = cookies.get('XSRF-TOKEN')
   >     return {
   >       csrfToken
   >     }
   >   },
   >   render() {
   >     return (<div><form action="http://127.0.0.1:5173/dolphinscheduler/projects" method="post">
   >       <input type="hidden"
   >         name="projectName"
   >         value="aasdasd" />
   >       <input type="hidden"
   >         name="userName"
   >         value="admin" />
   >       <input type="submit"
   >         value="Win Money!" />
   >       <input type="hidden" name="_csrf" value={this.csrfToken}></input>
   >     </form></div>)
   >   }
   > })
   > ```
   > 
   > ![1671536386598](https://user-images.githubusercontent.com/35210666/208658487-6c8f9d6d-3072-4d3c-beee-442a06b9181c.png)
   > 
   > Once the dolphinscheduler user clicks the button in the diagram, a csrf attack completes
   > 
   > ![1671536625047](https://user-images.githubusercontent.com/35210666/208659235-10bcfbc8-95ef-4a83-bd71-5a99a1b18555.png)
   > 
   > Maybe we can save the csrf token in pinia, but I'm not sure there is any risk that pinia will be stolen by other websites
   > 
   > * In order to make csrf token more secure, do we need to consider the encryption of csrf token?
   > 
   > The front end places the csrf token in the header or parameter. The back end uses the public key to decrypt the csrf Token in the http request and compares it to the token in the cookie
   > 
   > **3.Whether to perform csrf defense on login requests**
   > 
   > As mentioned in spring security, an attacker can forge login requests to obtain csrf token for subsequent attacks, but our login api must input the username and password. In my opinion, when the attacker has obtained the username and password, he can directly log in from the website, at this point, the csrf defense is meaningless
   
   For question 2,Pinia will store `csrfToken ` in localStorage and will not be stolen by other websites. Your attack succeeded because you deployed them on the same domain -- `127.0.0.1`.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] github-actions[bot] commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
github-actions[bot] commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1318411602

   Thank you for your feedback, we have received your issue, Please wait patiently for a reply.
   * In order for us to understand your request as soon as possible, please provide detailed information、version or pictures.
   * If you haven't received a reply for a long time, you can [join our slack](https://s.apache.org/dolphinscheduler-slack) and send your question to channel `#troubleshooting`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] EricGao888 commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
EricGao888 commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1318497594

   https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [dolphinscheduler] devosend commented on issue #12931: [Improvement][Security] Add CSRF protection

Posted by GitBox <gi...@apache.org>.
devosend commented on issue #12931:
URL: https://github.com/apache/dolphinscheduler/issues/12931#issuecomment-1370806494

   > At present, the following technical details need to be discussed **1.Whether it is necessary to introduce spring security dependencies on the back end to make dolphinscheduler safe from csrf attacks** The spring security csrf module does the following
   > 
   > * If the cookie in the request does not contain a CSRF-TOKEN, a CSRF-TOKEN is generated and a set cookie is added to the request
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >                 CsrfToken csrfToken = this.tokenRepository.loadToken(request);
   > 		boolean missingToken = (csrfToken == null);
   > 		if (missingToken) {
   > 			csrfToken = this.tokenRepository.generateToken(request);
   > 			this.tokenRepository.saveToken(csrfToken, request, response);
   > 		}
   > ```
   > 
   > code snippet in org.springframework.security.web.csrf.CookieCsrfTokenRepository
   > ```java
   >         @Override
   > 	public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
   > 		String tokenValue = (token != null) ? token.getToken() : "";
   > 		Cookie cookie = new Cookie(this.cookieName, tokenValue);
   > 		cookie.setSecure((this.secure != null) ? this.secure : request.isSecure());
   > 		cookie.setPath(StringUtils.hasLength(this.cookiePath) ? this.cookiePath : this.getRequestContext(request));
   > 		cookie.setMaxAge((token != null) ? this.cookieMaxAge : 0);
   > 		cookie.setHttpOnly(this.cookieHttpOnly);
   > 		if (StringUtils.hasLength(this.cookieDomain)) {
   > 			cookie.setDomain(this.cookieDomain);
   > 		}
   > 		response.addCookie(cookie);
   > 	}
   > ```
   > 
   > * Determine whether the request path needs to be protected by CSRF
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >               if (!this.requireCsrfProtectionMatcher.matches(request)) {
   > 			if (this.logger.isTraceEnabled()) {
   > 				this.logger.trace("Did not protect against CSRF since request did not match "
   > 						+ this.requireCsrfProtectionMatcher);
   > 			}
   > 			filterChain.doFilter(request, response);
   > 			return;
   > 		}
   > ```
   > 
   > * Compare the CSRF token in the cookie with the CSRF token in the http request header or the token in the http request param
   > 
   > code snippet in org.springframework.security.web.csrf.CsrfFilter
   > ```java
   >                String actualToken = request.getHeader(csrfToken.getHeaderName());
   > 		if (actualToken == null) {
   > 			actualToken = request.getParameter(csrfToken.getParameterName());
   > 		}
   > 		if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
   > 			this.logger.debug(
   > 					LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
   > 			AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
   > 					: new MissingCsrfTokenException(actualToken);
   > 			this.accessDeniedHandler.handle(request, response, exception);
   > 			return;
   > 		}
   > 		filterChain.doFilter(request, response);
   > ```
   > 
   > If we don't introduce spring security in the future, we can also implement csrf defense by adding a filter similar to CsrfFilter
   > 
   > **2.How do we save the csrf token to prevent attackers from stealing it**
   > 
   > * Whether we implement interceptors ourselves on the back end or use spring security, on the front end we need to think about how to store csrf tokens securely to prevent attackers from stealing them so that csrf defenses fail.
   > 
   > I found that after calling the login interface, the front end would save the sessionId returned after successful login into the cookie again, and the cookie saved in this way instead of the set-cookie in the http response header would be stolen by other websites
   > 
   > code snippet in use-login.ts
   > ```ts
   >   const handleLogin = () => {
   >     state.loginFormRef.validate(async (valid: any) => {
   >       if (!valid) {
   >         const loginRes: LoginRes = await login({ ...state.loginForm })
   >         debugger
   >         await userStore.setSessionId(loginRes.sessionId)
   >         await userStore.setSecurityConfigType(loginRes.securityConfigType)
   >         cookies.set('sessionId', loginRes.sessionId, { path: '/' })
   >        ……
   >       }
   >     })
   >   }
   > ```
   > 
   > This results in an attacker using the following code for a csrf attack, as shown below
   > 
   > ```tsx
   > import { defineComponent, ref } from "vue";
   > import cookies from 'js-cookie'
   > 
   > export default defineComponent({
   >   setup() {
   >     const csrfToken = cookies.get('XSRF-TOKEN')
   >     return {
   >       csrfToken
   >     }
   >   },
   >   render() {
   >     return (<div><form action="http://127.0.0.1:5173/dolphinscheduler/projects" method="post">
   >       <input type="hidden"
   >         name="projectName"
   >         value="aasdasd" />
   >       <input type="hidden"
   >         name="userName"
   >         value="admin" />
   >       <input type="submit"
   >         value="Win Money!" />
   >       <input type="hidden" name="_csrf" value={this.csrfToken}></input>
   >     </form></div>)
   >   }
   > })
   > ```
   > 
   > ![1671536386598](https://user-images.githubusercontent.com/35210666/208658487-6c8f9d6d-3072-4d3c-beee-442a06b9181c.png)
   > 
   > Once the dolphinscheduler user clicks the button in the diagram, a csrf attack completes
   > 
   > ![1671536625047](https://user-images.githubusercontent.com/35210666/208659235-10bcfbc8-95ef-4a83-bd71-5a99a1b18555.png)
   > 
   > Maybe we can save the csrf token in pinia, but I'm not sure there is any risk that pinia will be stolen by other websites
   > 
   > * In order to make csrf token more secure, do we need to consider the encryption of csrf token?
   > 
   > The front end places the csrf token in the header or parameter. The back end uses the public key to decrypt the csrf Token in the http request and compares it to the token in the cookie
   > 
   > **3.Whether to perform csrf defense on login requests**
   > 
   > As mentioned in spring security, an attacker can forge login requests to obtain csrf token for subsequent attacks, but our login api must input the username and password. In my opinion, when the attacker has obtained the username and password, he can directly log in from the website, at this point, the csrf defense is meaningless
   
   For question 2,Pinia will store `csrfToken ` in localStorage and will not be stolen by other websites. Your attack succeeded because you deployed them on the same domain -- `127.0.0.1`.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@dolphinscheduler.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org