我使用Facebook Messenger platform开发了一个聊天机器人应用程序。 我使用Spring Boot嵌入式Tomcat作为Web平台。 该应用程序应该在Amazon aws上运行,对WWW开放,并用作webhook,用于通过https接收来自Messenger的回调。
我需要一个如何保护应用程序的建议,因此不会被来自Facebook的请求所攻击或充斥。
我想让应用程序需要安全(ssl)连接,但在application.properties中使用“security.require_ssl = true”并没有完成工作。也许我不知道这是什么意思以及如何配置它。 是否有最佳实践如何阻止非https请求的请求?或者一种阻止应用程序级别的Messenger外部请求的方法?
非常感谢!
修改
与此同时,我使用处理程序拦截器阻止了来自应用程序层中其他IP的请求:
@Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer, WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (! (request.getRemoteAddr().equals("173.252.88.66") || request.getRemoteAddr().equals("127.0.0.1")|| request.getRemoteAddr().equals("0:0:0:0:0:0:0:1"))){
logger.warn("Request is not coming from authorized remote address: " + request.getRemoteAddr()+". Rejecting");
response.getWriter().write("Unauthorized Address");
response.setStatus(401);
return false;
} else {
return true;
}
}
}
答案 0 :(得分:1)
很多话要说,所以我相信我会错过一些观点。
设置SSL是第一件好事,但要确保获得证书。如果您不想支付SSL证书,lets encrypt是一件好事。
只需seeing aws就可以替代letsencrypt
Security Group您可以将安全组视为类似于防火墙的内容,以便您可以控制打开的端口,外部和内部流程。
查看IAM控制谁和如何访问您的AWS账户
显而易见:更改密码。不要让您可以在实例上进行安装的默认密码
阅读一些https://aws.amazon.com/security/security-resources/以获取有关您可以执行的操作的更多信息
它不会被黑客攻击或被请求淹没
很遗憾地说,但最有可能的是 - 它不需要是一个高级黑客来运行扫描仪和扫描IP并检查开放端口/强力登录等...
答案 1 :(得分:1)
您应该检查Facebook发送到您的webhook网址的请求中提供的X-Hub签名HTTP标头。
在您的情况下,您可以定义过滤器或拦截器以验证签名。您也可以在控制器中执行此操作,如我在Spring社交项目的RealTimeUpdateController.java中找到的示例中所示。
private boolean verifySignature(String payload, String signature) throws Exception {
if (!signature.startsWith("sha1=")) {
return false;
}
String expected = signature.substring(5);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
SecretKeySpec signingKey = new SecretKeySpec(applicationSecret.getBytes(), HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(payload.getBytes());
String actual = new String(Hex.encode(rawHmac));
return expected.equals(actual);
}
答案 2 :(得分:1)
感谢Guy Bouallet的帮助,我添加了签名检查。 我将它添加到我的控制器而不是拦截器中,以避免How to read data twice in spring的问题,这似乎有点复杂。
所以就是这样:
@RequestMapping(path = "/")
public void doHandleCallback(@RequestBody String body, @RequestHeader(value = "X-Hub-Signature") String signature) throws IOException {
if (!verifyRequestSignature(body.getBytes(), signature)){
logger.error ("Signature mismatch.");
throw new MismatchSignatureException(signature);
}
MessengerCallback callback = mapper.readValue(body, MessengerCallback.class);
logger.info("Incoming Callback: " + body );
for (EventData entry : callback.getEntry()) {
for (ReceivedMessagingObject message : entry.getMessaging()) {
if (message.isMessage() || message.isPostback()) {
doHandleMessage(message);
}
else if (message.isDelivery()){
doHandleDelivery(message);
}
}
}
}
private boolean verifyRequestSignature(byte[] payload, String signature) {
if (!signature.startsWith("sha1="))
return false;
String expected = signature.substring(5);
System.out.println("Expected signature: " + expected); //for debugging purposes
String hashResult = HmacUtils.hmacSha1Hex(APP_SECRET.getBytes(), payload);
System.out.println("Calculated signature: " + hashResult);
if (hashResult.equals(expected)) {
return true;
} else {
return false;
}
}
这是异常处理类:
@ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Request Signature mismatch")
public class MismatchSignatureException extends RuntimeException {
private String signature;
public MismatchSignatureException(String signature) {
this.signature = signature;
}
@Override
public String getMessage() {
return "Signature mismatch: " + signature;
}