Enabling Java Security Manager for WSO2 products
Why Java Security Manager is needed?
In Java, the Security Manager is available for applications to have various security policies. The Security Manager helps to prevent untrusted code from doing malicious actions on the system.
The security policies should explicitly allow actions performed by the code base. If any of the actions are not allowed by the security policy, there will be a SecurityException.
For more information on this, you can refer Java SE 7 Security Documentation.
Security Policy Guidelines for WSO2 Products
When enabling Security Manager for WSO2 products, it is recommended to give all permissions to all jars inside WSO2 product. For that, we plan to sign all jars using a common key and grant all permissions to the signed code by using "signedBy" grant as follows.
grant signedBy "<signer>" { permission java.security.AllPermission; };
We also recommend to allow all property reads and WSO2 has a customized Carbon Security Manager to deny certain system properties.
One of the main reasons is that in Java Security Policy, we need to explicitly mention which properties are allowed and if there are various user applications, we cannot have a pre-defined list of System Properties. Therefore Carbon Security Manager's approach is to define a list of denied properties using the System Property "denied.system.properties". This approach basically changes Java Security Manager's rule of "Deny all, allow specified" to "Allow all, deny specified".
There is another system property named "restricted.packages" to control the package access. However this "restricted.packages" system property is not working in latest Carbon and I have created CARBON-14967 JIRA to fix that properly in a future Carbon release.
Signing all JARs inside WSO2 product.
To sign the jars, we need a key. We can use the keytool command to generate a key.
$ keytool -genkey -alias signFiles -keyalg RSA -keystore signkeystore.jks -validity 3650 -dname "CN=Isuru,OU=Engineering, O=WSO2, L=Colombo, ST=Western, C=LK" Enter keystore password: Re-enter new password: Enter key password for (RETURN if same as keystore password):
Now extract the WSO2 product. I will be taking WSO2 Application Server as an example.
$ unzip -q ~/wso2-packs/wso2as-5.2.1.zip
Let's create two scripts to sign the jars. First script will find all jars and the second script will be used to sign a jar using the keystore we created earlier.
signJars.sh script:
#!/bin/bash if [[ ! -d $1 ]]; then echo "Please specify a target directory" exit 1 fi for jarfile in `find . -type f -iname \*.jar` do ./signJar.sh $jarfile done
signJar.sh script:
#!/bin/bash set -e jarfile=$1 keystore_file="signkeystore.jks" keystore_keyalias='signFiles' keystore_storepass='wso2123' keystore_keypass='wso2123' signjar="$JAVA_HOME/bin/jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore $keystore_file -storepass $keystore_storepass -keypass $keystore_keypass" verifyjar="$JAVA_HOME/bin/jarsigner -keystore $keystore_file -verify" echo "Signing $jarfile" $signjar $jarfile $keystore_keyalias echo "Verifying $jarfile" $verifyjar $jarfile # Check whether the verification is successful. if [ $? -eq 1 ] then echo "Verification failed for $jarfile" fi
Now we can see following files.
When we run signJars.sh, all JARs found inside WSO2 Application Server will be signed using the "signFiles" key.
$ ls -l -rwxrwxr-x 1 isuru isuru 602 Dec 9 13:05 signJar.sh -rwxrwxr-x 1 isuru isuru 174 Dec 9 12:56 signJars.sh -rw-rw-r-- 1 isuru isuru 2235 Dec 9 12:58 signkeystore.jks drwxr-xr-x 11 isuru isuru 4096 Dec 6 2013 wso2as-5.2.1
When we run signJars.sh, all JARs found inside WSO2 Application Server will be signed using the "signFiles" key.
$ ./signJars.sh wso2as-5.2.1/ > log
Configuring WSO2 Product to use Java Security Manager
To configure Java Security Manager, we need to pass few arguments to the main Java process.
Java Security Manager can be enabled by using "java.security.manager" system property. We will specify the WSO2 Carbon Security Manager using this argument.
We also need to specify the security policy file using "java.security.policy" system property.
As I mentioned earlier, we will also set "restricted.packages" & "denied.system.properties" system properties.
Following is the recommended set of values to be used in wso2server.sh (Edit the startup script and add following lines just before the line " org.wso2.carbon.bootstrap.Bootstrap $*"
-Djava.security.manager=org.wso2.carbon.bootstrap.CarbonSecurityManager \ -Djava.security.policy=$CARBON_HOME/repository/conf/sec.policy \ -Drestricted.packages=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,org.wso2.carbon. \ -Ddenied.system.properties=javax.net.ssl.trustStore,javax.net.ssl.trustStorePassword,denied.system.properties \
Exporting signFiles public key certificate and importing it to wso2carbon.jks
We need to import the signFiles public key certificate to the wso2carbon.jks as the security policy file will be referring the signFiles signer certificate from the wso2carbon.jks (as specified by the first line).
$ keytool -export -keystore signkeystore.jks -alias signFiles -file sign-cert.cer $ keytool -import -alias signFiles -file sign-cert.cer -keystore wso2as-5.2.1/repository/resources/security/wso2carbon.jks
Note: wso2carbon.jks' keystore password is "wso2carbon".
The Security Policy File
As specified in the system property "java.security.policy", we will keep the security policy file at $CARBON_HOME/repository/conf/sec.policy
Following policy file should be enough for starting up WSO2 Application Server and deploying a sample JSF & CXF webapps.
keystore "file:${user.dir}/repository/resources/security/wso2carbon.jks", "JKS"; // ========= Carbon Server Permissions =================================== grant { // Allow socket connections for any host permission java.net.SocketPermission "*:1-65535", "connect,resolve"; // Allow to read all properties. Use -Ddenied.system.properties in wso2server.sh to restrict properties permission java.util.PropertyPermission "*", "read"; permission java.lang.RuntimePermission "getClassLoader"; // CarbonContext APIs require this permission permission java.lang.management.ManagementPermission "control"; // Required by any component reading XMLs. For example: org.wso2.carbon.databridge.agent.thrift:4.2.1. permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind.v2.runtime.reflect"; // Required by org.wso2.carbon.ndatasource.core:4.2.0. This is only necessary after adding above permission. permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind"; }; // ========= Platform signed code permissions =========================== grant signedBy "signFiles" { permission java.security.AllPermission; }; // ========= Granting permissions to webapps ============================ grant codeBase "file:${carbon.home}/repository/deployment/server/webapps/-" { // Required by webapps. For example JSF apps. permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; // Required by webapps. For example JSF apps require this to initialize com.sun.faces.config.ConfigureListener permission java.lang.RuntimePermission "setContextClassLoader"; // Required by webapps to make HttpsURLConnection etc. permission java.lang.RuntimePermission "modifyThreadGroup"; // Required by webapps. For example JSF apps need to invoke annotated methods like @PreDestroy permission java.lang.RuntimePermission "accessDeclaredMembers"; // Required by webapps. For example JSF apps permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.compiler"; // Required by webapps. For example JSF EL permission java.lang.RuntimePermission "getClassLoader"; // Required by CXF app. Needed when invoking services permission javax.xml.bind.JAXBPermission "setDatatypeConverter"; // File reads required by JSF (Sun Mojarra & MyFaces require these) // MyFaces has a fix https://issues.apache.org/jira/browse/MYFACES-3590 permission java.io.FilePermission "/META-INF", "read"; permission java.io.FilePermission "/META-INF/-", "read"; // OSGi permissions are requied to resolve bundles. Required by JSF permission org.osgi.framework.AdminPermission "*", "resolve,resource"; };
The security policies may vary depending on your requirements. I recommend to test your application thoroughly in a development environment.
NOTE: There are risks in allowing some Runtime Permissions. Please look at the java docs for RuntimePermission. See Concerns below.
Troubleshooting Java Security
Java provides the "java.security.debug" system property to set various debugging options and monitor security access.
I recommend to add following line to wso2server.sh whenever you need to troubleshoot some issue with Java Security.
-Djava.security.debug="access,failure"
After adding that line, all the debug information will be printed to standard output. To check the logs, we can start the server using nohup.
$ nohup ./wso2server.sh &
Then we can grep the nohup.out and look for access denied messages.
$ tailf nohup.out | grep denied
Concerns with Java Security Policy
There are few concerns with current permission model in WSO2 products.
- Use of ManagementPermission instead of Carbon specific permissions. The real ManagementPermission is used for a different purpose. I created CARBON-14966 jira to fix that.
- Ideally the permission 'java.lang.management.ManagementPermission "control"' should not be specified in policy file as it is only required for privileged actions in Carbon. However due to indirect usage of such privileged actions within Carbon code, we need to specify that permission. This also needs to be fixed.
- In above policy file, the JSF webapps etc require some risky runtime permissions. I recommend to use a Custom Runtime Environment (CRE) in WSO2 Application Server for JSF webapps etc and sign the jars inside CRE. You can also grant permissions based on the jar names (Use grant codeBase). However signing jars and using a CRE is a better approach with WSO2 AS.
Comments