一、简述
在我们使用ES进行脚本操作的时候,可以在脚本中使用painless等脚本语言,但我们是否有想过在脚本中进行危险操作类似System.exit(0)的时候,ES是怎么规避这种风险的;
不废话,上例子!
POST /trick_search_news_zh/_search
{
"query": {
"bool": {
"filter": {
"script": {
"script": "System.exit(0);"
}
}
}
}
}
{
"error":{
"root_cause":[
{
"type":"script_exception",
"reason":"compile error",
"script_stack":[
"System.exit(0);",
" ^---- HERE"
],
"script":"System.exit(0);",
"lang":"painless",
"position":{
"offset":6,
"start":0,
"end":15
}
}
],
"type":"search_phase_execution_exception",
"reason":"all shards failed",
"phase":"query",
"grouped":true,
"failed_shards":[
{
"shard":0,
"index":"trick_search_news_zh",
"node":"CYqvksZkTwS5uzaFXGE2gw",
"reason":{
"type":"query_shard_exception",
"reason":"failed to create query: compile error",
"index_uuid":"siBuitizTt2iJtcUkBdIBA",
"index":"trick_search_news_zh",
"caused_by":{
"type":"script_exception",
"reason":"compile error",
"script_stack":[
"System.exit(0);",
" ^---- HERE"
],
"script":"System.exit(0);",
"lang":"painless",
"position":{
"offset":6,
"start":0,
"end":15
},
"caused_by":{
"type":"illegal_argument_exception",
"reason":"static method [java.lang.System, exit/1] not found"
}
}
}
}
],
"caused_by":{
"type":"script_exception",
"reason":"compile error",
"script_stack":[
"System.exit(0);",
" ^---- HERE"
],
"script":"System.exit(0);",
"lang":"painless",
"position":{
"offset":6,
"start":0,
"end":15
},
"caused_by":{
"type":"illegal_argument_exception",
"reason":"static method [java.lang.System, exit/1] not found"
}
}
},
"status":400
}
二、详解
先讲述一下Java的SecurityManager,该类是Java安全模型的核心部分,它是一个允许应用程序实现自定义安全策略的类;而ES就是使用该功能进行了危险操作的规避;
而SecurityManager可以简单理解为,使用该类可以定义了一系列的check方法,在指令层每当有一个敏感操作被执行时,会先抵达SecurityManager进行过滤,它对一些可能影响系统安全的敏感操作进行监控和控制。它会在这些操作执行前进行检查,并根据定义的安全策略决定是否允许这些操作。(这些敏感操作包括文件读写、网络访问、执行系统命令、动态加载类等)
Mark至源码org.elasticsearch.bootstrap.Security,可以看到如下静态方法块
也就是说在 Elasticsearch 启动时,会对自定义的 SecurityManager 进行初始化。
而该方法的核心在于SecureSM类,该类体现了自定义SecurityManage并进行了哪些check:
其实朋友们看到这就应该能够 理解了,在该类中进行了一系列的check,使得Elasticsearch在指令层面添加了类似过滤器的形态,当我们的指令为System.exit(0)时,会被其感知并抛出SecurityException,从而导致我们上面的例子出现了编译失败!
三、总结
在IK的源码中也有很多涉及Security相关的操作,但Java9以后相对使用SecurityManager的时候比较少;
一些Java开源的组件在使用过程中出现思考或问题,可以尽量参考源代码定位相关位置,从而得到固若金汤的结论;