Nashornはjsのセキュリティポリシーを実行します
8059 ワード
JAvaでjavax.scriptを使用してjsのセキュリティ防御を実行
0 x 01背景
ある浸透テストでは、システムのバックグラウンドにブラウザのjsコードを受信するサーバがあり、javax.scriptというコンポーネントを使用してjsコードを実行していることがわかりました.ここでは、以下のpocを使用してシステムコマンドを実行できます.
RDに聞いてみると、ここではもともとシステムの下部コマンドで、ここでjsを使ってデータフィルタリングのタスクをより柔軟に完了します.ここでjavax.scriptはNashornエンジンを使用してjsコードを実行し、制限しない場合はruntimeクラスを呼び出すなどの方法でシステムコマンドを実行します.開発側も直すわけにはいかないので、制限の方法を考えてみましょう.Googleが検索すると、starkoverflowとopenjdkがソリューションを提供していることがわかりました.ここでお話しします.
0 x 02解決
1.openjdkのソリューション
ここでopenjdkはjavaxがjsコードを実行すると説明し、デフォルトではセキュリティ制限はありません.任意のjavaオブジェクトにアクセスできます.しかし、java.security.policyを使用してpolicyファイルを作成し、システムコマンドを実行できない、システムの一部のファイルにアクセスできないなど、対応するjavaの動作を制限することができます.インスタンスコードは次のとおりです.
コードではまずnashornのjsエンジンを作成し、ファイルを読み取り、evalを介してファイル内のコードを実行します.制限しないと、jsファイルの内容が次のように仮定される任意のコード実行脆弱性が生じることがわかります.
JavaのFileオブジェクトから、現在のフォルダのすべてのフォルダとファイルを取得して印刷することを意味します.次にpolicyファイルを作成することで、この動作を制限することができます.
次のコマンドを使用して、
このとき再実行すると、セキュリティポリシーの制限によりエラーが発生します
ここでセキュリティポリシーの権限とは、コードの実行を許可する操作を指す.権限タイプ、権限名、および許可されたアクションの3つのセクションがあります.パーミッションタイプは、パーミッションを実装したJavaクラス名で、必須です.権限名とは、通常、ファイル名やワイルドカード、ネットワークホストなど、どのリソースを操作するリソースの位置づけであり、java.security.AllPermissionには権限名が不要な権限タイプに基づいて設定されます.許可された操作は、権限タイプにも対応しており、読み取り、書き込みなど、ターゲットに対して実行可能な操作動作を指定します.次の例を示します.
を選択します.
権限名
操作
例
ファイル権限
java.io.FilePermission
ファイル名(プラットフォーム依存)
読み取り、書き込み、削除、実行
すべての質問の読み取りと書き込みの削除を許可します:permission java.io.FilePermission"<"、"read,write,delete,execute";ユーザーホームの読み取りを許可:permission java.io.FilePermission"${user.home}/-","read";.
ソケット権限
java.net.SocketPermission
ホスト名:ポート
受信、傍受、接続、解析
すべてのソケット操作を可能にします:permission java.net.SocketPermission":1-","accept,listen,connect,resolve";特定のWebサイトへの接続を許可:permission java.net.SocketPermission".abc.com:1-","connect,resolve";
属性権限
java.util.PropertyPermission
アクセスが必要なjvmプロパティ名
読み書き
標準Java属性:permission java.util.PropertyPermission「java.」、「read」;.sdoパッケージに属性を作成します:permission java.util.PropertyPermission"sdo.","read,write";
ランタイム権限
java.lang.RuntimePermission
多種の権限名[付録A参照]
なし
コード初期化印刷タスクの許可:permission java.lang.RuntimePermission"queuePrintJob"
AWT権限
java.awt.AWTPermission
6種類の権限名[付録B参照]
なし
コードがrobotクラスを十分に使用できるようにする:permission java.awt.AWTPermission"createRobot";permission java.awt.AWTPermission "readDisplayPixels";.
ネットワーク権限
java.net.NetPermission
3種類の権限名[付録C参照]
なし
ストリームプロセッサのインストールを許可:permission java.net.NetPermission"specifyStreamHandler";
セキュリティ権限
java.security.SecurityPermission
多種の権限名[付録D参照]
なし
シーケンス権限
java.io.SerializablePermission
2種類の権限名[付録E参照]
なし
権限の反射
java.lang.reflect.ReflectPermission
uppressAccessChecks(任意のクラスのプライベート変数を反射でチェックできる)
なし
完全な権限
java.security.AllPermission
なし(アクションを実行する権限があります)
なし
ポリシーファイルの作成
ポリシーファイルは、砂箱を制御する管理要素であり、1つのポリシーファイルには1つ以上の保護ドメインの項目が含まれています.ポリシー・ファイルは、グローバルとユーザー固有の2つのポリシー・ファイルを含むコード権限の指定されたタスクを完了しました.
砂箱を管理するためには、ポリシーファイルが最も重要な内容だと思います.JVMは複数のポリシーファイルを使用できますが、一般的には2つが最も一般的です.1つはグローバル:$JREHOME/lib/security/java.policy、JVMのすべてのインスタンスに作用します.もう1つはユーザ自身であり,ユーザのホームディレクトリに格納できる.ポリシーファイルはjdkが所有するpolicytoolツールを使用して編集できます.
2.stackoverflowが提供するソリューション
jdk 1.8 u 40では、ClassFilterを使用してjsエンジンがアクセスできるクラスを制限できます.コードは次のとおりです.
実行すると、次のようにエラーが表示されます.
3.nashornsandbox砂箱方案
A secure sandbox for executing JavaScript in Java apps using the Nashorn engine.
次のコードでnashornエンジンがクラスにアクセス/拒否できるように制御でき、簡単で使いやすい
さらにこの砂箱の役割は大きく、javaクラスのアクセスを制限するだけでなく、nashornエンジンのリソースの使用状況を制限することもできます.
0 x 01背景
ある浸透テストでは、システムのバックグラウンドにブラウザのjsコードを受信するサーバがあり、javax.scriptというコンポーネントを使用してjsコードを実行していることがわかりました.ここでは、以下のpocを使用してシステムコマンドを実行できます.
function getResult(sqlArr) {
var r = "";
java.io.BufferedReader
b = java.lang.Runtime.getRuntime().exec('whoami').getInputStream();
r = String.fromCharCode(b.read());
while ((i = b.read()) != -1)
r = r + String.fromCharCode(i);
return r;
}
RDに聞いてみると、ここではもともとシステムの下部コマンドで、ここでjsを使ってデータフィルタリングのタスクをより柔軟に完了します.ここでjavax.scriptはNashornエンジンを使用してjsコードを実行し、制限しない場合はruntimeクラスを呼び出すなどの方法でシステムコマンドを実行します.開発側も直すわけにはいかないので、制限の方法を考えてみましょう.Googleが検索すると、starkoverflowとopenjdkがソリューションを提供していることがわかりました.ここでお話しします.
0 x 02解決
1.openjdkのソリューション
ここでopenjdkはjavaxがjsコードを実行すると説明し、デフォルトではセキュリティ制限はありません.任意のjavaオブジェクトにアクセスできます.しかし、java.security.policyを使用してpolicyファイルを作成し、システムコマンドを実行できない、システムの一部のファイルにアクセスできないなど、対応するjavaの動作を制限することができます.インスタンスコードは次のとおりです.
import java.io.*;
import java.nio.file.*;
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
if (args.length == 0) {
System.err.println("Usage: java Main ");
return;
}
// args[0] is script file to which permissions are granted
// in security policy
File file = new File(args[0]);
// read the file content and pass a String to 'eval'
// The script is untrusted as nashorn does not know the origin!
try {
e.eval(new String(Files.readAllBytes(file.toPath())));
} catch (SecurityException se) {
System.out.println(se);
}
// create a Reader over the file and pass to 'eval'
// The script is untrusted as nashorn does not know the origin!
try {
e.eval(new FileReader(file));
} catch (SecurityException se) {
System.out.println(se);
}
// pass a URLReader on file - script will get permissions
// configured in security policy!
e.eval(new URLReader(file.toURL()));
}
}
コードではまずnashornのjsエンジンを作成し、ファイルを読み取り、evalを介してファイル内のコードを実行します.制限しないと、jsファイルの内容が次のように仮定される任意のコード実行脆弱性が生じることがわかります.
test.js
var File = java.io.File;
// list contents of the current directory!
for each (var f in new File(".").list())
print(f)
JavaのFileオブジェクトから、現在のフォルダのすべてのフォルダとファイルを取得して印刷することを意味します.次にpolicyファイルを作成することで、この動作を制限することができます.
test.policy
/ give AllPermission for Main class (or any class in that directory!)
grant codeBase "file:///d:/test" {
permission java.security.AllPermission;
};
// give AllPermission to test.js script
grant codeBase "file:///d:/test/test.js" {
permission java.security.AllPermission;
};
次のコマンドを使用して、
java -Djava.security.manager -Djava.security.policy=./test.policy Main test.js
をロードして実行します.このとき再実行すると、セキュリティポリシーの制限によりエラーが発生します
java.security.AccessControlException: access denied ("java.io.FilePermission" "." "read")
java.security.AccessControlException: access denied ("java.io.FilePermission" "." "read")
Main.class
Main.java
test.js
test.policy
ここでセキュリティポリシーの権限とは、コードの実行を許可する操作を指す.権限タイプ、権限名、および許可されたアクションの3つのセクションがあります.パーミッションタイプは、パーミッションを実装したJavaクラス名で、必須です.権限名とは、通常、ファイル名やワイルドカード、ネットワークホストなど、どのリソースを操作するリソースの位置づけであり、java.security.AllPermissionには権限名が不要な権限タイプに基づいて設定されます.許可された操作は、権限タイプにも対応しており、読み取り、書き込みなど、ターゲットに対して実行可能な操作動作を指定します.次の例を示します.
を選択します.
権限名
操作
例
ファイル権限
java.io.FilePermission
ファイル名(プラットフォーム依存)
読み取り、書き込み、削除、実行
すべての質問の読み取りと書き込みの削除を許可します:permission java.io.FilePermission"<
ソケット権限
java.net.SocketPermission
ホスト名:ポート
受信、傍受、接続、解析
すべてのソケット操作を可能にします:permission java.net.SocketPermission":1-","accept,listen,connect,resolve";特定のWebサイトへの接続を許可:permission java.net.SocketPermission".abc.com:1-","connect,resolve";
属性権限
java.util.PropertyPermission
アクセスが必要なjvmプロパティ名
読み書き
標準Java属性:permission java.util.PropertyPermission「java.」、「read」;.sdoパッケージに属性を作成します:permission java.util.PropertyPermission"sdo.","read,write";
ランタイム権限
java.lang.RuntimePermission
多種の権限名[付録A参照]
なし
コード初期化印刷タスクの許可:permission java.lang.RuntimePermission"queuePrintJob"
AWT権限
java.awt.AWTPermission
6種類の権限名[付録B参照]
なし
コードがrobotクラスを十分に使用できるようにする:permission java.awt.AWTPermission"createRobot";permission java.awt.AWTPermission "readDisplayPixels";.
ネットワーク権限
java.net.NetPermission
3種類の権限名[付録C参照]
なし
ストリームプロセッサのインストールを許可:permission java.net.NetPermission"specifyStreamHandler";
セキュリティ権限
java.security.SecurityPermission
多種の権限名[付録D参照]
なし
シーケンス権限
java.io.SerializablePermission
2種類の権限名[付録E参照]
なし
権限の反射
java.lang.reflect.ReflectPermission
uppressAccessChecks(任意のクラスのプライベート変数を反射でチェックできる)
なし
完全な権限
java.security.AllPermission
なし(アクションを実行する権限があります)
なし
ポリシーファイルの作成
ポリシーファイルは、砂箱を制御する管理要素であり、1つのポリシーファイルには1つ以上の保護ドメインの項目が含まれています.ポリシー・ファイルは、グローバルとユーザー固有の2つのポリシー・ファイルを含むコード権限の指定されたタスクを完了しました.
砂箱を管理するためには、ポリシーファイルが最も重要な内容だと思います.JVMは複数のポリシーファイルを使用できますが、一般的には2つが最も一般的です.1つはグローバル:$JREHOME/lib/security/java.policy、JVMのすべてのインスタンスに作用します.もう1つはユーザ自身であり,ユーザのホームディレクトリに格納できる.ポリシーファイルはjdkが所有するpolicytoolツールを使用して編集できます.
2.stackoverflowが提供するソリューション
jdk 1.8 u 40では、ClassFilterを使用してjsエンジンがアクセスできるクラスを制限できます.コードは次のとおりです.
import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
public class MyClassFilterTest {
class MyCF implements ClassFilter {
@Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0) return false;
return true;
}
}
public void testClassFilter() {
final String script =
"print(java.lang.System.getProperty(\"java.home\"));" +
"print(\"Create file variable\");" +
"var File = Java.type(\"java.io.File\");";
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(
new MyClassFilterTest.MyCF());
try {
engine.eval(script);
} catch (Exception e) {
System.out.println("Exception caught: " + e.toString());
}
}
public static void main(String[] args) {
MyClassFilterTest myApp = new MyClassFilterTest();
myApp.testClassFilter();
}
}
実行すると、次のようにエラーが表示されます.
C:\Java\jre8
Create file variable
Exception caught: java.lang.RuntimeException: java.lang.ClassNotFoundException:
java.io.File
3.nashornsandbox砂箱方案
A secure sandbox for executing JavaScript in Java apps using the Nashorn engine.
次のコードでnashornエンジンがクラスにアクセス/拒否できるように制御でき、簡単で使いやすい
NashornSandbox sandbox = NashornSandboxes.create();
sandbox.allow(File.class);
sandbox.eval("var File = Java.type('java.io.File'); File;")
さらにこの砂箱の役割は大きく、javaクラスのアクセスを制限するだけでなく、nashornエンジンのリソースの使用状況を制限することもできます.
NashornSandbox sandbox = NashornSandboxes.create();
sandbox.setMaxCPUTime(100);
sandbox.setMaxMemory(50*1024);
sandbox.allowNoBraces(false);
sandbox.setMaxPreparedStatements(30); // because preparing scripts for execution is expensive
sandbox.setExecutor(Executors.newSingleThreadExecutor());
sandbox.eval("var o={}, i=0; while (true) {o[i++]='abc';};");