-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat:4107] Mysql connection security check extract utils (#4108)
* mysql connection security check extract utils
- Loading branch information
1 parent
584ea70
commit a652276
Showing
10 changed files
with
462 additions
and
166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
## 参数变化 | ||
|
||
| 模块名(服务名) | 类型 | 参数名 | 默认值 | 描述 | | ||
|---------------------------------------------------|-----|----------------------------------------------------------------------|-------| ------------------------------------------------------- | | ||
| ps-linkismanager | 修改 | pipeline.output.isoverwtite <br/>-><br/> pipeline.output.isoverwrite | true |取值范围:true或false| | ||
| linkis-engineconn-plugins <br/> linkis-datasource | 新增 | linkis.mysql.strong.security.enable | false |取值范围:true或false| | ||
| 模块名(服务名) | 类型 | 参数名 | 默认值 | 描述 | | ||
|---------------------------------------------------|-----|----------------------------------------------------------------------|-------|-----------------| | ||
| ps-linkismanager | 修改 | pipeline.output.isoverwtite <br/>-><br/> pipeline.output.isoverwrite | true | 取值范围:true或false | | ||
| linkis-engineconn-plugins <br/> linkis-datasource | 新增 | linkis.mysql.strong.security.enable | false | 取值范围:true或false | | ||
| linkis-common | 新增 | linkis.mysql.force.params | allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false | mysql连接强制携带参数 | | ||
| linkis-common | 新增 | linkis.mysql.sensitive.params | allowLoadLocalInfile,autoDeserialize,allowLocalInfile,allowUrlInLocalInfile,# | mysql连接安全校验参数 | |
30 changes: 30 additions & 0 deletions
30
...nkis-common/src/main/java/org/apache/linkis/common/exception/LinkisSecurityException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.linkis.common.exception; | ||
|
||
public class LinkisSecurityException extends LinkisRuntimeException { | ||
|
||
@Override | ||
public ExceptionLevel getLevel() { | ||
return null; | ||
} | ||
|
||
public LinkisSecurityException(int errCode, String desc) { | ||
super(errCode, desc); | ||
} | ||
} |
192 changes: 192 additions & 0 deletions
192
linkis-commons/linkis-common/src/main/java/org/apache/linkis/common/utils/SecurityUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.linkis.common.utils; | ||
|
||
import org.apache.linkis.common.conf.CommonVars; | ||
import org.apache.linkis.common.conf.CommonVars$; | ||
import org.apache.linkis.common.exception.LinkisSecurityException; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
|
||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public abstract class SecurityUtils { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(SecurityUtils.class); | ||
|
||
private static final String COMMA = ","; | ||
|
||
private static final String EQUAL_SIGN = "="; | ||
|
||
private static final String AND_SYMBOL = "&"; | ||
|
||
private static final String QUESTION_MARK = "?"; | ||
|
||
/** allowLoadLocalInfile,allowLoadLocalInfiled,# */ | ||
public static final CommonVars<String> MYSQL_SENSITIVE_PARAMS = | ||
CommonVars$.MODULE$.apply( | ||
"linkis.mysql.sensitive.params", | ||
"allowLoadLocalInfile,autoDeserialize,allowLocalInfile,allowUrlInLocalInfile,#"); | ||
|
||
/** | ||
* "allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false" | ||
*/ | ||
public static final CommonVars<String> MYSQL_FORCE_PARAMS = | ||
CommonVars$.MODULE$.apply( | ||
"linkis.mysql.force.params", | ||
"allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false"); | ||
|
||
public static final CommonVars<String> MYSQL_STRONG_SECURITY_ENABLE = | ||
CommonVars$.MODULE$.apply("linkis.mysql.strong.security.enable", "false"); | ||
|
||
/** | ||
* mysql url append force params | ||
* | ||
* @param url | ||
* @return | ||
*/ | ||
public static String appendMysqlForceParams(String url) { | ||
if (StringUtils.isBlank(url)) { | ||
return ""; | ||
} | ||
|
||
String extraParamString = MYSQL_FORCE_PARAMS.getValue(); | ||
|
||
if (url.endsWith(QUESTION_MARK)) { | ||
url = url + extraParamString; | ||
} else if (url.lastIndexOf(QUESTION_MARK) < 0) { | ||
url = url + QUESTION_MARK + extraParamString; | ||
} else { | ||
url = url + AND_SYMBOL + extraParamString; | ||
} | ||
return url; | ||
} | ||
|
||
public static void appendMysqlForceParams(Map<String, Object> extraParams) { | ||
extraParams.putAll(parseMysqlUrlParamsToMap(MYSQL_FORCE_PARAMS.getValue())); | ||
} | ||
|
||
public static String checkJdbcSecurity(String url) { | ||
logger.info("checkJdbcSecurity origin url: {}", url); | ||
if (StringUtils.isBlank(url)) { | ||
throw new LinkisSecurityException(35000, "Invalid mysql connection cul, url is empty"); | ||
} | ||
if (url.endsWith(QUESTION_MARK) || !url.contains(QUESTION_MARK)) { | ||
logger.info("checkJdbcSecurity target url: {}", url); | ||
return url; | ||
} | ||
String[] items = url.split("\\?"); | ||
if (items.length != 2) { | ||
logger.warn("Invalid url: {}", url); | ||
throw new LinkisSecurityException(35000, "Invalid mysql connection cul: " + url); | ||
} | ||
Map<String, Object> params = parseMysqlUrlParamsToMap(items[1]); | ||
Map<String, Object> securityMap = checkJdbcSecurity(params); | ||
String paramUrl = parseParamsMapToMysqlParamUrl(securityMap); | ||
url = items[0] + QUESTION_MARK + paramUrl; | ||
logger.info("checkJdbcSecurity target url: {}", url); | ||
return url; | ||
} | ||
|
||
/** | ||
* check jdbc params | ||
* | ||
* @param paramsMap | ||
*/ | ||
public static Map<String, Object> checkJdbcSecurity(Map<String, Object> paramsMap) { | ||
if (paramsMap == null) { | ||
return new HashMap<>(); | ||
} | ||
|
||
// mysql url strong security | ||
if (Boolean.valueOf(MYSQL_STRONG_SECURITY_ENABLE.getValue())) { | ||
paramsMap.clear(); | ||
return paramsMap; | ||
} | ||
|
||
Iterator<Map.Entry<String, Object>> iterator = paramsMap.entrySet().iterator(); | ||
while (iterator.hasNext()) { | ||
Map.Entry<String, Object> entry = iterator.next(); | ||
String key = entry.getKey(); | ||
Object value = entry.getValue(); | ||
if (StringUtils.isBlank(key) || value == null || StringUtils.isBlank(value.toString())) { | ||
logger.warn("Invalid parameter key or value is blank."); | ||
iterator.remove(); | ||
continue; | ||
} | ||
if (isNotSecurity(key, value.toString())) { | ||
logger.warn("Sensitive param : key={} and value={}", key, value); | ||
throw new LinkisSecurityException( | ||
35000, | ||
"Invalid mysql connection parameters: " + parseParamsMapToMysqlParamUrl(paramsMap)); | ||
} | ||
} | ||
return paramsMap; | ||
} | ||
|
||
public static String parseParamsMapToMysqlParamUrl(Map<String, Object> forceParams) { | ||
if (forceParams == null) { | ||
return ""; | ||
} | ||
return forceParams.entrySet().stream() | ||
.map(e -> String.join(EQUAL_SIGN, e.getKey(), String.valueOf(e.getValue()))) | ||
.collect(Collectors.joining(AND_SYMBOL)); | ||
} | ||
|
||
private static Map<String, Object> parseMysqlUrlParamsToMap(String paramsUrl) { | ||
String[] params = paramsUrl.split(AND_SYMBOL); | ||
Map<String, Object> map = new LinkedHashMap<>(params.length); | ||
for (String param : params) { | ||
String[] item = param.split(EQUAL_SIGN); | ||
if (item.length != 2) { | ||
logger.warn("mysql force param {} error.", param); | ||
continue; | ||
} | ||
map.put(item[0], item[1]); | ||
} | ||
return map; | ||
} | ||
|
||
private static boolean isNotSecurity(String key, String value) { | ||
boolean res = true; | ||
String sensitiveParamsStr = MYSQL_SENSITIVE_PARAMS.getValue(); | ||
if (StringUtils.isBlank(sensitiveParamsStr)) { | ||
return false; | ||
} | ||
String[] forceParams = sensitiveParamsStr.split(COMMA); | ||
for (String forceParam : forceParams) { | ||
if (isNotSecurity(key, value, forceParam)) { | ||
res = false; | ||
break; | ||
} | ||
} | ||
return !res; | ||
} | ||
|
||
private static boolean isNotSecurity(String key, String value, String param) { | ||
return key.toLowerCase().contains(param.toLowerCase()) | ||
|| value.toLowerCase().contains(param.toLowerCase()); | ||
} | ||
} |
Oops, something went wrong.