我的應用程序基於Java的Play Framework。我只是通過將相同的應用程序部署到多個服務器上並在它們之間分配Web請求來進行分發。每個節點將連接到同一個數據庫。如何在Play Framework for Java中的分佈式集羣中實現安全的節點間通信?
Play Framework已經使用Netty,所以我可以選擇使用HTTP請求進行節點之間的通信,但我不確定如何保護這些請求中的一部分,以便其中一些可以從瀏覽器中調用,即我正在使用該框架的網站仍然可以調用某些路由/ API端點,而某些路由/ API端點受到限制,只能由集羣中的其他節點調用,以便節點之間可以進行通信。
下面是一個例子控制器,我想成爲公共訪問
public class TestController extends Controller {
public static Result create() {
JsonNode json = request().body().asJson();
if (json == null) return badRequest("Invalid JSON!");
Testmodel model = JsonHelper.fromJson(json.toString(), Testmodel.class);
if (model == null) return badRequest("JSON does not conform to model!");
MongoHelper.getInstance().getDatastore().save(model);
return ok(JsonHelper.toJson(model));
}
public static Result addOneTest() {
Testmodel somemodel = new Testmodel();
somemodel.setName("name" + Math.random());
somemodel.setValue("val" + Math.random());
MongoHelper.getInstance().getDatastore().save(somemodel);
return ok(JsonHelper.toJson(somemodel));
}
public static Result getAllTest() {
List<Testmodel> all = MongoHelper.getInstance().getDatastore().find(Testmodel.class).asList();
return ok(JsonHelper.toJson(all));
}
public static Result getCountTest() {
long count = MongoHelper.getInstance().getDatastore().getCount(Testmodel.class);
return ok(Long.toString(count));
}
public static Result deleteAllTest() {
Datastore ds = MongoHelper.getInstance().getDatastore();
WriteResult result = ds.delete(ds.createQuery(Testmodel.class));
return ok(JsonHelper.toJson(result));
}
}
而且這裏的示例將/ API端點,該控制器
POST /api/test/create controllers.TestController.create()
POST /api/test/add controllers.TestController.addOneTest()
DELETE /api/test/delete controllers.TestController.deleteAllTest()
GET /api/test/get controllers.TestController.getAllTest
GET /api/test/count controllers.TestController.getCountTest
,這裏是一個控制器的例子我做而不是希望公開訪問,即我只希望羣集中的節點能夠使用它,以便他們可以通過HTTP請求與對方通話,並從另一個節點運行某些方法或將數據傳遞給另一個節點節點。爲了安全起見,對公共無障礙的限制是顯而易見的,我不希望網站上的人員訪問該控制器的任何路線。
public class NodeController extends Controller {
public static Result runJob(ObjectId jobId) {
Submission submission = MongoHelper.getInstance().getDatastore().get(Submission.class, jobId);
if (submission == null) {
return badRequest("No job with that id");
}
// TODO Do some more error checking and validation on the submission
JobRunner.getInstance().run(jobId);
return ok();
}
public static Result cancelJob(ObjectId jobId) {
boolean cancelled = JobRunner.getInstance().cancel(jobId);
if (cancelled) return ok();
else return badRequest("Example error");
}
}
我能找到保護這些使用Play Framework's Allowed Hosts Filters,這使框架僅接受指定的主機的HTTP請求唯一的選擇,但問題是這適用毯子過濾器,即所有的請求都將被限制,即使是我想要公開訪問的那些。
我讀到的另一個選擇是Java遠程方法調用(RMI),但我是初學者,因此對我來說可能有點困難。該項目也相當小和簡單,所以我擔心這可能是矯枉過正。正如你在上面的例子中看到的(特別是NodeController),我需要的只是節點從另一個節點調用一行或兩行代碼。
EDIT
我管理使用Action組成像這樣來限制給定控制器只給預先配置的源地址:
@With(SourceAddressFilter.class)
:
public class SourceAddressFilter extends Action<SourceAddressFilter> {
private static final org.slf4j.Logger LOGGER = play.Logger.underlying();
private static final List<String> allowedAddresses =
Configuration.root().getStringList("nodes.allowedSourceAddresses");
@Override
public CompletionStage<Result> call(Http.Context ctx) {
String srcAddress = ctx.request().remoteAddress();
if (!allowedAddresses.contains(srcAddress)) {
LOGGER.error("Address {} attempted to perform action, but is not in the list of allowed hosts!", srcAddress);
return CompletableFuture.completedFuture(badRequest("Address " + srcAddress + " is not authorized!"));
}
return delegate.call(ctx);
}
}
然後,在每個控制器的開始加入以下註解
它的工作原理,雖然我有點擔心這是一種好的方法,並且如果可能以某種方式在請求中僞造或僅僅通過在Action中調用request()。remoteAddress()來接收錯誤信息。
我仍然有興趣知道是否可以按照答案中的建議使用智威湯遜完成,但我不知道如何。
這絕對看起來很有用。它可能比通過主機或IP過濾更好。我剛剛學會了如何做動作組合,所以我只需要弄清楚JWT是如何工作的。任何關於如何使用它的提示,或者該網站上列出的哪些Java庫文件都很好? –
我用我爲遠程地址過濾所做的操作更新了我的問題。我將如何更新以與JWT合作?看來JWT主要是關於發送安全的有效載荷的,儘管我不想那麼做,我只是想限制錯誤的人員調用證書API。如果所有的JWT都是加密的,那麼是不是有可能攔截HTTP請求並提交一個相同的請求,即使他們不知道會發生什麼,我的應用程序會接受它?重要的是它不會收到任何重複的請求。 –