在 Amazon 上部署 spring 引导应用程序的最佳实践
Best practice for deploying spring boot application on Amazon
我使用 Facebook Messenger platform 开发了一个聊天机器人应用程序。
我在 Web 平台上使用了 Spring Boot 和嵌入式 Tomcat。
该应用程序应 运行 在 Amazon aws 上,对 WWW 开放,并用作 webhook,用于通过 https 从 Messenger 接收回调。
我需要有关如何保护应用程序的建议,这样它就不会被黑客攻击或被并非来自 Facebook 的请求淹没。
我想使应用程序需要安全 (ssl) 连接,但在 application.properties 中使用 "security.require_ssl=true" 没有成功。也许我不知道这是什么意思以及如何正确配置它。
是否有最佳实践如何阻止不是 https 请求的请求?或者在应用程序级别阻止来自 Messenger 外部的请求的方法?
非常感谢!
编辑
同时,我在应用层使用handler拦截器拦截了来自其他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;
}
}
}
有很多话要说,所以我确定我会漏掉一些要点。
设置 SSL 是第一件好事,但请确保您获得证书。如果您不想为 SSL 证书付费,lets encrypt 是一件好事。
只是 seeing aws 提供了 letsencrypt
的替代方案
Security Group 您可以将安全组视为类似于防火墙的东西,因此您可以控制打开哪个端口,外部和内部流量。
查看 IAM 控制谁以及如何访问您的 AWS 账户
显而易见:更改您的密码。不要让您可以在实例上设置的默认安装密码
阅读一些 https://aws.amazon.com/security/security-resources/ 以获取有关您可以做什么的更多信息
it won't be hacked or flooded with requests
抱歉这么说,但很可能是 - 它不需要是高级黑客就可以 运行 扫描器和扫描 IP 并检查打开的端口/暴力登录等...
您应该检查 Facebook 发送到您的网络钩子的请求中可用的 X-Hub-signature HTTP header URL。
在您的情况下,您可以定义一个过滤器或拦截器来验证签名。您也可以在您的控制器中执行此操作,就像我在 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);
}
感谢 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;
}
}
这是异常处理class:
@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;
}
我使用 Facebook Messenger platform 开发了一个聊天机器人应用程序。 我在 Web 平台上使用了 Spring Boot 和嵌入式 Tomcat。 该应用程序应 运行 在 Amazon aws 上,对 WWW 开放,并用作 webhook,用于通过 https 从 Messenger 接收回调。
我需要有关如何保护应用程序的建议,这样它就不会被黑客攻击或被并非来自 Facebook 的请求淹没。
我想使应用程序需要安全 (ssl) 连接,但在 application.properties 中使用 "security.require_ssl=true" 没有成功。也许我不知道这是什么意思以及如何正确配置它。 是否有最佳实践如何阻止不是 https 请求的请求?或者在应用程序级别阻止来自 Messenger 外部的请求的方法?
非常感谢!
编辑
同时,我在应用层使用handler拦截器拦截了来自其他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;
}
}
}
有很多话要说,所以我确定我会漏掉一些要点。
设置 SSL 是第一件好事,但请确保您获得证书。如果您不想为 SSL 证书付费,lets encrypt 是一件好事。
只是 seeing aws 提供了 letsencrypt
的替代方案Security Group 您可以将安全组视为类似于防火墙的东西,因此您可以控制打开哪个端口,外部和内部流量。
查看 IAM 控制谁以及如何访问您的 AWS 账户
显而易见:更改您的密码。不要让您可以在实例上设置的默认安装密码
阅读一些 https://aws.amazon.com/security/security-resources/ 以获取有关您可以做什么的更多信息
it won't be hacked or flooded with requests
抱歉这么说,但很可能是 - 它不需要是高级黑客就可以 运行 扫描器和扫描 IP 并检查打开的端口/暴力登录等...
您应该检查 Facebook 发送到您的网络钩子的请求中可用的 X-Hub-signature HTTP header URL。
在您的情况下,您可以定义一个过滤器或拦截器来验证签名。您也可以在您的控制器中执行此操作,就像我在 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);
}
感谢 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;
}
}
这是异常处理class:
@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;
}