Java SecureRandom与GWT编译器兼容性问题求助
问题分析与解决方案
问题本质
你的核心问题是GWT 2.5.1的客户端JRE模拟库不包含java.security.SecureRandom:
- Eclipse能编译通过是因为它只做普通Java代码编译,不做GWT的客户端转译;
- GWT插件编译失败是因为它需要把客户端代码转译成JS,而所有用到的类必须在GWT的JRE模拟列表中,
SecureRandom不在其中。
可行解决方案
方案1:将安全随机数生成逻辑移至服务端(推荐)
安全随机数的生成本就不应该放在客户端(客户端环境不可控,容易被篡改),完全符合Fortify的安全要求,同时避开GWT的限制:
- 定义GWT远程服务接口:
import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @RemoteServiceRelativePath("secureRandomService") public interface SecureRandomService extends RemoteService { // 示例:生成指定长度的随机字节数组 byte[] generateSecureRandomBytes(int length); // 或者生成随机字符串等业务需要的格式 String generateSecureRandomString(int length); }
- 创建服务端实现类:
import java.security.SecureRandom; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class SecureRandomServiceImpl extends RemoteServiceServlet implements SecureRandomService { private final SecureRandom secureRandom = new SecureRandom(); @Override public byte[] generateSecureRandomBytes(int length) { byte[] bytes = new byte[length]; secureRandom.nextBytes(bytes); return bytes; } @Override public String generateSecureRandomString(int length) { byte[] bytes = new byte[length]; secureRandom.nextBytes(bytes); return Base64.getEncoder().encodeToString(bytes).substring(0, length); } }
- 客户端调用服务获取随机数:
SecureRandomServiceAsync service = GWT.create(SecureRandomService.class); service.generateSecureRandomBytes(16, new AsyncCallback<byte[]>() { @Override public void onSuccess(byte[] result) { // 处理获取到的安全随机数 } @Override public void onFailure(Throwable caught) { // 处理异常 } });
方案2:客户端使用JSNI封装原生JS安全随机API
如果业务必须在客户端生成安全随机数,可以通过GWT的JSNI调用浏览器原生的crypto.getRandomValues()(支持现代浏览器),封装成Java类使用:
public class ClientSecureRandom { // JSNI方法调用浏览器原生安全随机API private native void getRandomValues(byte[] array) /*-{ if ($wnd.crypto && $wnd.crypto.getRandomValues) { $wnd.crypto.getRandomValues(array); } else if ($wnd.msCrypto && $wnd.msCrypto.getRandomValues) { // 兼容IE11 $wnd.msCrypto.getRandomValues(array); } else { throw new Error("No secure random available in this browser"); } }-*/; public void nextBytes(byte[] bytes) { if (bytes == null || bytes.length == 0) { return; } getRandomValues(bytes); } // 可扩展生成随机字符串等方法 public String generateRandomString(int length) { byte[] bytes = new byte[length]; nextBytes(bytes); return com.google.gwt.user.client.Base64.encode(bytes).substring(0, length); } }
然后客户端直接使用这个类替代SecureRandom即可,GWT编译时能正常转译JSNI代码。
注意事项
- 方案1是最安全且符合规范的做法,优先选择;
- 方案2依赖浏览器的
cryptoAPI,需要确认你的目标浏览器都支持(IE11及以上、现代浏览器都支持); - 不要尝试“跳过编译”这类方案,会导致客户端代码运行时出错,且不符合安全要求。
内容的提问来源于stack exchange,提问作者Ashish Parab
相关产品推荐
相关产品推荐

