mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-27 10:28:28 +00:00
parent
051beb51a3
commit
81e83cca74
@ -19,6 +19,58 @@ All places where a `script` parameter can be used, a `lang` parameter
|
||||
script. The `lang` options are `mvel`, `js`, `groovy`, `python`, and
|
||||
`native`.
|
||||
|
||||
added[1.2.0, Dynamic scripting is disabled by default since version 1.2.0]
|
||||
|
||||
To increase security, Elasticsearch does not allow you to specify scripts with a
|
||||
request. Instead, scripts must be placed in the `scripts` directory inside the
|
||||
configuration directory (the directory where elasticsearch.yml is). Scripts
|
||||
placed into this directory will automatically be picked up and be available to
|
||||
be used. Once a script has been placed in this directory, it can be referenced
|
||||
by name. For example, a script called `calculate-score.mvel` can be referenced
|
||||
in a request like this:
|
||||
|
||||
[source]
|
||||
--------------------------------------------------
|
||||
$ tree config
|
||||
config
|
||||
├── elasticsearch.yml
|
||||
├── logging.yml
|
||||
└── scripts
|
||||
└── calculate-score.mvel
|
||||
$ cat config/scripts/calculate-score.mvel
|
||||
Math.log(_score * 2) + my_modifier
|
||||
--------------------------------------------------
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
curl -XPOST localhost:9200/_search -d '{
|
||||
"query": {
|
||||
"function_score": {
|
||||
"query": {
|
||||
"match": {
|
||||
"body": "foo"
|
||||
}
|
||||
},
|
||||
"functions": [
|
||||
{
|
||||
"script_score": {
|
||||
"script": "calculate-score",
|
||||
"params": {
|
||||
"my_modifier": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}'
|
||||
--------------------------------------------------
|
||||
|
||||
The name of the script is derived from the hierarchy of directories it
|
||||
exists under, and the file name without the lang extension. For example,
|
||||
a script placed under `config/scripts/group1/group2/test.py` will be
|
||||
named `group1_group2_test`.
|
||||
|
||||
[float]
|
||||
=== Default Scripting Language
|
||||
|
||||
@ -27,46 +79,31 @@ provided) is `mvel`. In order to change it set the `script.default_lang`
|
||||
to the appropriate language.
|
||||
|
||||
[float]
|
||||
=== Preloaded Scripts
|
||||
|
||||
Scripts can always be provided as part of the relevant API, but they can
|
||||
also be preloaded by placing them under `config/scripts` and then
|
||||
referencing them by the script name (instead of providing the full
|
||||
script). This helps reduce the amount of data passed between the client
|
||||
and the nodes.
|
||||
|
||||
The name of the script is derived from the hierarchy of directories it
|
||||
exists under, and the file name without the lang extension. For example,
|
||||
a script placed under `config/scripts/group1/group2/test.py` will be
|
||||
named `group1_group2_test`.
|
||||
|
||||
[float]
|
||||
=== Disabling dynamic scripts
|
||||
=== Enabling dynamic scripting
|
||||
|
||||
We recommend running Elasticsearch behind an application or proxy,
|
||||
which protects Elasticsearch from the outside world. If users are
|
||||
allowed to run dynamic scripts (even in a search request), then they
|
||||
have the same access to your box as the user that Elasticsearch is
|
||||
running as.
|
||||
running as. For this reason dynamic scripting is disabled by default.
|
||||
|
||||
First, you should not run Elasticsearch as the `root` user, as this
|
||||
would allow a script to access or do *anything* on your server, without
|
||||
limitations. Second, you should not expose Elasticsearch directly to
|
||||
users, but instead have a proxy application inbetween. If you *do*
|
||||
intend to expose Elasticsearch directly to your users, then you have
|
||||
to decide whether you trust them enough to run scripts on your box or
|
||||
not. If not, then even if you have a proxy which only allows `GET`
|
||||
requests, you should disable dynamic scripting by adding the following
|
||||
setting to the `config/elasticsearch.yml` file on every node:
|
||||
First, you should not run Elasticsearch as the `root` user, as this would allow
|
||||
a script to access or do *anything* on your server, without limitations. Second,
|
||||
you should not expose Elasticsearch directly to users, but instead have a proxy
|
||||
application inbetween. If you *do* intend to expose Elasticsearch directly to
|
||||
your users, then you have to decide whether you trust them enough to run scripts
|
||||
on your box or not. If you do, you can enable dynamic scripting by adding the
|
||||
following setting to the `config/elasticsearch.yml` file on every node:
|
||||
|
||||
[source,yaml]
|
||||
-----------------------------------
|
||||
script.disable_dynamic: true
|
||||
script.disable_dynamic: false
|
||||
-----------------------------------
|
||||
|
||||
This will still allow execution of named scripts provided in the config, or
|
||||
_native_ Java scripts registered through plugins, however it will prevent
|
||||
users from running arbitrary scripts via the API.
|
||||
While this still allows execution of named scripts provided in the config, or
|
||||
_native_ Java scripts registered through plugins, it also allows users to run
|
||||
arbitrary scripts via the API. Instead of sending the name of the file as the
|
||||
script, the body of the script can be sent instead.
|
||||
|
||||
[float]
|
||||
=== Automatic Script Reloading
|
||||
@ -113,7 +150,7 @@ doc score using `doc.score`.
|
||||
[float]
|
||||
=== Computing scores based on terms in scripts
|
||||
|
||||
see <<modules-advanced-scripting, advanced scripting documentation>>
|
||||
see <<modules-advanced-scripting, advanced scripting documentation>>
|
||||
|
||||
[float]
|
||||
=== Document Fields
|
||||
|
@ -52,6 +52,11 @@ public class NativeScriptEngineService extends AbstractComponent implements Scri
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sandboxed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) {
|
||||
NativeScriptFactory scriptFactory = scripts.get(script);
|
||||
|
@ -33,6 +33,8 @@ public interface ScriptEngineService {
|
||||
|
||||
String[] extensions();
|
||||
|
||||
boolean sandboxed();
|
||||
|
||||
Object compile(String script);
|
||||
|
||||
ExecutableScript executable(Object compiledScript, @Nullable Map<String, Object> vars);
|
||||
|
@ -75,7 +75,7 @@ public class ScriptService extends AbstractComponent {
|
||||
logger.debug("using script cache with max_size [{}], expire [{}]", cacheMaxSize, cacheExpire);
|
||||
|
||||
this.defaultLang = componentSettings.get("default_lang", "mvel");
|
||||
this.disableDynamic = componentSettings.getAsBoolean("disable_dynamic", false);
|
||||
this.disableDynamic = componentSettings.getAsBoolean("disable_dynamic", true);
|
||||
|
||||
CacheBuilder cacheBuilder = CacheBuilder.newBuilder();
|
||||
if (cacheMaxSize >= 0) {
|
||||
@ -129,7 +129,7 @@ public class ScriptService extends AbstractComponent {
|
||||
if (lang == null) {
|
||||
lang = defaultLang;
|
||||
}
|
||||
if (dynamicScriptDisabled(lang)) {
|
||||
if (!dynamicScriptEnabled(lang)) {
|
||||
throw new ScriptException("dynamic scripting disabled");
|
||||
}
|
||||
CacheKey cacheKey = new CacheKey(lang, script);
|
||||
@ -175,12 +175,17 @@ public class ScriptService extends AbstractComponent {
|
||||
cache.invalidateAll();
|
||||
}
|
||||
|
||||
private boolean dynamicScriptDisabled(String lang) {
|
||||
if (!disableDynamic) {
|
||||
return false;
|
||||
private boolean dynamicScriptEnabled(String lang) {
|
||||
ScriptEngineService service = scriptEngines.get(lang);
|
||||
if (service == null) {
|
||||
throw new ElasticsearchIllegalArgumentException("script_lang not supported [" + lang + "]");
|
||||
}
|
||||
// we allow "native" executions since they register through plugins, so they are "allowed"
|
||||
return !"native".equals(lang);
|
||||
// Templating languages and native scripts are always allowed
|
||||
// "native" executions are registered through plugins
|
||||
if (service.sandboxed() || "native".equals(lang)) {
|
||||
return true;
|
||||
}
|
||||
return !disableDynamic;
|
||||
}
|
||||
|
||||
private class ScriptChangesListener extends FileChangesListener {
|
||||
|
@ -120,6 +120,11 @@ public class MustacheScriptEngineService extends AbstractComponent implements Sc
|
||||
return new String[] {"mustache"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sandboxed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutableScript executable(Object mustache,
|
||||
@Nullable Map<String, Object> vars) {
|
||||
|
@ -79,6 +79,11 @@ public class MvelScriptEngineService extends AbstractComponent implements Script
|
||||
return new String[]{"mvel"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sandboxed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) {
|
||||
return MVEL.compileExpression(script.trim(), new ParserContext(parserConfiguration));
|
||||
|
@ -200,6 +200,7 @@ public final class TestCluster extends ImmutableTestCluster {
|
||||
builder.put("path.data", dataPath.toString());
|
||||
}
|
||||
}
|
||||
builder.put("script.disable_dynamic", false);
|
||||
defaultSettings = builder.build();
|
||||
executor = EsExecutors.newCached(1, TimeUnit.MINUTES, EsExecutors.daemonThreadFactory("test_" + clusterName));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user