通过反射调用方法会带来哪些安全问题?

Dav*_*hen 9 java json

我正在开发一个拥有主机和客户端的项目,主机可以向客户端发送命令(通过套接字).

我确定使用JSON进行通信是最好的.

例如:

{
    "method" : "toasty",
    "params" : ["hello world", true]
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,当此JSON字符串发送到客户端时,它将被处理,并且客户端内的合适方法将如下运行:

public abstract class ClientProcessor {

    public abstract void toasty(String s, boolean bool);
    public abstract void shutdown(int timer);

    private Method[] methods = getClass().getDeclaredMethods();

    public void process(String data) {
        try {
            JSONObject json = new JSONObject(data);
            String methodName = (String) json.get("method");

            if (methodName.equals("process"))
                return;

            for (int i = 0; i < methods.length; i++)
                if (methods[i].getName().equals(methodName)) {
                    JSONArray arr = json.getJSONArray("params");

                    int length = arr.length();
                    Object[] args = new Object[length];
                    for (int i2 = 0; i2 < length; i2++)
                        args[i2] = arr.get(i2);

                    methods[i].invoke(this, args);
                    return;
                }
        } catch (Exception e) {}
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用ClientProcessor:

public class Client extends ClientProcessor {
    @Override
    public void toasty(String s, boolean bool) {
        //make toast here
    }

    @Override
    public void shutdown(int timer) {
        //shutdown system within timer
    }

    public void processJSON(String json) {
        process(json);
    }
}
Run Code Online (Sandbox Code Playgroud)

JSON由服务器发送到客户端,但可以修改服务器以发送不同的JSON.

我的问题是:

  • 这是通过处理JSON运行方法的安全方法吗?
  • 有一个更好的方法吗?我认为使用反射非常慢.

Nic*_*olt 4

有 100 和 1 种方法可以处理 JSON 消息,以便进行某些处理,但它们都可以归结为:

  • 解析消息
  • 将消息映射到方法
  • 调用方法
  • 发送回复

虽然您可以使用反射调用(从性能角度来说,大多数情况下都可以)来调用方法,但恕我直言,这有点太开放了 - 例如,恶意客户端可能会通过发出调用来使您的系统崩溃wait

反射还让您必须正确映射参数,这比您在问题中显示的代码更复杂。

所以不要使用反射。

您可以定义一个简单的interface,其实现将了解如何处理参数并让您的处理器(更通常称为控制器)调用它,如下所示:

public interface ServiceCall
{
  public JsonObject invoke(JsonArray params) throws ServiceCallException;
}

public class ServiceProcessor
{
  private static final Map<String, ServiceCall> SERVICE_CALLS = new HashMap<>();

  static
  {
    SERVICE_CALLS.put("toasty", new ToastCall());
  }

  public String process(String messageStr) 
  {
    try 
    {
      JsonObject message = Json.createReader(new StringReader(messageStr)).readObject();

      if (message.containsKey("method"))
      {
        String method = message.getString("method");

        ServiceCall serviceCall = SERVICE_CALLS.get(method);

        if (serviceCall != null)
        {
          return serviceCall.invoke(message.getJsonArray("params")).toString();
        }
        else
        {
          return fail("Unknown method: " + method);
        }
      }
      else
      {
        return fail("Invalid message: no method specified");
      }
    } 
    catch (Exception e) 
    {
      return fail(e.message);
    }
  }

  private String fail(String message)
  {
    return Json.createObjectBuilder()
      .add("status", "failed")
      .add("message", message)
      .build()
      .toString();
  }      

  private static class ToastCall implements ServiceCall
  {
    public JsonObject invoke(JsonArray params) throws ServiceCallException  
    {
      //make toast here
    }
  }
}
Run Code Online (Sandbox Code Playgroud)